Fix problems with getting parameter names in generated code. This manifests
itself when, for example, generating i18n output files from messages in a
UiBinder generated source file. Also, used the actual argument names in the
generated output files for convenience and clarity.
Patch by: jat
Review by: scottb, rjrjr
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7378 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java b/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
index 4d523fe..eb4f340 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
@@ -74,7 +74,7 @@
ArtificialRescueChecker.check(cud, builder.isGenerated());
BinaryTypeReferenceRestrictionsChecker.check(cud);
- // TODO: Collect parameter names?
+ MethodArgNamesLookup methodArgs = MethodParamCollector.collect(cud);
CompilationUnitInvalidator.reportErrors(logger, cud,
builder.getSource());
@@ -82,7 +82,8 @@
Set<ContentId> dependencies = compiler.computeDependencies(cud,
jsniDeps);
CompilationUnit unit = builder.build(compiledClasses, dependencies,
- jsniMethods.values(), cud.compilationResult().getProblems());
+ jsniMethods.values(), methodArgs,
+ cud.compilationResult().getProblems());
if (cud.compilationResult().hasErrors()) {
unit = new ErrorCompilationUnit(unit);
} else {
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
index b54161c..11bb848 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -266,6 +266,11 @@
public abstract long getLastModified();
/**
+ * @return a way to lookup method argument names for this compilation unit.
+ */
+ public abstract MethodArgNamesLookup getMethodArgs();
+
+ /**
* Returns the source code for this unit.
*/
@Deprecated
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java
index 6941e9b..d5f3413 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java
@@ -63,9 +63,9 @@
protected CompilationUnit makeUnit(List<CompiledClass> compiledClasses,
Set<ContentId> dependencies,
Collection<? extends JsniMethod> jsniMethods,
- CategorizedProblem[] problems) {
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
return new GeneratedCompilationUnit(generatedUnit, compiledClasses,
- dependencies, jsniMethods, problems);
+ dependencies, jsniMethods, methodArgs, problems);
}
@Override
@@ -148,9 +148,9 @@
protected CompilationUnit makeUnit(List<CompiledClass> compiledClasses,
Set<ContentId> dependencies,
Collection<? extends JsniMethod> jsniMethods,
- CategorizedProblem[] problems) {
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
return new SourceFileCompilationUnit(getResource(), contentId,
- compiledClasses, dependencies, jsniMethods, problems);
+ compiledClasses, dependencies, jsniMethods, methodArgs, problems);
}
}
@@ -161,8 +161,8 @@
public GeneratedCompilationUnit(GeneratedUnit generatedUnit,
List<CompiledClass> compiledClasses, Set<ContentId> dependencies,
Collection<? extends JsniMethod> jsniMethods,
- CategorizedProblem[] problems) {
- super(compiledClasses, dependencies, jsniMethods, problems);
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
+ super(compiledClasses, dependencies, jsniMethods, methodArgs, problems);
this.generatedUnit = generatedUnit;
}
@@ -176,6 +176,7 @@
return generatedUnit.creationTime();
}
+ @Deprecated
@Override
public String getSource() {
return generatedUnit.getSource();
@@ -186,11 +187,13 @@
return generatedUnit.getTypeName();
}
+ @Deprecated
@Override
public boolean isGenerated() {
return true;
}
+ @Deprecated
@Override
public boolean isSuperSource() {
return false;
@@ -234,10 +237,11 @@
public CompilationUnit build(List<CompiledClass> compiledClasses,
Set<ContentId> dependencies,
Collection<? extends JsniMethod> jsniMethods,
- CategorizedProblem[] problems) {
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
// Free the source now.
source = null;
- return makeUnit(compiledClasses, dependencies, jsniMethods, problems);
+ return makeUnit(compiledClasses, dependencies, jsniMethods, methodArgs,
+ problems);
}
public abstract ContentId getContentId();
@@ -262,7 +266,8 @@
protected abstract CompilationUnit makeUnit(
List<CompiledClass> compiledClasses, Set<ContentId> dependencies,
- Collection<? extends JsniMethod> jsniMethods, CategorizedProblem[] errors);
+ Collection<? extends JsniMethod> jsniMethods,
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] errors);
/**
* This only matters for {@link ArtificialRescueChecker}.
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java
index f97c545..fcb3c0f 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java
@@ -29,35 +29,46 @@
private final List<CompiledClass> exposedCompiledClasses;
private final List<JsniMethod> jsniMethods;
private final CategorizedProblem[] problems;
+ private final MethodArgNamesLookup methodArgs;
public CompilationUnitImpl(List<CompiledClass> compiledClasses,
Set<ContentId> dependencies,
Collection<? extends JsniMethod> jsniMethods,
- CategorizedProblem[] problems) {
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
this.exposedCompiledClasses = Lists.normalizeUnmodifiable(compiledClasses);
this.dependencies = dependencies;
this.jsniMethods = Lists.create(jsniMethods.toArray(new JsniMethod[jsniMethods.size()]));
+ this.methodArgs = methodArgs;
this.problems = problems;
for (CompiledClass cc : compiledClasses) {
cc.initUnit(this);
}
}
+ @Override
public List<JsniMethod> getJsniMethods() {
return jsniMethods;
}
+ @Override
+ public MethodArgNamesLookup getMethodArgs() {
+ return methodArgs;
+ }
+
/**
* Returns all contained classes.
*/
+ @Override
Collection<CompiledClass> getCompiledClasses() {
return exposedCompiledClasses;
}
+ @Override
Set<ContentId> getDependencies() {
return dependencies;
}
+ @Override
CategorizedProblem[] getProblems() {
return problems;
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/ErrorCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/ErrorCompilationUnit.java
index 9564cdd..0dbc168 100644
--- a/dev/core/src/com/google/gwt/dev/javac/ErrorCompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/ErrorCompilationUnit.java
@@ -32,38 +32,55 @@
this.unit = unit;
}
+ @Override
public String getDisplayLocation() {
return unit.getDisplayLocation();
}
+ @Override
public List<JsniMethod> getJsniMethods() {
return unit.getJsniMethods();
}
+ @Override
public long getLastModified() {
return unit.getLastModified();
}
+ @Override
+ public MethodArgNamesLookup getMethodArgs() {
+ return unit.getMethodArgs();
+ }
+
+ @Override
+ @Deprecated
public String getSource() {
return unit.getSource();
}
+ @Override
public String getTypeName() {
return unit.getTypeName();
}
+ @Override
public boolean isCompiled() {
return false;
}
+ @Override
public boolean isError() {
return true;
}
+ @Override
+ @Deprecated
public boolean isGenerated() {
return unit.isGenerated();
}
+ @Override
+ @Deprecated
public boolean isSuperSource() {
return unit.isSuperSource();
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/InvalidCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/InvalidCompilationUnit.java
index a87be20..c0fbeef 100644
--- a/dev/core/src/com/google/gwt/dev/javac/InvalidCompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/InvalidCompilationUnit.java
@@ -32,38 +32,55 @@
this.unit = unit;
}
+ @Override
public String getDisplayLocation() {
return unit.getDisplayLocation();
}
+ @Override
public List<JsniMethod> getJsniMethods() {
return unit.getJsniMethods();
}
+ @Override
public long getLastModified() {
return unit.getLastModified();
}
+ @Override
+ public MethodArgNamesLookup getMethodArgs() {
+ return unit.getMethodArgs();
+ }
+
+ @Override
+ @Deprecated
public String getSource() {
return unit.getSource();
}
+ @Override
public String getTypeName() {
return unit.getTypeName();
}
+ @Override
public boolean isCompiled() {
return false;
}
+ @Override
public boolean isError() {
return false;
}
+ @Override
+ @Deprecated
public boolean isGenerated() {
return unit.isGenerated();
}
+ @Override
+ @Deprecated
public boolean isSuperSource() {
return unit.isSuperSource();
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
index 99439d7..e685994 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -85,6 +85,7 @@
CompilationUnit unit = builder.build(compiledClasses,
compiler.computeDependencies(cud),
Collections.<JsniMethod> emptyList(),
+ new MethodArgNamesLookup(),
cud.compilationResult().getProblems());
if (cud.compilationResult().hasErrors()) {
unit = new ErrorCompilationUnit(unit);
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
index d91dc84..922faf2 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
@@ -27,20 +27,15 @@
import com.google.gwt.dev.js.ast.JsParameter;
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsStatement;
-import com.google.gwt.dev.util.Name.InternalName;
import com.google.gwt.dev.util.collect.IdentityHashMap;
import com.google.gwt.dev.util.collect.IdentityMaps;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
-import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.Util;
@@ -118,6 +113,38 @@
}
}
+ private static class Visitor extends MethodVisitor {
+
+ private final Map<AbstractMethodDeclaration, JsniMethod> jsniMethods;
+ private final JsProgram jsProgram;
+ private final String source;
+
+ public Visitor(String source, JsProgram program,
+ Map<AbstractMethodDeclaration, JsniMethod> jsniMethods) {
+ this.jsProgram = program;
+ this.jsniMethods = jsniMethods;
+ this.source = source;
+ }
+
+ @Override
+ protected boolean interestingMethod(AbstractMethodDeclaration method) {
+ return method.isNative();
+ }
+
+ @Override
+ protected void processMethod(TypeDeclaration typeDecl,
+ AbstractMethodDeclaration method, String enclosingType,
+ String loc) {
+ JsFunction jsFunction = parseJsniFunction(method, source, enclosingType,
+ loc, jsProgram);
+ if (jsFunction != null) {
+ String jsniSignature = getJsniSignature(enclosingType, method);
+ jsniMethods.put(method, new JsniMethodImpl(jsniSignature,
+ jsFunction));
+ }
+ }
+ }
+
public static final String JSNI_BLOCK_END = "}-*/";
public static final String JSNI_BLOCK_START = "/*-{";
@@ -125,23 +152,8 @@
public static Map<AbstractMethodDeclaration, JsniMethod> collectJsniMethods(
final CompilationUnitDeclaration cud, final String source,
final JsProgram program) {
- final Map<AbstractMethodDeclaration, JsniMethod> jsniMethods = new IdentityHashMap<AbstractMethodDeclaration, JsniMethod>();
- cud.traverse(new ASTVisitor() {
- @Override
- public void endVisit(TypeDeclaration type, BlockScope scope) {
- collectJsniMethods(cud, type, source, program, jsniMethods);
- }
-
- @Override
- public void endVisit(TypeDeclaration type, ClassScope scope) {
- collectJsniMethods(cud, type, source, program, jsniMethods);
- }
-
- @Override
- public void endVisit(TypeDeclaration type, CompilationUnitScope scope) {
- collectJsniMethods(cud, type, source, program, jsniMethods);
- }
- }, cud.scope);
+ Map<AbstractMethodDeclaration, JsniMethod> jsniMethods = new IdentityHashMap<AbstractMethodDeclaration, JsniMethod>();
+ new Visitor(source, program, jsniMethods).collect(cud);
return IdentityMaps.normalizeUnmodifiable(jsniMethods);
}
@@ -246,43 +258,6 @@
reportJsniProblem(info, method, msg, ProblemSeverities.Warning);
}
- private static void collectJsniMethods(CompilationUnitDeclaration cud,
- TypeDeclaration typeDecl, String source, JsProgram jsProgram,
- Map<AbstractMethodDeclaration, JsniMethod> results) {
- AbstractMethodDeclaration[] methods = typeDecl.methods;
- if (methods == null) {
- return;
- }
-
- // Lazy initialize these when a native method is actually hit.
- String enclosingType = null;
- String loc = null;
- boolean lazyInitialized = false;
-
- for (AbstractMethodDeclaration method : methods) {
- if (!method.isNative()) {
- continue;
- }
-
- if (!lazyInitialized) {
- char[] constantPoolName = typeDecl.binding.constantPoolName();
- if (constantPoolName == null) {
- // Unreachable local type
- return;
- }
- enclosingType = InternalName.toBinaryName(String.valueOf(constantPoolName));
- loc = String.valueOf(cud.getFileName());
- lazyInitialized = true;
- }
- JsFunction jsFunction = parseJsniFunction(method, source, enclosingType,
- loc, jsProgram);
- if (jsFunction != null) {
- String jsniSignature = getJsniSignature(enclosingType, method);
- results.put(method, new JsniMethodImpl(jsniSignature, jsFunction));
- }
- }
- }
-
/**
* JS reports the error as a line number, to find the absolute position in the
* real source stream, we have to walk from the absolute JS start position
@@ -336,25 +311,8 @@
*/
private static String getJsniSignature(String enclosingType,
AbstractMethodDeclaration method) {
- return '@' + enclosingType + "::" + getMemberSignature(method);
- }
-
- /**
- * Gets a unique name for this method and its signature (this is used to
- * determine whether one method overrides another).
- */
- private static String getMemberSignature(AbstractMethodDeclaration method) {
- String name = String.valueOf(method.selector);
- StringBuilder sb = new StringBuilder();
- sb.append(name);
- sb.append("(");
- if (method.arguments != null) {
- for (Argument param : method.arguments) {
- sb.append(param.binding.type.signature());
- }
- }
- sb.append(")");
- return sb.toString();
+ return '@' + enclosingType + "::"
+ + MethodVisitor.getMemberSignature(method);
}
private static void reportJsniProblem(SourceInfo info,
diff --git a/dev/core/src/com/google/gwt/dev/javac/MethodArgNamesLookup.java b/dev/core/src/com/google/gwt/dev/javac/MethodArgNamesLookup.java
new file mode 100644
index 0000000..0b9d667
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/MethodArgNamesLookup.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.javac;
+
+import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
+import com.google.gwt.dev.javac.asm.CollectMethodData;
+import com.google.gwt.dev.util.collect.Maps;
+
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Keeps track of method argument names that cannot be read from just the
+ * bytecode.
+ */
+public class MethodArgNamesLookup {
+
+ private Map<String, String[]> methodArgs;
+
+ public MethodArgNamesLookup() {
+ this.methodArgs = new HashMap<String, String[]>();
+ }
+
+ /**
+ * Prevent further modification to this object. Calls to
+ * {@link #store(String, AbstractMethodDeclaration)} or
+ * {@link #mergeFrom(MethodArgNamesLookup)} on this object will fail after
+ * this method is called.
+ */
+ public void freeze() {
+ methodArgs = Maps.normalizeUnmodifiable(methodArgs);
+ }
+
+ /**
+ * Lookup the argument names for a given method.
+ *
+ * @param method TypeOracle method
+ * @param methodData method data collected from bytecode
+ * @return an array of the argument names, or null if unavailable
+ */
+ public String[] lookup(JAbstractMethod method, CollectMethodData methodData) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(method.getEnclosingType().getQualifiedBinaryName());
+ buf.append('.').append(method.getName());
+ buf.append(methodData.getDesc());
+ String key = buf.toString();
+ return methodArgs.get(key);
+ }
+
+ /**
+ * Merge argument names from another lookup map into this one.
+ *
+ * @param other
+ */
+ public void mergeFrom(MethodArgNamesLookup other) {
+ methodArgs.putAll(other.methodArgs);
+ }
+
+ /**
+ * Store the argument names for a method.
+ * <p>
+ * <b>Note: method must have non-zero arguments.<b>
+ *
+ * @param enclosingType fully qualified binary name of the enclosing type
+ * @param method JDT method
+ */
+ public void store(String enclosingType,
+ AbstractMethodDeclaration method) {
+ int n = method.arguments.length;
+ String[] argNames = new String[n];
+ for (int i = 0; i < n; ++i) {
+ argNames[i] = String.valueOf(method.arguments[i].name);
+ }
+ StringBuilder buf = new StringBuilder();
+ buf.append(enclosingType).append('.').append(method.selector);
+ buf.append(method.binding.signature());
+ String key = buf.toString();
+ methodArgs.put(key, argNames);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/MethodParamCollector.java b/dev/core/src/com/google/gwt/dev/javac/MethodParamCollector.java
new file mode 100644
index 0000000..8b36de4
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/MethodParamCollector.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.javac;
+
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+
+/**
+ * Collects method parameter names.
+ */
+public class MethodParamCollector {
+
+ private static class Visitor extends MethodVisitor {
+
+ private final MethodArgNamesLookup methodArgs;
+
+ public Visitor(MethodArgNamesLookup methodArgs) {
+ this.methodArgs = methodArgs;
+ }
+
+ @Override
+ protected boolean interestingMethod(AbstractMethodDeclaration method) {
+ return method.arguments != null && method.arguments.length > 0
+ && method.isAbstract();
+ }
+
+ @Override
+ protected void processMethod(TypeDeclaration typeDecl,
+ AbstractMethodDeclaration method, String enclosingType, String loc) {
+ methodArgs.store(enclosingType, method);
+ }
+ }
+
+ /**
+ * Returns an unmodifiable MethodArgNamesLookup containing the method argument
+ * names for the supplied compilation unit.
+ *
+ * @param cud
+ * @return MethodArgNamesLookup instance
+ */
+ public static MethodArgNamesLookup collect(CompilationUnitDeclaration cud) {
+ MethodArgNamesLookup methodArgs = new MethodArgNamesLookup();
+ new Visitor(methodArgs).collect(cud);
+ methodArgs.freeze();
+ return methodArgs;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/MethodVisitor.java b/dev/core/src/com/google/gwt/dev/javac/MethodVisitor.java
new file mode 100644
index 0000000..eab9613
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/MethodVisitor.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.javac;
+
+import com.google.gwt.dev.util.Name.InternalName;
+
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+
+/**
+ * Base class of things that walk methods in a CUD and collect things
+ * about interesting methods.
+ */
+public abstract class MethodVisitor {
+
+ /**
+ * Gets a unique name for this method, including its signature.
+ */
+ protected static String getMemberSignature(AbstractMethodDeclaration method) {
+ String name = String.valueOf(method.selector);
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ sb.append("(");
+ if (method.arguments != null) {
+ for (Argument param : method.arguments) {
+ sb.append(param.binding.type.signature());
+ }
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * Collect data about interesting methods in one compilation unit.
+ *
+ * @param cud
+ */
+ public final void collect(final CompilationUnitDeclaration cud) {
+ cud.traverse(new ASTVisitor() {
+ @Override
+ public void endVisit(TypeDeclaration type, BlockScope scope) {
+ collectMethods(cud, type);
+ }
+
+ @Override
+ public void endVisit(TypeDeclaration type, ClassScope scope) {
+ collectMethods(cud, type);
+ }
+
+ @Override
+ public void endVisit(TypeDeclaration type, CompilationUnitScope scope) {
+ collectMethods(cud, type);
+ }
+ }, cud.scope);
+ }
+
+ /**
+ * Provided by a subclass to return true if this method should be processed.
+ * This is separate since some extra work is performed in order to call
+ * {@link #processMethod}.
+ *
+ * @param method
+ * @return true if processMethod should be called on this method
+ */
+ protected abstract boolean interestingMethod(
+ AbstractMethodDeclaration method);
+
+ /**
+ * Provided by a subclass to process a method definition. Methods which have
+ * no name are not passed to this method, even if {@link #interestingMethod}
+ * returns true.
+ *
+ * @param typeDecl
+ * @param method
+ * @param enclosingType
+ * @param loc
+ */
+ protected abstract void processMethod(TypeDeclaration typeDecl,
+ AbstractMethodDeclaration method, String enclosingType, String loc);
+
+ /**
+ * Collect data about interesting methods on a particular type in a
+ * compilation unit.
+ *
+ * @param cud
+ * @param typeDecl
+ */
+ private void collectMethods(CompilationUnitDeclaration cud,
+ TypeDeclaration typeDecl) {
+ AbstractMethodDeclaration[] methods = typeDecl.methods;
+ if (methods == null) {
+ return;
+ }
+
+ // Lazy initialize these when an interesting method is actually hit.
+ String enclosingType = null;
+ String loc = null;
+ boolean lazyInitialized = false;
+
+ for (AbstractMethodDeclaration method : methods) {
+ if (!interestingMethod(method)) {
+ continue;
+ }
+
+ if (!lazyInitialized) {
+ char[] constantPoolName = typeDecl.binding.constantPoolName();
+ if (constantPoolName == null) {
+ // Unreachable local type
+ return;
+ }
+ enclosingType = InternalName.toBinaryName(String.valueOf(
+ constantPoolName));
+ loc = String.valueOf(cud.getFileName());
+ lazyInitialized = true;
+ }
+ processMethod(typeDecl, method, enclosingType, loc);
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java
index 4e272ca..e77f614 100644
--- a/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java
@@ -42,8 +42,8 @@
public SourceFileCompilationUnit(Resource sourceFile, ContentId contentId,
List<CompiledClass> compiledClasses, Set<ContentId> dependencies,
Collection<? extends JsniMethod> jsniMethods,
- CategorizedProblem[] problems) {
- super(compiledClasses, dependencies, jsniMethods, problems);
+ MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
+ super(compiledClasses, dependencies, jsniMethods, methodArgs, problems);
this.sourceFile = sourceFile;
this.contentId = contentId;
}
@@ -58,6 +58,7 @@
return sourceFile.getLastModified();
}
+ @Deprecated
@Override
public String getSource() {
if (cacheToken < 0) {
@@ -78,11 +79,13 @@
return Shared.getTypeName(sourceFile);
}
+ @Deprecated
@Override
public boolean isGenerated() {
return false;
}
+ @Deprecated
@Override
public boolean isSuperSource() {
return sourceFile.wasRerooted();
diff --git a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
index 3d828a5..ebd5e8d 100644
--- a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
@@ -53,7 +53,6 @@
import com.google.gwt.dev.javac.asm.ResolveTypeSignature;
import com.google.gwt.dev.javac.asm.CollectAnnotationData.AnnotationData;
import com.google.gwt.dev.javac.asm.CollectClassData.AnnotationEnum;
-import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.Name;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Name.InternalName;
@@ -223,6 +222,10 @@
final TypeOracle typeOracle;
+ // map of fully qualified method names to their argument names
+ // transient since it is not retained across calls to addNewUnits
+ private transient MethodArgNamesLookup allMethodArgs;
+
// map of internal names to class visitors
// transient since it is not retained across calls to addNewUnits
private transient Map<String, CollectClassData> classMap;
@@ -309,6 +312,7 @@
// Perform a shallow pass to establish identity for new and old types.
classMapType = new HashMap<JRealClassType, CollectClassData>();
+ allMethodArgs = new MethodArgNamesLookup();
Set<JRealClassType> unresolvedTypes = new HashSet<JRealClassType>();
for (CompilationUnit unit : units) {
if (!unit.isCompiled()) {
@@ -324,11 +328,7 @@
}
JRealClassType type = createType(compiledClass, unresolvedTypes);
if (type != null) {
- if (unit instanceof SourceFileCompilationUnit) {
- SourceFileCompilationUnit sourceUnit = (SourceFileCompilationUnit) unit;
- Resource sourceFile = sourceUnit.getSourceFile();
- typeOracle.addSourceReference(type, sourceFile);
- }
+ allMethodArgs.mergeFrom(unit.getMethodArgs());
binaryMapper.put(internalName, type);
classMapType.put(type, cv);
}
@@ -359,6 +359,7 @@
typeOracle.finish();
// no longer needed
+ allMethodArgs = null;
classMap = null;
classMapType = null;
PerfLogger.end();
@@ -538,7 +539,6 @@
return output;
}
-
/**
* Collects data about a class which only needs the bytecode and no TypeOracle
* data structures. This is used to make the initial shallow identity pass for
@@ -968,7 +968,7 @@
ResolveMethodSignature methodResolver = new ResolveMethodSignature(
resolver, logger, method, typeParamLookup, hasReturnType, methodData,
methodData.getArgTypes(), methodData.getArgNames(),
- methodData.hasActualArgNames());
+ methodData.hasActualArgNames(), allMethodArgs);
// TraceSignatureVisitor trace = new TraceSignatureVisitor(
// methodData.getAccess());
// reader.accept(trace);
@@ -1020,8 +1020,15 @@
private boolean resolveParameters(TreeLogger logger, JAbstractMethod method,
CollectMethodData methodData) {
Type[] argTypes = methodData.getArgTypes();
- String[] argNames = methodData.getArgNames();
boolean argNamesAreReal = methodData.hasActualArgNames();
+ String[] argNames = methodData.getArgNames();
+ if (!argNamesAreReal) {
+ String[] lookupNames = allMethodArgs.lookup(method, methodData);
+ if (lookupNames != null) {
+ argNames = lookupNames;
+ argNamesAreReal = true;
+ }
+ }
List<CollectAnnotationData>[] paramAnnot = methodData.getArgAnnotations();
for (int i = 0; i < argTypes.length; ++i) {
JType argType = resolveType(argTypes[i]);
diff --git a/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java b/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java
index 639e867..82ab78d 100644
--- a/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java
+++ b/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java
@@ -87,6 +87,10 @@
argNames[i] = "arg" + i;
paramAnnots[i] = new ArrayList<CollectAnnotationData>();
}
+ if (argNames.length == 0) {
+ // save some work later if there aren't any parameters
+ actualArgNames = true;
+ }
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java b/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java
index 2a612e4..8939958 100644
--- a/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java
+++ b/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java
@@ -24,6 +24,7 @@
import com.google.gwt.core.ext.typeinfo.JTypeParameter;
import com.google.gwt.dev.asm.Type;
import com.google.gwt.dev.asm.signature.SignatureVisitor;
+import com.google.gwt.dev.javac.MethodArgNamesLookup;
import com.google.gwt.dev.javac.Resolver;
import com.google.gwt.dev.javac.TypeParameterLookup;
@@ -48,6 +49,7 @@
private final Type[] argTypes;
private final String[] argNames;
private final boolean argNamesAreReal;
+ private final MethodArgNamesLookup allMethodArgs;
private JType[] returnType = new JType[1];
private List<JType[]> params = new ArrayList<JType[]>();
@@ -67,11 +69,13 @@
* @param argTypes
* @param argNames
* @param argNamesAreReal
+ * @param allMethodArgs
*/
public ResolveMethodSignature(Resolver resolver, TreeLogger logger,
JAbstractMethod method, TypeParameterLookup typeParamLookup,
boolean hasReturnType, CollectMethodData methodData, Type[] argTypes,
- String[] argNames, boolean argNamesAreReal) {
+ String[] argNames, boolean argNamesAreReal,
+ MethodArgNamesLookup allMethodArgs) {
this.resolver = resolver;
this.logger = logger;
this.method = method;
@@ -81,6 +85,7 @@
this.argTypes = argTypes;
this.argNames = argNames;
this.argNamesAreReal = argNamesAreReal;
+ this.allMethodArgs = allMethodArgs;
}
/**
@@ -106,6 +111,16 @@
+ methodData.getDesc() + ") and signature ("
+ methodData.getSignature() + ")");
}
+ String[] names = argNames;
+ boolean namesAreReal = argNamesAreReal;
+ if (!namesAreReal) {
+ // lookup argument names in allMethodArgs
+ String[] lookupArgNames = allMethodArgs.lookup(method, methodData);
+ if (lookupArgNames != null) {
+ names = lookupArgNames;
+ namesAreReal = true;
+ }
+ }
for (int i = 0; i < argTypes.length; ++i) {
JType argType = params.get(i)[0];
if (argType == null) {
@@ -118,8 +133,8 @@
declaredAnnotations);
// JParameter adds itself to the method
- new JParameter(method, argType, argNames[i], declaredAnnotations,
- argNamesAreReal);
+ new JParameter(method, argType, names[i], declaredAnnotations,
+ namesAreReal);
}
// Handle thrown exceptions
diff --git a/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java b/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java
index eed044b..c47d02d 100644
--- a/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java
@@ -308,7 +308,7 @@
}
ResolveMethodSignature methodResolver = new ResolveMethodSignature(resolver,
failTreeLogger, method, lookup, true, methodData, argTypes, argNames,
- false);
+ false, Collections.<String, String[]>emptyMap());
new SignatureReader(signature).accept(methodResolver);
methodResolver.finish();
}
diff --git a/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java
index a9a9dd7..c550087 100644
--- a/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/LookupMethodCreator.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
@@ -66,7 +67,13 @@
}
void createMethodFor(JMethod targetMethod) {
- String template = "{0} target = ({0}) cache.get(arg0);";
+ JParameter[] args = targetMethod.getParameters();
+ if (args.length != 1) {
+ throw new IllegalStateException(
+ "ConstantsWithLookup methods must have exactly one argument");
+ }
+ String arg0 = args[0].getName();
+ String template = "{0} target = ({0}) cache.get(" + arg0 + ");";
String returnTypeName = getReturnTypeName();
String lookup = MessageFormat.format(template, new Object[] {returnTypeName});
println(lookup);
@@ -81,7 +88,7 @@
if (methods[i].getReturnType().getErasedType().equals(erasedType)
&& methods[i] != targetMethod) {
String methodName = methods[i].getName();
- String body = "if(arg0.equals(" + wrap(methodName) + ")) {";
+ String body = "if(" + arg0 + ".equals(" + wrap(methodName) + ")) {";
println(body);
indent();
printFound(methodName);
@@ -91,7 +98,7 @@
}
String format = "throw new java.util.MissingResourceException(\"Cannot find constant ''\" +"
+ "{0} + \"''; expecting a method name\", \"{1}\", {0});";
- String result = MessageFormat.format(format, "arg0",
+ String result = MessageFormat.format(format, arg0,
this.currentCreator.getTarget().getQualifiedSourceName());
println(result);
}
diff --git a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
index a360356..a6725e2 100644
--- a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
@@ -338,7 +338,8 @@
generated.append(PluralRule.class.getCanonicalName());
generated.append(" rule = new " + rule.getClass().getCanonicalName()
+ "();\n");
- generated.append("switch (rule.select(arg" + pluralParamIndex + ")) {\n");
+ generated.append("switch (rule.select("
+ + params[pluralParamIndex].getName() + ")) {\n");
PluralForm[] pluralForms = rule.pluralForms();
resourceList.setPluralForms(key, pluralForms);
// Skip default plural form (index 0); the fall-through case will handle
@@ -370,8 +371,8 @@
if (!seenFlags[i]) {
Optional optional = params[i].getAnnotation(Optional.class);
if (optional == null) {
- throw error(logger, "Required argument " + i + " not present: "
- + template);
+ throw error(logger, "Required argument " + params[i].getName()
+ + " not present: " + template);
}
}
}
@@ -459,7 +460,7 @@
+ " beyond range of arguments: " + template);
}
seenFlag[argNumber] = true;
- String arg = "arg" + argNumber;
+ String arg = params[argNumber].getName();
String format = argChunk.getFormat();
if (format != null) {
String subformat = argChunk.getSubFormat();
diff --git a/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java b/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java
index 45e23c4..0790903 100644
--- a/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java
+++ b/user/src/com/google/gwt/user/rebind/AbstractGeneratorClassCreator.java
@@ -253,8 +253,8 @@
getWriter().print(",");
}
getWriter().print(
- params[i].getType().getParameterizedQualifiedSourceName() + " arg"
- + (i));
+ params[i].getType().getParameterizedQualifiedSourceName() + " "
+ + params[i].getName());
}
getWriter().println(") {");
getWriter().indent();