OuterValues added

inner/anonymous classes completely reworked
FieldOperator added to remove doubled code in Put/Get-FieldOperator
LocalVarOperator is now a class
LValueExpression is only an interface
ArrayStoreOperator extends ArrayLoadOperator


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1192 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent 62ca43d74f
commit 38a01116c1
  1. 1
      jode/jode/expr/ArrayLoadOperator.java
  2. 30
      jode/jode/expr/ArrayStoreOperator.java
  3. 228
      jode/jode/expr/FieldOperator.java.in
  4. 159
      jode/jode/expr/GetFieldOperator.java
  5. 56
      jode/jode/expr/InvokeOperator.java.in
  6. 7
      jode/jode/expr/LValueExpression.java
  7. 43
      jode/jode/expr/LocalLoadOperator.java
  8. 33
      jode/jode/expr/LocalStoreOperator.java
  9. 53
      jode/jode/expr/LocalVarOperator.java
  10. 1
      jode/jode/expr/Makefile.am
  11. 2
      jode/jode/expr/Operator.java.in
  12. 5
      jode/jode/expr/OuterLocalOperator.java
  13. 2
      jode/jode/expr/PrePostFixOperator.java
  14. 161
      jode/jode/expr/PutFieldOperator.java
  15. 2
      jode/jode/expr/StoreInstruction.java

@ -23,7 +23,6 @@ import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
public class ArrayLoadOperator extends Operator { public class ArrayLoadOperator extends Operator {
String value;
public ArrayLoadOperator(Type type) { public ArrayLoadOperator(Type type) {
super(type, 0); super(type, 0);

@ -22,40 +22,14 @@ import jode.type.Type;
import jode.type.ArrayType; import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
public class ArrayStoreOperator extends LValueExpression { public class ArrayStoreOperator extends ArrayLoadOperator
implements LValueExpression {
public ArrayStoreOperator(Type type) { public ArrayStoreOperator(Type type) {
super(type); super(type);
initOperands(2);
} }
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
return loadop instanceof ArrayLoadOperator; return loadop instanceof ArrayLoadOperator;
} }
public int getPriority() {
return 950;
}
public void updateSubTypes() {
subExpressions[0].setType(Type.tArray(type));
subExpressions[1].setType(Type.tSubType(Type.tInt));
}
public void updateType() {
Type subType = subExpressions[0].getType()
.intersection(Type.tArray(type));
if (!(subType instanceof ArrayType))
updateParentType(Type.tError);
else
updateParentType(((ArrayType)subType).getElementType());
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
subExpressions[0].dumpExpression(writer, 950);
writer.print("[");
subExpressions[1].dumpExpression(writer, 0);
writer.print("]");
}
} }

@ -0,0 +1,228 @@
/* FieldOperator Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.expr;
import jode.type.Type;
import jode.type.NullType;
import jode.type.ClassInterfacesType;
import jode.bytecode.FieldInfo;
import jode.bytecode.ClassInfo;
import jode.bytecode.Reference;
import jode.bytecode.InnerClassInfo;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.ClassAnalyzer;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope;
import jode.Decompiler;
import @COLLECTIONS@.Collection;
/**
* This class contains everything shared between PutFieldOperator and
* GetFieldOperator
*/
public abstract class FieldOperator extends Operator {
MethodAnalyzer methodAnalyzer;
boolean staticFlag;
Reference ref;
Type classType;
public FieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag,
Reference ref) {
super(Type.tType(ref.getType()));
this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag;
this.classType = Type.tType(ref.getClazz());
this.ref = ref;
if (staticFlag)
methodAnalyzer.useType(classType);
initOperands(staticFlag ? 0 : 1);
}
public int getPriority() {
return 950;
}
public void updateSubTypes() {
if (!staticFlag)
subExpressions[0].setType(Type.tSubType(classType));
}
public void updateType() {
updateParentType(getFieldType());
}
public boolean isStatic() {
return staticFlag;
}
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType)
return ((ClassInterfacesType) classType).getClassInfo();
return null;
}
public FieldAnalyzer getField() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz()) {
return ana.getField(ana.getFieldIndex
(ref.getName(),
Type.tType(ref.getType())));
}
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError("Unknown parent");
}
}
return null;
}
public String getFieldName() {
return ref.getName();
}
public Type getFieldType() {
return Type.tType(ref.getType());
}
public boolean needsCast(Type type) {
if (type instanceof NullType)
return true;
if (!(type instanceof ClassInterfacesType
&& classType instanceof ClassInterfacesType))
return false;
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassInfo parClazz = ((ClassInterfacesType) type).getClassInfo();
while (clazz != parClazz && clazz != null) {
FieldInfo[] fields = parClazz.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(ref.getName()))
return true;
}
parClazz = parClazz.getSuperclass();
}
return false;
}
public InnerClassInfo getOuterClassInfo(ClassInfo ci) {
if (ci != null) {
InnerClassInfo[] outers = ci.getOuterClasses();
if (outers != null)
return outers[0];
}
return null;
}
/**
* We add the named method scoped classes to the declarables.
*/
public void fillDeclarables(Collection used) {
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
if ((Decompiler.options & Decompiler.OPTION_ANON) != 0
&& clazzAna != null
&& outer != null && (outer.outer == null || outer.name == null)) {
if (outer.name != null) {
if (clazzAna.getParent() == methodAnalyzer) {
/* This is a named method scope class, declare it.
* But first declare all method scoped classes,
* that are used inside; order does matter.
*/
clazzAna.fillDeclarables(used);
used.add(clazzAna);
}
}
}
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator;
String fieldName = ref.getName();
if (staticFlag) {
if (!classType.equals(Type.tClass(methodAnalyzer.getClazz()))
|| methodAnalyzer.findLocal(fieldName) != null) {
writer.printType(classType);
writer.print(".");
}
writer.print(fieldName);
} else if (needsCast(subExpressions[0].getType().getCanonic())) {
writer.print("((");
writer.printType(classType);
writer.print(") ");
subExpressions[0].dumpExpression(writer, 700);
writer.print(").");
writer.print(fieldName);
} else {
if (opIsThis) {
ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE);
if (scope == null || writer.conflicts(fieldName, scope,
Scope.FIELDNAME)) {
thisOp.dumpExpression(writer, 950);
writer.print(".");
} else if (writer.conflicts(fieldName, scope,
Scope.AMBIGUOUSNAME)
|| (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getField() == null
&& writer.conflicts(fieldName, null,
Scope.NOSUPERFIELDNAME))) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope)
// For a simple outer class we can say this
writer.print("this.");
else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
writer.print(".");
}
}
} else {
subExpressions[0].dumpExpression(writer, 950);
writer.print(".");
}
writer.print(fieldName);
}
}
}

@ -31,165 +31,10 @@ import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope; import jode.decompiler.Scope;
public class GetFieldOperator extends Operator { public class GetFieldOperator extends FieldOperator {
boolean staticFlag;
MethodAnalyzer methodAnalyzer;
Reference ref;
Type classType;
public GetFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag, public GetFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag,
Reference ref) { Reference ref) {
super(Type.tType(ref.getType()), 0); super(methodAnalyzer, staticFlag, ref);
this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag;
this.classType = Type.tType(ref.getClazz());
this.ref = ref;
if (staticFlag)
methodAnalyzer.useType(classType);
initOperands(staticFlag ? 0 : 1);
}
public int getPriority() {
return 950;
}
public void updateSubTypes() {
if (!staticFlag)
subExpressions[0].setType(Type.tSubType(classType));
}
public void updateType() {
}
/**
* Checks, whether this is a call of a method from this class or an
* outer instance.
*/
public boolean isOuter() {
if (classType instanceof ClassInterfacesType) {
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz())
return true;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
return false;
}
}
return false;
}
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType)
return ((ClassInterfacesType) classType).getClassInfo();
return null;
}
public FieldAnalyzer getField() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz()) {
return ana.getField(ref.getName(),
Type.tType(ref.getType()));
}
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError("Unknown parent");
}
}
return null;
}
public boolean needsCast(Type type) {
if (type instanceof NullType)
return true;
if (!(type instanceof ClassInterfacesType
&& classType instanceof ClassInterfacesType))
return false;
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassInfo parClazz = ((ClassInterfacesType) type).getClassInfo();
while (clazz != parClazz && clazz != null) {
FieldInfo[] fields = parClazz.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(ref.getName()))
return true;
}
parClazz = parClazz.getSuperclass();
}
return false;
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator;
String fieldName = ref.getName();
if (staticFlag) {
if (!classType.equals(Type.tClass(methodAnalyzer.getClazz()))
|| methodAnalyzer.findLocal(fieldName) != null) {
writer.printType(classType);
writer.print(".");
}
writer.print(fieldName);
} else if (needsCast(subExpressions[0].getType().getCanonic())) {
writer.print("((");
writer.printType(classType);
writer.print(") ");
subExpressions[0].dumpExpression(writer, 700);
writer.print(").");
writer.print(fieldName);
} else {
if (opIsThis) {
ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE);
if (scope == null || writer.conflicts(fieldName, scope,
Scope.FIELDNAME)) {
thisOp.dumpExpression(writer, 950);
writer.print(".");
} else if (writer.conflicts(fieldName, scope,
Scope.AMBIGUOUSNAME)
|| (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getField() == null
&& writer.conflicts(fieldName, null,
Scope.NOSUPERFIELDNAME))) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope)
// For a simple outer class we can say this
writer.print("this.");
else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
writer.print(".");
}
}
} else {
subExpressions[0].dumpExpression(writer, 950);
writer.print(".");
}
writer.print(fieldName);
}
} }
public Expression simplify() { public Expression simplify() {

@ -25,6 +25,7 @@ import jode.decompiler.MethodAnalyzer;
import jode.decompiler.MethodAnalyzer; import jode.decompiler.MethodAnalyzer;
import jode.decompiler.ClassAnalyzer; import jode.decompiler.ClassAnalyzer;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.OuterValues;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.bytecode.*; import jode.bytecode.*;
import jode.jvm.*; import jode.jvm.*;
@ -173,12 +174,10 @@ public final class InvokeOperator extends Operator
} }
public void checkAnonymousClasses() { public void checkAnonymousClasses() {
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0) if (methodFlag != CONSTRUCTOR
return; || (Decompiler.options & Decompiler.OPTION_ANON) == 0)
if (methodFlag != CONSTRUCTOR)
return; return;
ClassInfo clazz = getClassInfo(); InnerClassInfo outer = getOuterClassInfo(getClassInfo());
InnerClassInfo outer = getOuterClassInfo(clazz);
if (outer != null && (outer.outer == null || outer.name == null)) { if (outer != null && (outer.outer == null || outer.name == null)) {
methodAnalyzer.addAnonymousConstructor(this); methodAnalyzer.addAnonymousConstructor(this);
} }
@ -277,10 +276,14 @@ public final class InvokeOperator extends Operator
callee = ClassInfo.forName(outers[nested - 1].outer); callee = ClassInfo.forName(outers[nested - 1].outer);
} }
/* First check if it is an inner class */
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer(callee);
if (ana == null) {
/* Now we iterate the caller analyzer queue to find the class /* Now we iterate the caller analyzer queue to find the class
* analyzer for callee * analyzer for callee
*/ */
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer(); ana = methodAnalyzer.getClassAnalyzer();
while (callee != ana.getClazz()) { while (callee != ana.getClazz()) {
if (ana.getParent() == null) if (ana.getParent() == null)
return null; return null;
@ -296,6 +299,7 @@ public final class InvokeOperator extends Operator
throw new jode.AssertError throw new jode.AssertError
("Unknown parent: "+ana+": "+ana.getParent()); ("Unknown parent: "+ana+": "+ana.getParent());
} }
}
/* Now get the ClassAnalyzer of the real callee */ /* Now get the ClassAnalyzer of the real callee */
while (nested > 0) { while (nested > 0) {
@ -692,14 +696,10 @@ public final class InvokeOperator extends Operator
* only fillDeclarables on the parameters we will print. * only fillDeclarables on the parameters we will print.
*/ */
public void fillDeclarables(Collection used) { public void fillDeclarables(Collection used) {
if (!isConstructor()) {
super.fillDeclarables(used);
return;
}
ClassInfo clazz = getClassInfo(); ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz); InnerClassInfo outer = getOuterClassInfo(clazz);
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
int arg = 1; int arg = 1;
int length = subExpressions.length; int length = subExpressions.length;
boolean jikesAnonymousInner = false; boolean jikesAnonymousInner = false;
@ -707,7 +707,22 @@ public final class InvokeOperator extends Operator
if ((Decompiler.options & Decompiler.OPTION_ANON) != 0 if ((Decompiler.options & Decompiler.OPTION_ANON) != 0
&& clazzAna != null && clazzAna != null
&& outer != null && (outer.outer == null || outer.name == null)) { && outer != null && (outer.outer == null || outer.name == null)) {
arg += clazzAna.getOuterValues().length;
if (outer.name != null) {
if (clazzAna.getParent() == methodAnalyzer) {
/* This is a named method scope class, declare it.
* But first declare all method scoped classes,
* that are used inside; order does matter.
*/
clazzAna.fillDeclarables(used);
used.add(clazzAna);
}
}
if (isConstructor()) {
OuterValues ov = clazzAna.getOuterValues();
arg += ov.getCount();
jikesAnonymousInner = ov.isJikesAnonymousInner();
for (int i=1; i< arg; i++) { for (int i=1; i< arg; i++) {
Expression expr = subExpressions[i]; Expression expr = subExpressions[i];
if (expr instanceof CheckNullOperator) { if (expr instanceof CheckNullOperator) {
@ -716,13 +731,8 @@ public final class InvokeOperator extends Operator
} }
expr.fillDeclarables(used); expr.fillDeclarables(used);
} }
jikesAnonymousInner = clazzAna.isJikesAnonymousInner();
if (outer.name != null) { if (outer.name == null) {
if (clazzAna.getParent() == methodAnalyzer)
/* This is a named method scope class, declare it */
used.add(clazzAna);
} else {
/* This is an anonymous class */ /* This is an anonymous class */
ClassInfo superClazz = clazz.getSuperclass(); ClassInfo superClazz = clazz.getSuperclass();
ClassInfo[] interfaces = clazz.getInterfaces(); ClassInfo[] interfaces = clazz.getInterfaces();
@ -735,9 +745,12 @@ public final class InvokeOperator extends Operator
? superClazz : ClassInfo.javaLangObject); ? superClazz : ClassInfo.javaLangObject);
} }
outer = getOuterClassInfo(clazz); outer = getOuterClassInfo(clazz);
} }
} }
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0 }
if (isConstructor()
&& (Decompiler.options & Decompiler.OPTION_INNER) != 0
&& outer != null && outer.outer != null && outer.name != null && outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers)) { && !Modifier.isStatic(outer.modifiers)) {
@ -792,8 +805,9 @@ public final class InvokeOperator extends Operator
&& (outer.outer == null || outer.name == null)) { && (outer.outer == null || outer.name == null)) {
/* This is a method scoped class, skip the outerValues */ /* This is a method scoped class, skip the outerValues */
arg += clazzAna.getOuterValues().length; OuterValues ov = clazzAna.getOuterValues();
jikesAnonymousInner = clazzAna.isJikesAnonymousInner(); arg += ov.getCount();
jikesAnonymousInner = ov.isJikesAnonymousInner();
if (outer.name == null) { if (outer.name == null) {
/* This is an anonymous class */ /* This is an anonymous class */

@ -22,10 +22,5 @@ import jode.type.Type;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
public abstract class LValueExpression extends Operator public interface LValueExpression extends MatchableOperator {
implements MatchableOperator {
public LValueExpression(Type lvalueType) {
super(lvalueType, 0);
}
} }

@ -25,18 +25,14 @@ import jode.decompiler.ClassAnalyzer;
import jode.decompiler.LocalInfo; import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
public class LocalLoadOperator extends Operator public class LocalLoadOperator extends LocalVarOperator {
implements LocalVarOperator {
MethodAnalyzer methodAnalyzer; MethodAnalyzer methodAnalyzer;
LocalInfo local;
public LocalLoadOperator(Type type, MethodAnalyzer methodAnalyzer, public LocalLoadOperator(Type type, MethodAnalyzer methodAnalyzer,
LocalInfo local) { LocalInfo local) {
super(type); super(type, local);
this.methodAnalyzer = methodAnalyzer; this.methodAnalyzer = methodAnalyzer;
this.local = local;
local.setOperator(this);
initOperands(0);
} }
public boolean isRead() { public boolean isRead() {
@ -51,38 +47,10 @@ public class LocalLoadOperator extends Operator
return false; return false;
} }
public int getPriority() {
return 1000;
}
public LocalInfo getLocalInfo() {
return local.getLocalInfo();
}
public void setMethodAnalyzer(MethodAnalyzer ma) { public void setMethodAnalyzer(MethodAnalyzer ma) {
methodAnalyzer = ma; methodAnalyzer = ma;
} }
public void setLocalInfo(LocalInfo newLocal) {
local = newLocal;
updateType();
}
public void updateSubTypes() {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("setType of "+local.getName()+": "
+local.getType());
local.setType(type);
}
public void updateType() {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("local "+local.getName()+" changed: "
+type+" to "+local.getType()
+" in "+parent);
updateParentType(local.getType());
}
public boolean opEquals(Operator o) { public boolean opEquals(Operator o) {
return (o instanceof LocalLoadOperator && return (o instanceof LocalLoadOperator &&
((LocalLoadOperator) o).local.getSlot() == local.getSlot()); ((LocalLoadOperator) o).local.getSlot() == local.getSlot());
@ -93,9 +61,4 @@ public class LocalLoadOperator extends Operator
return local.getExpression().simplify(); return local.getExpression().simplify();
return super.simplify(); return super.simplify();
} }
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print(local.getName());
}
} }

@ -23,15 +23,11 @@ import jode.type.Type;
import jode.decompiler.LocalInfo; import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
public class LocalStoreOperator extends LValueExpression public class LocalStoreOperator extends LocalVarOperator
implements LocalVarOperator { implements LValueExpression {
LocalInfo local;
public LocalStoreOperator(Type lvalueType, LocalInfo local) { public LocalStoreOperator(Type lvalueType, LocalInfo local) {
super(lvalueType); super(lvalueType, local);
this.local = local;
local.setOperator(this);
initOperands(0);
} }
public boolean isRead() { public boolean isRead() {
@ -43,33 +39,10 @@ public class LocalStoreOperator extends LValueExpression
return true; return true;
} }
public void updateSubTypes() {
if (parent != null
&& (GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("local type changed in: "+parent);
local.setType(type);
}
public void updateType() {
updateParentType(local.getType());
}
public LocalInfo getLocalInfo() {
return local.getLocalInfo();
}
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
return loadop instanceof LocalLoadOperator && return loadop instanceof LocalLoadOperator &&
((LocalLoadOperator)loadop).getLocalInfo().getSlot() ((LocalLoadOperator)loadop).getLocalInfo().getSlot()
== local.getSlot(); == local.getSlot();
} }
public int getPriority() {
return 1000;
}
public void dumpExpression(TabbedPrintWriter writer) {
writer.print(local.getName());
}
} }

@ -1,4 +1,4 @@
/* LocalVarOperator Copyright (C) 1998-1999 Jochen Hoenicke. /* LocalOperator Copyright (C) 1998-1999 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,16 +18,49 @@
*/ */
package jode.expr; package jode.expr;
import jode.GlobalOptions;
import jode.type.Type; import jode.type.Type;
import jode.decompiler.LocalInfo; import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter;
public interface LocalVarOperator { public abstract class LocalVarOperator extends Operator {
public boolean isRead(); LocalInfo local;
public boolean isWrite();
public LocalInfo getLocalInfo(); public LocalVarOperator(Type lvalueType, LocalInfo local) {
/** super(lvalueType);
* This is called by the local info when the type this.local = local;
* of it changed local.setOperator(this);
*/ initOperands(0);
public void updateType(); }
public abstract boolean isRead();
public abstract boolean isWrite();
public void updateSubTypes() {
if (parent != null
&& (GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("local type changed in: "+parent);
local.setType(type);
}
public void updateType() {
updateParentType(local.getType());
}
public LocalInfo getLocalInfo() {
return local.getLocalInfo();
}
public void setLocalInfo(LocalInfo newLocal) {
local = newLocal;
updateType();
}
public int getPriority() {
return 1000;
}
public void dumpExpression(TabbedPrintWriter writer) {
writer.print(local.getName());
}
} }

@ -26,6 +26,7 @@ MY_JAVA_FILES = \
ConstantArrayOperator.java \ ConstantArrayOperator.java \
ConvertOperator.java \ ConvertOperator.java \
Expression.java \ Expression.java \
FieldOperator.java \
GetFieldOperator.java \ GetFieldOperator.java \
IIncOperator.java \ IIncOperator.java \
IfThenElseOperator.java \ IfThenElseOperator.java \

@ -224,7 +224,7 @@ public abstract class Operator extends Expression {
public boolean containsMatchingLoad(CombineableOperator comb) { public boolean containsMatchingLoad(CombineableOperator comb) {
Operator combOp = (Operator) comb; Operator combOp = (Operator) comb;
if (comb.getLValue().matches(this)) { if (comb.getLValue().matches(this)) {
if (subsEquals(comb.getLValue())) if (subsEquals((Operator) comb.getLValue()))
return true; return true;
} }
for (int i=0; i < subExpressions.length; i++) { for (int i=0; i < subExpressions.length; i++) {

@ -56,6 +56,11 @@ public class OuterLocalOperator extends Operator {
public void updateType() { public void updateType() {
} }
public boolean opEquals(Operator o) {
return (o instanceof OuterLocalOperator &&
((OuterLocalOperator) o).local.getSlot() == local.getSlot());
}
public Expression simplify() { public Expression simplify() {
return super.simplify(); return super.simplify();
} }

@ -33,7 +33,7 @@ public class PrePostFixOperator extends Operator {
this.postfix = postfix; this.postfix = postfix;
setOperatorIndex(operatorIndex); setOperatorIndex(operatorIndex);
initOperands(1); initOperands(1);
setSubExpressions(0, lvalue); setSubExpressions(0, (Operator) lvalue);
} }
public int getPriority() { public int getPriority() {

@ -30,72 +30,12 @@ import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope; import jode.decompiler.Scope;
public class PutFieldOperator extends LValueExpression { public class PutFieldOperator extends FieldOperator
MethodAnalyzer methodAnalyzer; implements LValueExpression {
boolean staticFlag;
Reference ref;
Type classType;
public PutFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag, public PutFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag,
Reference ref) { Reference ref) {
super(Type.tType(ref.getType())); super(methodAnalyzer, staticFlag, ref);
this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag;
this.ref = ref;
this.classType = Type.tType(ref.getClazz());
if (staticFlag)
methodAnalyzer.useType(classType);
initOperands(staticFlag ? 0 : 1);
}
public boolean isStatic() {
return staticFlag;
}
/**
* Checks, whether this is a call of a method from this class.
* @XXX check, if this class implements the method and if not
* allow super class
*/
public boolean isThis() {
return (classType.equals(Type.tClass(methodAnalyzer.getClazz())));
}
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType)
return ((ClassInterfacesType) classType).getClassInfo();
return null;
}
public FieldAnalyzer getField() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz()) {
return ana.getField(ref.getName(),
Type.tType(ref.getType()));
}
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError("Unknown parent");
}
}
return null;
}
public String getFieldName() {
return ref.getName();
}
public Type getFieldType() {
return Type.tType(ref.getType());
} }
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
@ -103,101 +43,6 @@ public class PutFieldOperator extends LValueExpression {
&& ((GetFieldOperator)loadop).ref.equals(ref); && ((GetFieldOperator)loadop).ref.equals(ref);
} }
public int getPriority() {
return 950;
}
public void updateSubTypes() {
if (!staticFlag)
subExpressions[0].setType(Type.tSubType(classType));
}
public void updateType() {
updateParentType(getFieldType());
}
public boolean needsCast(Type type) {
if (type instanceof NullType)
return true;
if (!(type instanceof ClassInterfacesType
&& classType instanceof ClassInterfacesType))
return false;
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassInfo parClazz = ((ClassInterfacesType) type).getClassInfo();
while (clazz != parClazz && clazz != null) {
FieldInfo[] fields = parClazz.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(ref.getName()))
return true;
}
parClazz = parClazz.getSuperclass();
}
return false;
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator;
String fieldName = ref.getName();
if (staticFlag) {
if (!classType.equals(Type.tClass(methodAnalyzer.getClazz()))
|| methodAnalyzer.findLocal(fieldName) != null) {
writer.printType(classType);
writer.print(".");
}
writer.print(fieldName);
} else if (needsCast(subExpressions[0].getType().getCanonic())) {
writer.print("((");
writer.printType(classType);
writer.print(") ");
subExpressions[0].dumpExpression(writer, 700);
writer.print(").");
writer.print(fieldName);
} else {
if (opIsThis) {
ThisOperator thisOp = (ThisOperator) subExpressions[0];
ClassInfo clazz = thisOp.getClassInfo();
Scope scope = writer.getScope(clazz, Scope.CLASSSCOPE);
if (scope == null || writer.conflicts(fieldName, scope,
Scope.FIELDNAME)) {
thisOp.dumpExpression(writer, 950);
writer.print(".");
} else {
if (writer.conflicts(fieldName, scope,
Scope.AMBIGUOUSNAME)
|| (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getField() == null
&& writer.conflicts(fieldName, null,
Scope.NOSUPERFIELDNAME))) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope)
// For a simple outer class we can say this
writer.print("this.");
else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
writer.print(".");
}
}
}
} else {
subExpressions[0].dumpExpression(writer, 950);
writer.print(".");
}
writer.print(fieldName);
}
}
public boolean opEquals(Operator o) { public boolean opEquals(Operator o) {
return o instanceof PutFieldOperator return o instanceof PutFieldOperator
&& ((PutFieldOperator)o).ref.equals(ref); && ((PutFieldOperator)o).ref.equals(ref);

@ -30,7 +30,7 @@ public class StoreInstruction extends Operator
public StoreInstruction(LValueExpression lvalue) { public StoreInstruction(LValueExpression lvalue) {
super(Type.tVoid, ASSIGN_OP); super(Type.tVoid, ASSIGN_OP);
initOperands(2); initOperands(2);
setSubExpressions(0, lvalue); setSubExpressions(0, (Operator) lvalue);
} }
public LValueExpression getLValue() { public LValueExpression getLValue() {

Loading…
Cancel
Save