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-85095c16579ebranch_1_1
parent
62ca43d74f
commit
38a01116c1
@ -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); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue