git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1082 379699f6-c40d-0410-875b-85095c16579ebranch_1_1
parent
1a153a2529
commit
e4337a16a7
@ -1,333 +0,0 @@ |
|||||||
/* ConstructorOperator 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.type.MethodType; |
|
||||||
import jode.bytecode.ClassInfo; |
|
||||||
import jode.bytecode.InnerClassInfo; |
|
||||||
import jode.bytecode.Reference; |
|
||||||
import jode.Decompiler; |
|
||||||
import jode.decompiler.MethodAnalyzer; |
|
||||||
import jode.decompiler.ClassAnalyzer; |
|
||||||
import jode.decompiler.TabbedPrintWriter; |
|
||||||
import jode.decompiler.Scope; |
|
||||||
|
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
///#ifdef JDK12
|
|
||||||
///import java.util.Collection;
|
|
||||||
///#else
|
|
||||||
import jode.util.Collection; |
|
||||||
///#endif
|
|
||||||
|
|
||||||
public class ConstructorOperator extends Operator |
|
||||||
implements MatchableOperator { |
|
||||||
MethodType methodType; |
|
||||||
Type classType; |
|
||||||
MethodAnalyzer methodAnalyzer; |
|
||||||
|
|
||||||
public ConstructorOperator(Type classType, MethodType methodType, |
|
||||||
MethodAnalyzer methodAna, boolean isVoid) { |
|
||||||
super(isVoid ? Type.tVoid : classType, 0); |
|
||||||
this.classType = classType; |
|
||||||
this.methodType = methodType; |
|
||||||
this.methodAnalyzer = methodAna; |
|
||||||
initOperands(methodType.getParameterTypes().length); |
|
||||||
checkAnonymousClasses(); |
|
||||||
} |
|
||||||
|
|
||||||
public ConstructorOperator(Reference ref, MethodAnalyzer methodAna, |
|
||||||
boolean isVoid) { |
|
||||||
this (Type.tType(ref.getClazz()), Type.tMethod(ref.getType()), |
|
||||||
methodAna, isVoid); |
|
||||||
} |
|
||||||
|
|
||||||
public ConstructorOperator(InvokeOperator invoke, boolean isVoid) { |
|
||||||
this (invoke.getClassType(), invoke.getMethodType(), |
|
||||||
invoke.methodAnalyzer, isVoid); |
|
||||||
} |
|
||||||
|
|
||||||
public MethodType getMethodType() { |
|
||||||
return methodType; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Checks if the value of the operator can be changed by this expression. |
|
||||||
*/ |
|
||||||
public boolean matches(Operator loadop) { |
|
||||||
return (loadop instanceof InvokeOperator |
|
||||||
|| loadop instanceof ConstructorOperator |
|
||||||
|| loadop instanceof GetFieldOperator); |
|
||||||
} |
|
||||||
|
|
||||||
public int getPriority() { |
|
||||||
return 950; |
|
||||||
} |
|
||||||
|
|
||||||
public Type getClassType() { |
|
||||||
return classType; |
|
||||||
} |
|
||||||
|
|
||||||
public void updateSubTypes() { |
|
||||||
Type[] paramTypes = methodType.getParameterTypes(); |
|
||||||
for (int i=0; i < paramTypes.length; i++) |
|
||||||
subExpressions[i].setType(Type.tSubType(paramTypes[i])); |
|
||||||
} |
|
||||||
|
|
||||||
public void updateType() { |
|
||||||
} |
|
||||||
|
|
||||||
public Expression simplifyStringBuffer() { |
|
||||||
if (getClassType() == Type.tStringBuffer) { |
|
||||||
if (methodType.getParameterTypes().length == 0) |
|
||||||
return EMPTYSTRING; |
|
||||||
if (methodType.getParameterTypes().length == 1 |
|
||||||
&& methodType.getParameterTypes()[0].equals(Type.tString)) |
|
||||||
return subExpressions[0].simplifyString(); |
|
||||||
} |
|
||||||
return (getClassType() == Type.tStringBuffer) |
|
||||||
? EMPTYSTRING : null; |
|
||||||
} |
|
||||||
|
|
||||||
public Expression simplify() { |
|
||||||
return super.simplify(); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInfo getClassInfo() { |
|
||||||
if (classType instanceof ClassInterfacesType) { |
|
||||||
return ((ClassInterfacesType) classType).getClassInfo(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public InnerClassInfo getOuterClassInfo(ClassInfo ci) { |
|
||||||
if (ci != null) { |
|
||||||
InnerClassInfo[] outers = ci.getOuterClasses(); |
|
||||||
if (outers != null) |
|
||||||
return outers[0]; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public void checkAnonymousClasses() { |
|
||||||
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0) |
|
||||||
return; |
|
||||||
ClassInfo clazz = getClassInfo(); |
|
||||||
InnerClassInfo outer = getOuterClassInfo(clazz); |
|
||||||
if (outer != null && (outer.outer == null || outer.name == null)) { |
|
||||||
methodAnalyzer.addAnonymousConstructor(this); |
|
||||||
|
|
||||||
if (outer.name == null) { |
|
||||||
if (clazz.getInterfaces().length > 0) |
|
||||||
type = Type.tClass(clazz.getInterfaces()[0]); |
|
||||||
else |
|
||||||
type = Type.tClass(clazz.getSuperclass()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isConstant() { |
|
||||||
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 |
|
||||||
&& clazzAna.getParent() == methodAnalyzer) { |
|
||||||
/* This is a named method scope class, it needs |
|
||||||
* declaration. And therefore can't be moved into |
|
||||||
* a field initializer. */ |
|
||||||
return false; |
|
||||||
} |
|
||||||
return super.isConstant(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* We add the named method scoped classes to the declarables, and |
|
||||||
* only fillDeclarables on the parameters we will print. |
|
||||||
*/ |
|
||||||
public void fillDeclarables(Collection used) { |
|
||||||
ClassInfo clazz = getClassInfo(); |
|
||||||
InnerClassInfo outer = getOuterClassInfo(clazz); |
|
||||||
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); |
|
||||||
int arg = 0; |
|
||||||
int length = subExpressions.length; |
|
||||||
boolean jikesAnonymousInner = false; |
|
||||||
|
|
||||||
if ((Decompiler.options & Decompiler.OPTION_ANON) != 0 |
|
||||||
&& clazzAna != null |
|
||||||
&& outer != null && (outer.outer == null || outer.name == null)) { |
|
||||||
arg += clazzAna.getOuterValues().length; |
|
||||||
for (int i=0; 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 */ |
|
||||||
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 ((Decompiler.options & Decompiler.OPTION_INNER) != 0 |
|
||||||
&& outer != null && outer.outer != null && outer.name != null |
|
||||||
&& !Modifier.isStatic(outer.modifiers)) { |
|
||||||
|
|
||||||
Expression outerExpr = jikesAnonymousInner |
|
||||||
? subExpressions[--length] |
|
||||||
: subExpressions[arg++]; |
|
||||||
if (outerExpr instanceof CheckNullOperator) { |
|
||||||
CheckNullOperator cno = (CheckNullOperator) outerExpr; |
|
||||||
outerExpr = cno.subExpressions[0]; |
|
||||||
} |
|
||||||
outerExpr.fillDeclarables(used); |
|
||||||
} |
|
||||||
for (int i=arg; i < length; i++) |
|
||||||
subExpressions[i].fillDeclarables(used); |
|
||||||
} |
|
||||||
|
|
||||||
public void dumpExpression(TabbedPrintWriter writer) |
|
||||||
throws java.io.IOException { |
|
||||||
|
|
||||||
int arg = 0; |
|
||||||
int length = subExpressions.length; |
|
||||||
boolean jikesAnonymousInner = false; |
|
||||||
ClassInfo clazz = getClassInfo(); |
|
||||||
InnerClassInfo outer = getOuterClassInfo(clazz); |
|
||||||
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz); |
|
||||||
|
|
||||||
boolean dumpBlock = false; |
|
||||||
if ((Decompiler.options & |
|
||||||
(Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) != 0 |
|
||||||
&& clazzAna != null |
|
||||||
&& outer != null && (outer.outer == null || outer.name == null)) { |
|
||||||
arg += clazzAna.getOuterValues().length; |
|
||||||
jikesAnonymousInner = clazzAna.isJikesAnonymousInner(); |
|
||||||
|
|
||||||
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 { |
|
||||||
if (interfaces.length > 0) { |
|
||||||
writer.print("too many supers in ANONYMOUS "); |
|
||||||
} |
|
||||||
clazz = (superClazz != null |
|
||||||
? superClazz : ClassInfo.javaLangObject); |
|
||||||
} |
|
||||||
outer = getOuterClassInfo(clazz); |
|
||||||
dumpBlock = true; |
|
||||||
if (jikesAnonymousInner |
|
||||||
&& outer.outer == null && outer.name != null) { |
|
||||||
Expression thisExpr = subExpressions[--length]; |
|
||||||
if (thisExpr instanceof CheckNullOperator) { |
|
||||||
CheckNullOperator cno = (CheckNullOperator) thisExpr; |
|
||||||
thisExpr = cno.subExpressions[0]; |
|
||||||
} |
|
||||||
if (!(thisExpr instanceof ThisOperator) |
|
||||||
|| (((ThisOperator) thisExpr).getClassInfo() |
|
||||||
!= methodAnalyzer.getClazz())) |
|
||||||
writer.print("ILLEGAL ANON CONSTR"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (outer != null && outer.outer != null && outer.name != null |
|
||||||
&& !Modifier.isStatic(outer.modifiers) |
|
||||||
&& (Decompiler.options & |
|
||||||
(Decompiler.OPTION_INNER | Decompiler.OPTION_CONTRAFO)) != 0) { |
|
||||||
|
|
||||||
Expression outerExpr = jikesAnonymousInner |
|
||||||
? subExpressions[--length] |
|
||||||
: subExpressions[arg++]; |
|
||||||
if (outerExpr instanceof CheckNullOperator) { |
|
||||||
CheckNullOperator cno = (CheckNullOperator) outerExpr; |
|
||||||
outerExpr = cno.subExpressions[0]; |
|
||||||
} else if (!(outerExpr instanceof ThisOperator)) { |
|
||||||
// Bug in jikes: it doesn't do a check null.
|
|
||||||
// We don't complain here.
|
|
||||||
if (!jikesAnonymousInner) |
|
||||||
writer.print("MISSING CHECKNULL "); |
|
||||||
} |
|
||||||
|
|
||||||
if (outerExpr instanceof ThisOperator) { |
|
||||||
Scope scope = writer.getScope |
|
||||||
(((ThisOperator) outerExpr).getClassInfo(), |
|
||||||
Scope.CLASSSCOPE); |
|
||||||
if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) { |
|
||||||
outerExpr.dumpExpression(writer, 950); |
|
||||||
writer.print("."); |
|
||||||
} |
|
||||||
} else { |
|
||||||
if (outerExpr.getType() instanceof NullType) { |
|
||||||
writer.print("(("); |
|
||||||
writer.printType(Type.tClass |
|
||||||
(ClassInfo.forName(outer.outer))); |
|
||||||
writer.print(") "); |
|
||||||
outerExpr.dumpExpression(writer, 700); |
|
||||||
writer.print(")"); |
|
||||||
} else |
|
||||||
outerExpr.dumpExpression(writer, 950); |
|
||||||
writer.print("."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
writer.print("new "); |
|
||||||
writer.printType(Type.tClass(clazz)); |
|
||||||
writer.print("("); |
|
||||||
for (int i = arg; i < length; i++) { |
|
||||||
if (i>arg) |
|
||||||
writer.print(", "); |
|
||||||
subExpressions[i].dumpExpression(writer, 0); |
|
||||||
} |
|
||||||
writer.print(")"); |
|
||||||
if (dumpBlock) { |
|
||||||
writer.openBrace(); |
|
||||||
writer.tab(); |
|
||||||
clazzAna.dumpBlock(writer); |
|
||||||
writer.untab(); |
|
||||||
writer.closeBraceNoSpace(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue