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