ConstructorOperator removed, InvokeOperator handles it all.

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1082 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 26 years ago
parent 1a153a2529
commit e4337a16a7
  1. 333
      jode/jode/expr/ConstructorOperator.java
  2. 264
      jode/jode/expr/InvokeOperator.java
  3. 45
      jode/jode/flow/CreateNewConstructor.java

@ -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();
}
}
}

@ -36,10 +36,12 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable; import java.util.Hashtable;
///#ifdef JDK12 ///#ifdef JDK12
///import java.util.Collections; ///import java.util.Collections;
///import java.util.Collection;
///import java.util.Map; ///import java.util.Map;
///import java.util.Iterator; ///import java.util.Iterator;
///#else ///#else
import jode.util.Collections; import jode.util.Collections;
import jode.util.Collection;
import jode.util.Map; import jode.util.Map;
import jode.util.Iterator; import jode.util.Iterator;
///#endif ///#endif
@ -145,6 +147,7 @@ public final class InvokeOperator extends Operator
methodAnalyzer.useType(classType); methodAnalyzer.useType(classType);
initOperands((staticFlag ? 0 : 1) initOperands((staticFlag ? 0 : 1)
+ methodType.getParameterTypes().length); + methodType.getParameterTypes().length);
checkAnonymousClasses();
} }
public final boolean isStatic() { public final boolean isStatic() {
@ -167,6 +170,19 @@ public final class InvokeOperator extends Operator
return 950; return 950;
} }
public void checkAnonymousClasses() {
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0)
return;
if (!isConstructor())
return;
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
if (outer != null && (outer.outer == null || outer.name == null)) {
methodAnalyzer.addAnonymousConstructor(this);
System.err.println("addAnonymousConstructor: "+this);
}
}
public void updateSubTypes() { public void updateSubTypes() {
int offset = 0; int offset = 0;
if (!isStatic()) { if (!isStatic()) {
@ -183,6 +199,24 @@ public final class InvokeOperator extends Operator
public void updateType() { public void updateType() {
} }
/**
* Makes a non void expression out of this store instruction.
*/
public void makeNonVoid() {
if (type != Type.tVoid)
throw new jode.AssertError("already non void");
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
if (outer != null && outer.name == null) {
/* This is an anonymous class */
if (clazz.getInterfaces().length > 0)
type = Type.tClass(clazz.getInterfaces()[0]);
else
type = Type.tClass(clazz.getSuperclass());
} else
type = subExpressions[0].getType();
}
public boolean isConstructor() { public boolean isConstructor() {
return methodName.equals("<init>"); return methodName.equals("<init>");
} }
@ -274,12 +308,29 @@ public final class InvokeOperator extends Operator
return false; return false;
} }
public boolean isConstant() {
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0)
return super.isConstant();
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
if (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();
}
/** /**
* Checks if the value of the operator can be changed by this expression. * Checks if the value of the operator can be changed by this expression.
*/ */
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
return (loadop instanceof InvokeOperator return (loadop instanceof InvokeOperator
|| loadop instanceof ConstructorOperator
|| loadop instanceof GetFieldOperator); || loadop instanceof GetFieldOperator);
} }
@ -352,40 +403,51 @@ public final class InvokeOperator extends Operator
} }
public Expression simplifyStringBuffer() { public Expression simplifyStringBuffer() {
if (getClassType().equals(Type.tStringBuffer) if (getClassType().equals(Type.tStringBuffer)) {
&& !isStatic() if (isConstructor()
&& getMethodName().equals("append") && subExpressions[0] instanceof NewOperator) {
&& getMethodType().getParameterTypes().length == 1) { if (methodType.getParameterTypes().length == 0)
return EMPTYSTRING;
Expression firstOp = subExpressions[0].simplifyStringBuffer(); if (methodType.getParameterTypes().length == 1
if (firstOp == null) && methodType.getParameterTypes()[0].equals(Type.tString))
return null; return subExpressions[1].simplifyString();
subExpressions[1] = subExpressions[1].simplifyString();
if (firstOp == EMPTYSTRING
&& subExpressions[1].getType().isOfType(Type.tString))
return subExpressions[1];
if (firstOp instanceof StringAddOperator
&& ((Operator)firstOp).getSubExpressions()[0] == EMPTYSTRING)
firstOp = ((Operator)firstOp).getSubExpressions()[1];
Expression secondOp = subExpressions[1];
Type[] paramTypes = new Type[] {
Type.tStringBuffer, secondOp.getType().getCanonic()
};
if (needsCast(1, paramTypes)) {
Type castType = methodType.getParameterTypes()[0];
Operator castOp = new ConvertOperator(castType, castType);
castOp.addOperand(secondOp);
secondOp = castOp;
} }
Operator result = new StringAddOperator();
result.addOperand(secondOp); if (!isStatic()
result.addOperand(firstOp); && getMethodName().equals("append")
return result; && getMethodType().getParameterTypes().length == 1) {
}
Expression firstOp = subExpressions[0].simplifyStringBuffer();
if (firstOp == null)
return null;
subExpressions[1] = subExpressions[1].simplifyString();
if (firstOp == EMPTYSTRING
&& subExpressions[1].getType().isOfType(Type.tString))
return subExpressions[1];
if (firstOp instanceof StringAddOperator
&& (((Operator)firstOp).getSubExpressions()[0]
== EMPTYSTRING))
firstOp = ((Operator)firstOp).getSubExpressions()[1];
Expression secondOp = subExpressions[1];
Type[] paramTypes = new Type[] {
Type.tStringBuffer, secondOp.getType().getCanonic()
};
if (needsCast(1, paramTypes)) {
Type castType = methodType.getParameterTypes()[0];
Operator castOp = new ConvertOperator(castType, castType);
castOp.addOperand(secondOp);
secondOp = castOp;
}
Operator result = new StringAddOperator();
result.addOperand(secondOp);
result.addOperand(firstOp);
return result;
}
}
return null; return null;
} }
@ -560,18 +622,88 @@ public final class InvokeOperator extends Operator
} }
/**
* We add the named method scoped classes to the declarables, and
* 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;
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 */
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);
}
/* Invokes never equals: they may return different values even if /* Invokes never equals: they may return different values even if
* they have the same parameters. * they have the same parameters.
*/ */
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException { throws java.io.IOException {
boolean opIsThis = !staticFlag boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator; && subExpressions[0] instanceof ThisOperator;
int arg = 1; int arg = 1;
int length = subExpressions.length; int length = subExpressions.length;
/* true, if this is the constructor of an anonymous class and we
* must therefore dump the class.
*/
boolean dumpBlock = false;
ClassInfo clazz = getClassInfo(); ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz); ClassAnalyzer clazzAna = null;
Type[] paramTypes = new Type[subExpressions.length]; Type[] paramTypes = new Type[subExpressions.length];
for (int i=0; i< subExpressions.length; i++) for (int i=0; i< subExpressions.length; i++)
@ -579,24 +711,56 @@ public final class InvokeOperator extends Operator
if (isConstructor()) { if (isConstructor()) {
boolean jikesAnonymousInner = false; boolean jikesAnonymousInner = false;
InnerClassInfo outer = getOuterClassInfo(clazz);
clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
if ((Decompiler.options & if ((Decompiler.options &
(Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) != 0 (Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) != 0
&& clazzAna != null
&& outer != null && outer != null
&& (outer.outer == null || outer.name == null)) { && (outer.outer == null || outer.name == null)) {
ClassAnalyzer anonymousClass = methodAnalyzer.getClassAnalyzer(clazz);
jikesAnonymousInner = anonymousClass.isJikesAnonymousInner(); arg += clazzAna.getOuterValues().length;
jikesAnonymousInner = clazzAna.isJikesAnonymousInner();
if (outer.name == null) { if (outer.name == null) {
writer.print("SUPER IS ANONYMOUS?"); /* This is an anonymous class */
outer = null; 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");
}
} }
/* XXX check outerValues */
arg += anonymousClass.getOuterValues().length;
} }
if (outer != null && outer.outer != null && outer.name != null if (outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers) && !Modifier.isStatic(outer.modifiers)
&& (Decompiler.options & Decompiler.OPTION_INNER) != 0) { && (Decompiler.options &
(Decompiler.OPTION_INNER
| Decompiler.OPTION_CONTRAFO)) != 0) {
Expression outerExpr = jikesAnonymousInner Expression outerExpr = jikesAnonymousInner
? subExpressions[--length] ? subExpressions[--length]
: subExpressions[arg++]; : subExpressions[arg++];
@ -632,6 +796,7 @@ public final class InvokeOperator extends Operator
} }
} }
} }
if (specialFlag) { if (specialFlag) {
if (opIsThis if (opIsThis
&& (((ThisOperator)subExpressions[0]).getClassInfo() && (((ThisOperator)subExpressions[0]).getClassInfo()
@ -647,6 +812,12 @@ public final class InvokeOperator extends Operator
? Type.tObject : Type.tClass(superClazz); ? Type.tObject : Type.tClass(superClazz);
opIsThis = false; opIsThis = false;
} }
} else if (isConstructor()
&& subExpressions[0] instanceof NewOperator) {
writer.print("new ");
writer.printType(Type.tClass(clazz));
} else { } else {
/* XXX check if this is a private or final method. */ /* XXX check if this is a private or final method. */
int minPriority = 950; /* field access */ int minPriority = 950; /* field access */
@ -737,5 +908,12 @@ public final class InvokeOperator extends Operator
subExpressions[arg++].dumpExpression(writer, priority); subExpressions[arg++].dumpExpression(writer, priority);
} }
writer.print(")"); writer.print(")");
if (dumpBlock) {
writer.openBrace();
writer.tab();
clazzAna.dumpBlock(writer);
writer.untab();
writer.closeBraceNoSpace();
}
} }
} }

@ -38,7 +38,7 @@ public class CreateNewConstructor {
* SWAP * SWAP
* PUSH POP.append(POP) * PUSH POP.append(POP)
* *
* We transform it to javac String +=: * We transform it to the javac String +=:
* *
* PUSH new StringBuffer(String.valueOf(POP)) * PUSH new StringBuffer(String.valueOf(POP))
*/ */
@ -68,14 +68,15 @@ public class CreateNewConstructor {
InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0]; InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0];
sequBlock = (SequentialBlock) sequBlock.outer; sequBlock = (SequentialBlock) sequBlock.outer;
if (!(ib.getInstruction() instanceof ConstructorOperator) if (!(ib.getInstruction() instanceof InvokeOperator)
|| !(sequBlock.subBlocks[0] instanceof InstructionBlock)) || !(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false; return false;
ConstructorOperator constr = (ConstructorOperator) ib.getInstruction(); InvokeOperator constr = (InvokeOperator) ib.getInstruction();
ib = (InstructionBlock) sequBlock.subBlocks[0]; ib = (InstructionBlock) sequBlock.subBlocks[0];
if (constr.getClassType() != Type.tStringBuffer if (!constr.isConstructor()
|| !constr.getClassType().equals(Type.tStringBuffer)
|| constr.isVoid() || constr.isVoid()
|| constr.getMethodType().getParameterTypes().length != 0) || constr.getMethodType().getParameterTypes().length != 0)
return false; return false;
@ -92,10 +93,14 @@ public class CreateNewConstructor {
+ ")Ljava/lang/String;")); + ")Ljava/lang/String;"));
expr = valueOf.addOperand(expr); expr = valueOf.addOperand(expr);
} }
ConstructorOperator newConstr = new ConstructorOperator InvokeOperator newConstr = new InvokeOperator
(Reference.getReference("Ljava/lang/StringBuffer;", "<init>", (methodAna, false, true,
"(Ljava/lang/String;)V"), methodAna, false); Reference.getReference("Ljava/lang/StringBuffer;", "<init>",
ic.setInstruction(newConstr.addOperand(expr)); "(Ljava/lang/String;)V"));
newConstr.makeNonVoid();
newConstr.setSubExpressions(0, constr.getSubExpressions()[0]);
newConstr.setSubExpressions(1, expr);
ic.setInstruction(newConstr);
last.replace(sequBlock); last.replace(sequBlock);
return true; return true;
} }
@ -111,6 +116,7 @@ public class CreateNewConstructor {
* *
* transform it to * transform it to
* *
* (void resolved expressions)
* (optional PUSH) new <object>((optional: stack_n), * (optional PUSH) new <object>((optional: stack_n),
* resolved expressions) * resolved expressions)
* *
@ -125,6 +131,7 @@ public class CreateNewConstructor {
* *
* transform it to * transform it to
* *
* (void resolved expressions)
* PUSH load_ops * PUSH load_ops
* DUP <= remove the depth * DUP <= remove the depth
* (optional PUSH) new <object>(stack_n, resolved expressions) * (optional PUSH) new <object>(stack_n, resolved expressions)
@ -135,7 +142,7 @@ public class CreateNewConstructor {
if (!(ic.getInstruction() instanceof InvokeOperator)) if (!(ic.getInstruction() instanceof InvokeOperator))
return false; return false;
InvokeOperator constrCall = (InvokeOperator) ic.getInstruction(); InvokeOperator constrCall = (InvokeOperator) ic.getInstruction();
if (!constrCall.isConstructor()) if (!constrCall.isConstructor() || !constrCall.isVoid())
return false; return false;
/* The rest should probably succeed */ /* The rest should probably succeed */
@ -218,15 +225,17 @@ public class CreateNewConstructor {
if (optDupX2 != null) if (optDupX2 != null)
optDupX2.depth = 0; optDupX2.depth = 0;
Expression newExpr = new ConstructorOperator constrCall.setSubExpressions(0, op);
(constrCall, dup == null); if (dup != null)
constrCall.makeNonVoid();
if (subs != null) { // Expression newExpr = new ConstructorOperator
for (int i=subs.length; i-- > 1; ) // (constrCall, dup == null);
newExpr = newExpr.addOperand(subs[i]);
} // if (subs != null) {
ic.setInstruction(newExpr); // for (int i=subs.length; i-- > 1; )
// newExpr = newExpr.addOperand(subs[i]);
// }
// ic.setInstruction(newExpr);
return true; return true;
} }
} }

Loading…
Cancel
Save