better this. handling (NOSUPERMETHODNAME)

hint types reworked (classes inherit hints now)


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@940 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent d0c889ccfe
commit 4efd9c5761
  1. 174
      jode/jode/expr/InvokeOperator.java

@ -30,9 +30,19 @@ import jode.bytecode.*;
import jode.jvm.*; import jode.jvm.*;
import jode.type.*; import jode.type.*;
import jode.decompiler.Scope; import jode.decompiler.Scope;
import jode.util.SimpleMap;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable; import java.util.Hashtable;
///#ifdef JDK12
///import java.util.Collections;
///import java.util.Map;
///import java.util.Iterator;
///#else
import jode.util.Collections;
import jode.util.Map;
import jode.util.Iterator;
///#endif
public final class InvokeOperator extends Operator public final class InvokeOperator extends Operator
implements MatchableOperator { implements MatchableOperator {
@ -44,6 +54,19 @@ public final class InvokeOperator extends Operator
Type classType; Type classType;
Type[] hints; Type[] hints;
/**
* This hashtable contains hints for every library method. Some
* library method take or return an int, but it should be a char
* instead. We will remember that here to give them the right
* hint.
*
* The key is the string: methodName + "." + methodType, the value
* is a map: It maps base class types for which this hint applies,
* to an array of hint types corresponding to the parameters: The
* first element is the hint type of the return value, the
* remaining entries are the hint types of the parameters. All
* hint types may be null, if that parameter shouldn't be hinted.
*/
private final static Hashtable hintTypes = new Hashtable(); private final static Hashtable hintTypes = new Hashtable();
static { static {
@ -52,77 +75,44 @@ public final class InvokeOperator extends Operator
* though the formal parameter is an int. * though the formal parameter is an int.
* First hint is hint of return value (even if void) * First hint is hint of return value (even if void)
* other hints are that of the parameters in order * other hints are that of the parameters in order
*
* You only have to hint the base class. Other classes will
* inherit the hints.
*
* We reuse a lot of objects, since they are all unchangeable
* this is no problem. We only hint for chars; it doesn't
* make much sense to hint for byte, since its constant
* representation is more difficult than an int
* representation. If you have more hints to suggest, please
* write contact me. (see GlobalOptions.EMAIL)
*/ */
Type tCharHint = new IntegerType(IntegerType.IT_I, IntegerType.IT_C); Type tCharHint = new IntegerType(IntegerType.IT_I, IntegerType.IT_C);
Type[] hintC = new Type[] { tCharHint }; Type[] hintC = new Type[] { tCharHint };
Type[] hint0C = new Type[] { null, tCharHint }; Type[] hint0C = new Type[] { null, tCharHint };
Type[] hint0C0 = new Type[] { null, tCharHint, null }; Type[] hint0C0 = new Type[] { null, tCharHint, null };
hintTypes.put(Reference.getReference
("Ljava/lang/String;", "indexOf", "(I)I"), Map hintString0CMap = new SimpleMap
hint0C); (Collections.singleton
hintTypes.put(Reference.getReference (new SimpleMap.SimpleEntry(Type.tString, hint0C)));
("Ljava/lang/String;", "indexOf", "(II)I"), Map hintString0C0Map = new SimpleMap
hint0C0); (Collections.singleton
hintTypes.put(Reference.getReference (new SimpleMap.SimpleEntry(Type.tString, hint0C0)));
("Ljava/lang/String;", "lastIndexOf", "(I)I"), hintTypes.put("indexOf.(I)I", hintString0CMap);
hint0C); hintTypes.put("lastIndexOf.(I)I", hintString0CMap);
hintTypes.put(Reference.getReference hintTypes.put("indexOf.(II)I", hintString0C0Map);
("Ljava/lang/String;", "lastIndexOf", "(II)I"), hintTypes.put("lastIndexOf.(II)I", hintString0C0Map);
hint0C0); hintTypes.put("write.(I)V", new SimpleMap
hintTypes.put(Reference.getReference (Collections.singleton
("Ljava/io/Writer;", "write", "(I)V"), (new SimpleMap.SimpleEntry
hint0C); (Type.tClass("java.io.Writer"), hint0C))));
hintTypes.put(Reference.getReference hintTypes.put("read.()I", new SimpleMap
("Ljava/io/BufferedWriter;", "write", "(I)V"), (Collections.singleton
hint0C); (new SimpleMap.SimpleEntry
hintTypes.put(Reference.getReference (Type.tClass("java.io.Reader"), hintC))));
("Ljava/io/CharArrayWriter;", "write", "(I)V"), hintTypes.put("unread.(I)V", new SimpleMap
hint0C); (Collections.singleton
hintTypes.put(Reference.getReference (new SimpleMap.SimpleEntry
("Ljava/io/FilterWriter;", "write", "(I)V"), (Type.tClass("java.io.PushbackReader"), hint0C))));
hint0C);
hintTypes.put(Reference.getReference
("Ljava/io/OutputStreamWriter;", "write", "(I)V"),
hint0C);
hintTypes.put(Reference.getReference
("Ljava/io/PipedWriter;", "write", "(I)V"),
hint0C);
hintTypes.put(Reference.getReference
("Ljava/io/PrintWriter;", "write", "(I)V"),
hint0C);
hintTypes.put(Reference.getReference
("Ljava/io/StringWriter;", "write", "(I)V"),
hint0C);
hintTypes.put(Reference.getReference
("Ljava/io/PushbackReader;", "unread", "(I)V"),
hint0C);
hintTypes.put(Reference.getReference
("Ljava/lang/Reader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/BufferedReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/CharArrayReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/FilterReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/InputStreamReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/LineNumberReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/PipedReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/PushBackReader;", "read", "()I"),
hintC);
hintTypes.put(Reference.getReference
("Ljava/lang/StringReader;", "read", "()I"),
hintC);
} }
@ -133,7 +123,17 @@ public final class InvokeOperator extends Operator
this.methodType = Type.tMethod(reference.getType()); this.methodType = Type.tMethod(reference.getType());
this.methodName = reference.getName(); this.methodName = reference.getName();
this.classType = Type.tType(reference.getClazz()); this.classType = Type.tType(reference.getClazz());
this.hints = (Type[]) hintTypes.get(reference); this.hints = null;
Map allHints = (Map) hintTypes.get(methodName+"."+methodType);
if (allHints != null) {
for (Iterator i = allHints.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry) i.next();
if (classType.isOfType(((Type)e.getKey()).getSubType())) {
this.hints = (Type[]) e.getValue();
break;
}
}
}
if (hints != null && hints[0] != null) if (hints != null && hints[0] != null)
this.type = hints[0]; this.type = hints[0];
else else
@ -241,11 +241,11 @@ public final class InvokeOperator extends Operator
} }
public MethodAnalyzer getMethodAnalyzer() { public MethodAnalyzer getMethodAnalyzer() {
if (classType instanceof ClassInterfacesType) { ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer(); ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) { while (true) {
if (((ClassInterfacesType) classType).getClassInfo() if (clazz == ana.getClazz()) {
== ana.getClazz()) {
return ana.getMethod(methodName, methodType); return ana.getMethod(methodName, methodType);
} }
if (ana.getParent() == null) if (ana.getParent() == null)
@ -267,9 +267,9 @@ public final class InvokeOperator extends Operator
* @XXX check, if its the first super class that implements the method. * @XXX check, if its the first super class that implements the method.
*/ */
public boolean isSuperOrThis() { public boolean isSuperOrThis() {
if (classType instanceof ClassInterfacesType) { ClassInfo clazz = getClassInfo();
return ((ClassInterfacesType) classType).getClassInfo() if (clazz != null) {
.superClassOf(methodAnalyzer.getClazz()); return clazz.superClassOf(methodAnalyzer.getClazz());
} }
return false; return false;
} }
@ -446,7 +446,7 @@ public final class InvokeOperator extends Operator
if (getMethodAnalyzer() != null) { if (getMethodAnalyzer() != null) {
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
if (synth != null) { if (synth != null) {
Operator op = null; Expression op = null;
switch (synth.getKind()) { switch (synth.getKind()) {
case SyntheticAnalyzer.ACCESSGETFIELD: case SyntheticAnalyzer.ACCESSGETFIELD:
op = new GetFieldOperator(methodAnalyzer, false, op = new GetFieldOperator(methodAnalyzer, false,
@ -478,8 +478,11 @@ public final class InvokeOperator extends Operator
if (op != null) { if (op != null) {
if (subExpressions != null) { if (subExpressions != null) {
for (int i=subExpressions.length; i-- > 0; ) for (int i=subExpressions.length; i-- > 0; ) {
op.addOperand(subExpressions[i]); op = op.addOperand(subExpressions[i]);
if (subExpressions[i].getFreeOperandCount() > 0)
break;
}
} }
return op; return op;
} }
@ -639,6 +642,9 @@ public final class InvokeOperator extends Operator
/* XXX check that this is the first defined /* XXX check that this is the first defined
* super method. */ * super method. */
writer.print("super"); writer.print("super");
ClassInfo superClazz = getClassInfo().getSuperclass();
paramTypes[0] = superClazz == null
? Type.tObject : Type.tClass(superClazz);
opIsThis = false; opIsThis = false;
} }
} else { } else {
@ -675,8 +681,20 @@ public final class InvokeOperator extends Operator
*/ */
getMethodAnalyzer() == null getMethodAnalyzer() == null
&& writer.conflicts(methodName, null, && writer.conflicts(methodName, null,
Scope.METHODNAME)) { Scope.NOSUPERMETHODNAME)) {
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."); 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 { } else {
if (needsCast(0, paramTypes)){ if (needsCast(0, paramTypes)){
@ -712,7 +730,7 @@ public final class InvokeOperator extends Operator
Type castType = methodType.getParameterTypes()[arg-offset]; Type castType = methodType.getParameterTypes()[arg-offset];
writer.print("("); writer.print("(");
writer.printType(castType); writer.printType(castType);
writer.print(")"); writer.print(") ");
paramTypes[arg] = castType; paramTypes[arg] = castType;
priority = 700; priority = 700;
} }

Loading…
Cancel
Save