- Fixes a bug in GenerateJavaAST where the Iterator variable of a foreach was assigned the wrong type, causing all kinds of madness. - Fixes a latent problem where referencing a generic field fails to generate an appropriate cast operation. - Adds gwt.jjs.traceMethods to the compiler for easy method change tracking Found by: jaimeyap Review by: spoon (pair prog) git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2171 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java index e2976b3..e008c91 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -20,13 +20,20 @@ import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * A Java method implementation. */ public final class JMethod extends JNode implements HasEnclosingType, HasName, - HasSettableType, CanBeAbstract, CanBeSetFinal, CanBeNative, - CanBeStatic { + HasSettableType, CanBeAbstract, CanBeSetFinal, CanBeNative, CanBeStatic { + + private static void trace(String title, String code) { + System.out.println("---------------------------"); + System.out.println(title + ":"); + System.out.println("---------------------------"); + System.out.println(code); + } /** * References to any methods which this method overrides. This should be an @@ -46,6 +53,8 @@ private final String name; private ArrayList<JType> originalParamTypes; private JType returnType; + private boolean trace = false; + private boolean traceFirst = true; /** * These are only supposed to be constructed by JProgram. @@ -72,6 +81,22 @@ JParameter param = params.get(i); originalParamTypes.add(param.getType()); } + + // Determine if we should trace this method. + if (enclosingType != null) { + String jsniSig = JProgram.getJsniSig(this); + Set<String> set = JProgram.traceMethods.get(enclosingType.getName()); + if (set != null && (set.contains(name) || set.contains(jsniSig))) { + trace = true; + } + // Try the short name. + if (!trace && enclosingType != null) { + set = JProgram.traceMethods.get(enclosingType.getShortName()); + if (set != null && (set.contains(name) || set.contains(jsniSig))) { + trace = true; + } + } + } } public JAbstractMethodBody getBody() { @@ -138,6 +163,14 @@ } public void traverse(JVisitor visitor, Context ctx) { + String before = null; + if (trace && visitor instanceof JModVisitor) { + before = this.toSource(); + if (traceFirst) { + traceFirst = false; + trace("Initial", before); + } + } if (visitor.visit(this, ctx)) { visitor.accept(params); if (body != null) { @@ -145,6 +178,16 @@ } } visitor.endVisit(this, ctx); + if (trace && visitor instanceof JModVisitor) { + String after = this.toSource(); + if (!after.equals(before)) { + String title = visitor.getClass().getSimpleName(); + trace(title, after); + } + } } + void copyTraceStatusFrom(JMethod x) { + this.trace = x.trace; + } }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java index 9bc354a..9cbbc04 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -50,6 +50,8 @@ "com.google.gwt.lang.Exceptions", "com.google.gwt.lang.LongLib", "com.google.gwt.lang.Stats",})); + static final Map<String, Set<String>> traceMethods = new HashMap<String, Set<String>>(); + private static final Set<String> INDEX_TYPES_SET = new HashSet<String>( Arrays.asList(new String[] { "java.lang.Object", "java.lang.String", "java.lang.Class", @@ -67,6 +69,43 @@ static { INDEX_TYPES_SET.addAll(CODEGEN_TYPES_SET); + + /* + * The format to trace methods is a colon-separated list of + * "className.methodName", such as "Hello.onModuleLoad:Foo.bar". You can + * fully-qualify a class to disambiguate classes, and you can also append + * the JSNI signature of the method to disambiguate overloads, ala + * "Foo.bar(IZ)". + */ + String toTrace = System.getProperty("gwt.jjs.traceMethods"); + if (toTrace != null) { + String[] split = toTrace.split(":"); + for (String str : split) { + int pos = str.lastIndexOf('.'); + if (pos > 0) { + String className = str.substring(0, pos); + String methodName = str.substring(pos + 1); + Set<String> set = traceMethods.get(className); + if (set == null) { + set = new HashSet<String>(); + traceMethods.put(className, set); + } + set.add(methodName); + } + } + } + } + + public static String getJsniSig(JMethod method) { + StringBuffer sb = new StringBuffer(); + sb.append(method.getName()); + sb.append("("); + for (int i = 0; i < method.getOriginalParamTypes().size(); ++i) { + JType type = method.getOriginalParamTypes().get(i); + sb.append(type.getJsniSignatureName()); + } + sb.append(")"); + return sb.toString(); } public static boolean methodsDoMatch(JMethod method1, JMethod method2) { @@ -701,6 +740,7 @@ public void putStaticImpl(JMethod method, JMethod staticImpl) { instanceToStaticMap.put(method, staticImpl); staticToInstanceMap.put(staticImpl, method); + staticImpl.copyTraceStatusFrom(method); } public JClassType rebind(JType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java index fd392c4..b51c265 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -278,7 +278,7 @@ for (int i = 0; i < type.methods.size(); ++i) { JMethod method = type.methods.get(i); if (method.getName().equals(methodName)) { - String jsniSig = getJsniSig(method); + String jsniSig = JProgram.getJsniSig(method); if (jsniSig.equals(rhs)) { return method; } else if (almostMatches == null) { @@ -387,18 +387,6 @@ } } - private static String getJsniSig(JMethod method) { - StringBuffer sb = new StringBuffer(); - sb.append(method.getName()); - sb.append("("); - for (int i = 0; i < method.getOriginalParamTypes().size(); ++i) { - JType type = method.getOriginalParamTypes().get(i); - sb.append(type.getJsniSignatureName()); - } - sb.append(")"); - return sb.toString(); - } - private static InternalCompilerException translateException(JNode node, Throwable e) { InternalCompilerException ice; @@ -1190,6 +1178,7 @@ JExpression processExpression(FieldReference x) { SourceInfo info = makeSourceInfo(x); FieldBinding fieldBinding = x.binding; + JType type = (JType) typeMap.get(x.resolvedType); JField field; if (fieldBinding.declaringClass == null) { // probably array.length @@ -1203,7 +1192,14 @@ JExpression instance = dispProcessExpression(x.receiver); JExpression fieldRef = new JFieldRef(program, info, instance, field, currentClass); - return fieldRef; + + if (type != field.getType()) { + // Must be a generic; insert a cast operation. + JReferenceType toType = (JReferenceType) type; + return new JCastOperation(program, info, toType, fieldRef); + } else { + return fieldRef; + } } JExpression processExpression(InstanceOfExpression x) { @@ -1753,7 +1749,7 @@ * </pre> */ JLocal iteratorVar = createSyntheticLocal(info, elementVarName - + "$iterator", (JType) typeMap.get(x.collection.resolvedType)); + + "$iterator", program.getIndexedType("Iterator")); List<JStatement> initializers = new ArrayList<JStatement>(1); // Iterator<T> i$iterator = collection.iterator() @@ -1766,10 +1762,20 @@ createVariableRef(info, iteratorVar), program.getIndexedMethod("Iterator.hasNext")); - // T elementVar = i$array[i$index]; - elementDecl.initializer = new JMethodCall(program, info, + // T elementVar = (T) i$iterator.next(); + JMethodCall nextCall = new JMethodCall(program, info, createVariableRef(info, iteratorVar), program.getIndexedMethod("Iterator.next")); + + JType elementType = elementDecl.getVariableRef().getType(); + if (elementType != nextCall.getType()) { + // Must be a generic; insert a cast operation. + elementDecl.initializer = new JCastOperation(program, info, + elementType, nextCall); + } else { + elementDecl.initializer = nextCall; + } + body.statements.add(0, elementDecl); result = new JForStatement(program, info, initializers, condition,