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. 32
      jode/jode/expr/ArrayStoreOperator.java
  3. 228
      jode/jode/expr/FieldOperator.java.in
  4. 159
      jode/jode/expr/GetFieldOperator.java
  5. 120
      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;
public class ArrayLoadOperator extends Operator {
String value;
public ArrayLoadOperator(Type type) {
super(type, 0);

@ -22,40 +22,14 @@ import jode.type.Type;
import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter;
public class ArrayStoreOperator extends LValueExpression {
public class ArrayStoreOperator extends ArrayLoadOperator
implements LValueExpression {
public ArrayStoreOperator(Type type) {
super(type);
initOperands(2);
super(type);
}
public boolean matches(Operator loadop) {
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.Scope;
public class GetFieldOperator extends Operator {
boolean staticFlag;
MethodAnalyzer methodAnalyzer;
Reference ref;
Type classType;
public class GetFieldOperator extends FieldOperator {
public GetFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag,
Reference ref) {
super(Type.tType(ref.getType()), 0);
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);
}
super(methodAnalyzer, staticFlag, ref);
}
public Expression simplify() {

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

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

@ -25,18 +25,14 @@ import jode.decompiler.ClassAnalyzer;
import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter;
public class LocalLoadOperator extends Operator
implements LocalVarOperator {
public class LocalLoadOperator extends LocalVarOperator {
MethodAnalyzer methodAnalyzer;
LocalInfo local;
public LocalLoadOperator(Type type, MethodAnalyzer methodAnalyzer,
LocalInfo local) {
super(type);
super(type, local);
this.methodAnalyzer = methodAnalyzer;
this.local = local;
local.setOperator(this);
initOperands(0);
}
public boolean isRead() {
@ -51,38 +47,10 @@ public class LocalLoadOperator extends Operator
return false;
}
public int getPriority() {
return 1000;
}
public LocalInfo getLocalInfo() {
return local.getLocalInfo();
}
public void setMethodAnalyzer(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) {
return (o instanceof LocalLoadOperator &&
((LocalLoadOperator) o).local.getSlot() == local.getSlot());
@ -93,9 +61,4 @@ public class LocalLoadOperator extends Operator
return local.getExpression().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.TabbedPrintWriter;
public class LocalStoreOperator extends LValueExpression
implements LocalVarOperator {
LocalInfo local;
public class LocalStoreOperator extends LocalVarOperator
implements LValueExpression {
public LocalStoreOperator(Type lvalueType, LocalInfo local) {
super(lvalueType);
this.local = local;
local.setOperator(this);
initOperands(0);
super(lvalueType, local);
}
public boolean isRead() {
@ -43,33 +39,10 @@ public class LocalStoreOperator extends LValueExpression
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) {
return loadop instanceof LocalLoadOperator &&
((LocalLoadOperator)loadop).getLocalInfo().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
* it under the terms of the GNU General Public License as published by
@ -18,16 +18,49 @@
*/
package jode.expr;
import jode.GlobalOptions;
import jode.type.Type;
import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter;
public interface LocalVarOperator {
public boolean isRead();
public boolean isWrite();
public LocalInfo getLocalInfo();
/**
* This is called by the local info when the type
* of it changed
*/
public void updateType();
public abstract class LocalVarOperator extends Operator {
LocalInfo local;
public LocalVarOperator(Type lvalueType, LocalInfo local) {
super(lvalueType);
this.local = local;
local.setOperator(this);
initOperands(0);
}
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 \
ConvertOperator.java \
Expression.java \
FieldOperator.java \
GetFieldOperator.java \
IIncOperator.java \
IfThenElseOperator.java \

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

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

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

@ -30,72 +30,12 @@ import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope;
public class PutFieldOperator extends LValueExpression {
MethodAnalyzer methodAnalyzer;
boolean staticFlag;
Reference ref;
Type classType;
public class PutFieldOperator extends FieldOperator
implements LValueExpression {
public PutFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag,
Reference ref) {
super(Type.tType(ref.getType()));
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());
super(methodAnalyzer, staticFlag, ref);
}
public boolean matches(Operator loadop) {
@ -103,101 +43,6 @@ public class PutFieldOperator extends LValueExpression {
&& ((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) {
return o instanceof PutFieldOperator
&& ((PutFieldOperator)o).ref.equals(ref);

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

Loading…
Cancel
Save