Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/jode/expr/ConstructorOperator.java

333 lines
10 KiB

/* 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.Set;
///#else
import jode.util.Set;
///#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(Set 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();
}
}
}