- CompilingClassLoader had a bug related to the JsniRef refactor
- Iterated on warnings produced by LongFromJSNIChecker
- TypeSerializerCreator now produces a suppress long warnings annotation
Review by: spoon (TBR)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2221 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java b/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
index 40808d8..11afaf8 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
@@ -19,9 +19,9 @@
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
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.core.ext.typeinfo.JniConstants;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.util.Jsni;
@@ -61,41 +61,78 @@
@Override
public void endVisit(MethodDeclaration meth, ClassScope scope) {
if (meth.isNative() && !suppressingWarnings(meth, scope)) {
- // check return type
- final TypeReference returnType = meth.returnType;
- if (containsLong(returnType, scope)) {
- warn(meth, "JSNI method with return type of " + returnType);
- }
+ checkDecl(meth, scope);
+ checkRefs(meth, scope);
+ }
+ }
- // check parameter types
- if (meth.arguments != null) {
- for (Argument arg : meth.arguments) {
- if (containsLong(arg.type, scope)) {
- warn(arg, "JSNI method with a parameter of type " + arg.type);
- }
+ private void checkDecl(MethodDeclaration meth, ClassScope scope) {
+ TypeReference returnType = meth.returnType;
+ if (containsLong(returnType, scope)) {
+ warn(meth, "Return value of type '" + returnType
+ + "' is an opaque, non-numeric value in JS code");
+ }
+
+ if (meth.arguments != null) {
+ for (Argument arg : meth.arguments) {
+ if (containsLong(arg.type, scope)) {
+ warn(arg, "Parameter '" + String.valueOf(arg.name) + "': '"
+ + arg.type + "' is an opaque, non-numeric value in JS code");
}
}
+ }
+ }
- // check JSNI references
- FindJsniRefVisitor jsniRefsVisitor = new FindJsniRefVisitor();
- meth.traverse(jsniRefsVisitor, scope);
- Set<String> jsniRefs = jsniRefsVisitor.getJsniRefs();
+ private void checkFieldRef(MethodDeclaration meth, JsniRef jsniRef) {
+ assert jsniRef.isField();
+ JField target = getField(jsniRef);
+ if (target == null) {
+ return;
+ }
+ if (containsLong(target.getType())) {
+ warn(meth, "Referencing field '"
+ + target.getEnclosingType().getSimpleSourceName() + "."
+ + target.getName() + "': '" + target.getType()
+ + "' is an opaque, non-numeric value in JS code");
+ }
+ }
- for (String jsniRefString : jsniRefs) {
- JsniRef jsniRef = JsniRef.parse(jsniRefString);
- if (hasLongParam(jsniRef)) {
- warn(meth, "Passing a long into Java from JSNI (method "
- + jsniRef.memberName() + ")");
- }
- JType jsniRefType = getType(jsniRef);
- if (containsLong(jsniRefType)) {
- if (jsniRef.isMethod()) {
- warn(meth, "Method " + jsniRef.memberName() + " returns type "
- + jsniRefType + ", which cannot be processed in JSNI code");
- } else {
- warn(meth, "Field " + jsniRef.memberName() + " has type "
- + jsniRefType + ", which cannot be processed in JSNI code");
- }
+ private void checkMethodRef(MethodDeclaration meth, JsniRef jsniRef) {
+ assert jsniRef.isMethod();
+ JMethod target = getMethod(jsniRef);
+ if (target == null) {
+ return;
+ }
+ if (containsLong(target.getReturnType())) {
+ warn(meth, "Referencing method '"
+ + target.getEnclosingType().getSimpleSourceName() + "."
+ + target.getName() + "': return type '" + target.getReturnType()
+ + "' is an opaque, non-numeric value in JS code");
+ }
+
+ for (JParameter param : target.getParameters()) {
+ if (containsLong(param.getType())) {
+ warn(meth, "Referencing method '"
+ + target.getEnclosingType().getSimpleSourceName() + "."
+ + target.getName() + "': parameter '" + param.getName() + "': '"
+ + param.getType()
+ + "' is an opaque, non-numeric value in JS code");
+ }
+ }
+ }
+
+ private void checkRefs(MethodDeclaration meth, ClassScope scope) {
+ FindJsniRefVisitor jsniRefsVisitor = new FindJsniRefVisitor();
+ meth.traverse(jsniRefsVisitor, scope);
+ Set<String> jsniRefs = jsniRefsVisitor.getJsniRefs();
+
+ for (String jsniRefString : jsniRefs) {
+ JsniRef jsniRef = JsniRef.parse(jsniRefString);
+ if (jsniRef != null) {
+ if (jsniRef.isMethod()) {
+ checkMethodRef(meth, jsniRef);
+ } else {
+ checkFieldRef(meth, jsniRef);
}
}
}
@@ -135,50 +172,56 @@
return returnType != null && containsLong(returnType.resolveType(scope));
}
+ private JClassType findType(JsniRef jsniRef) {
+ // Use source name.
+ String className = jsniRef.className();
+ className = className.replace('$', '.');
+ JClassType type = typeOracle.findType(className);
+ return type;
+ }
+
/**
* Returns either the type returned if this reference is "read". For a
* field, returns the field's type. For a method, returns the method's
* return type. If the reference cannot be resolved, returns null.
*/
- private JType getType(JsniRef jsniRef) {
- JClassType type = typeOracle.findType(jsniRef.className());
+ private JField getField(JsniRef jsniRef) {
+ assert jsniRef.isField();
+ JClassType type = findType(jsniRef);
if (type == null) {
return null;
}
- if (jsniRef.isMethod()) {
- for (JMethod method : type.getMethods()) {
- if (paramTypesMatch(method, jsniRef)) {
- return method.getReturnType();
- }
- }
- // no method matched
- return null;
- } else {
- JField field = type.getField(jsniRef.memberName());
- if (field != null) {
- return field.getType();
- }
- // field not found
- return null;
+ JField field = type.getField(jsniRef.memberName());
+ if (field != null) {
+ return field;
}
+ return null;
}
- private boolean hasLongParam(JsniRef jsniRef) {
- if (!jsniRef.isMethod()) {
- return false;
+ /**
+ * Returns either the type returned if this reference is "read". For a
+ * field, returns the field's type. For a method, returns the method's
+ * return type. If the reference cannot be resolved, returns null.
+ */
+ private JMethod getMethod(JsniRef jsniRef) {
+ assert jsniRef.isMethod();
+ JClassType type = findType(jsniRef);
+ if (type == null) {
+ return null;
}
- for (String type : jsniRef.paramTypes()) {
- if (type.charAt(type.length() - 1) == JniConstants.DESC_LONG) {
- return true;
+
+ for (JMethod method : type.getMethods()) {
+ if (paramTypesMatch(method, jsniRef)) {
+ return method;
}
}
- return false;
+ return null;
}
private boolean paramTypesMatch(JMethod method, JsniRef jsniRef) {
- JsniRef methodJsni = JsniRef.parse(Jsni.getJsniSignature(method));
- return methodJsni.equals(jsniRef);
+ String methodSig = Jsni.getMemberSignature(method);
+ return methodSig.equals(jsniRef.memberSignature());
}
private boolean suppressingWarnings(MethodDeclaration meth, ClassScope scope) {
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 546409f..e5ba2f5 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
@@ -34,6 +34,7 @@
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
import com.google.gwt.dev.jjs.ast.JContinueStatement;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JDoStatement;
import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
import com.google.gwt.dev.jjs.ast.JEnumField;
@@ -52,7 +53,6 @@
import com.google.gwt.dev.jjs.ast.JLabeledStatement;
import com.google.gwt.dev.jjs.ast.JLiteral;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JLongLiteral;
import com.google.gwt.dev.jjs.ast.JMethod;
@@ -278,7 +278,7 @@
// look for a method
String almostMatches = null;
String methodName = parsed.memberName();
- String jsniSig = methodName + "(" + parsed.paramTypesString() + ")";
+ String jsniSig = parsed.memberSignature();
if (type == null) {
if (jsniSig.equals("nullMethod()")) {
return program.getNullMethod();
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 5475668..ba0102e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -116,7 +116,7 @@
String className = parsed.className();
DispatchClassInfo dispClassInfo = getClassInfoFromClassName(className);
if (dispClassInfo != null) {
- String memberName = parsed.memberName();
+ String memberName = parsed.memberSignature();
int memberId = dispClassInfo.getMemberId(memberName);
if (memberId < 0) {
logger.log(TreeLogger.WARN, "Member '" + memberName
diff --git a/dev/core/src/com/google/gwt/dev/util/Jsni.java b/dev/core/src/com/google/gwt/dev/util/Jsni.java
index d3b33c2..1b8ed8d 100644
--- a/dev/core/src/com/google/gwt/dev/util/Jsni.java
+++ b/dev/core/src/com/google/gwt/dev/util/Jsni.java
@@ -282,12 +282,17 @@
* determine whether one method overrides another).
*/
public static String getJsniSignature(JMethod method) {
- String name = method.getName();
- String className = method.getEnclosingType().getQualifiedSourceName();
+ return method.getEnclosingType().getQualifiedSourceName() + "::"
+ + getMemberSignature(method);
+ }
+ /**
+ * Gets a unique name for this method and its signature (this is used to
+ * determine whether one method overrides another).
+ */
+ public static String getMemberSignature(JMethod method) {
+ String name = method.getName();
StringBuffer sb = new StringBuffer();
- sb.append(className);
- sb.append("::");
sb.append(name);
sb.append("(");
JParameter[] params = method.getParameters();
@@ -297,8 +302,8 @@
sb.append(typeSig);
}
sb.append(")");
- String fullName = sb.toString();
- return fullName;
+ String result = sb.toString();
+ return result;
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/util/JsniRef.java b/dev/core/src/com/google/gwt/dev/util/JsniRef.java
index 68f9a4c..c7b4dae 100644
--- a/dev/core/src/com/google/gwt/dev/util/JsniRef.java
+++ b/dev/core/src/com/google/gwt/dev/util/JsniRef.java
@@ -24,7 +24,7 @@
/**
* A parsed Java reference from within a JSNI method.
*/
-public class JsniRef {
+public final class JsniRef {
/**
* A regex pattern for a Java reference in JSNI code. Its groups are:
@@ -126,10 +126,7 @@
@Override
public boolean equals(Object obj) {
- if (obj instanceof JsniRef) {
- return toString().equals(obj.toString());
- }
- return false;
+ return (obj instanceof JsniRef) && toString().equals(obj.toString());
}
@Override
@@ -137,14 +134,26 @@
return toString().hashCode();
}
- public final boolean isMethod() {
- return paramTypesString() != null;
+ public boolean isField() {
+ return paramTypesString == null;
+ }
+
+ public boolean isMethod() {
+ return paramTypesString != null;
}
public String memberName() {
return memberName;
}
+ public String memberSignature() {
+ String ret = memberName;
+ if (isMethod()) {
+ ret += "(" + paramTypesString + ")";
+ }
+ return ret;
+ }
+
/**
* Return the list of parameter types for the method referred to by this
* reference.
@@ -159,10 +168,6 @@
@Override
public String toString() {
- String ret = "@" + className + "::" + memberName;
- if (isMethod()) {
- ret += "(" + paramTypesString + ")";
- }
- return ret;
+ return "@" + className + "::" + memberSignature();
}
}
diff --git a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java b/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
index faa5885..8e41ad7 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
+++ b/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
@@ -34,8 +34,10 @@
code.append(" $wnd.alert(\"x is: \"+this.@Buggy::x); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 3,
- "Field x has type long, which cannot be processed in JSNI code");
+ shouldGenerateWarning(
+ code,
+ 3,
+ "Referencing field 'Buggy.x': 'long' is an opaque, non-numeric value in JS code");
}
public void testLongArray() throws UnableToCompleteException {
@@ -46,8 +48,10 @@
code.append(" $wnd.alert(this.@Buggy::m()()); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 3,
- "Method m returns type long[], which cannot be processed in JSNI code");
+ shouldGenerateWarning(
+ code,
+ 3,
+ "Referencing method \'Buggy.m\': return type \'long[]\' is an opaque, non-numeric value in JS code");
}
public void testLongParameter() throws UnableToCompleteException {
@@ -56,7 +60,8 @@
code.append(" native void jsniMeth(long x) /*-{ return; }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 2, "JSNI method with a parameter of type long");
+ shouldGenerateWarning(code, 2,
+ "Parameter 'x': 'long' is an opaque, non-numeric value in JS code");
}
public void testLongReturn() throws UnableToCompleteException {
@@ -65,7 +70,8 @@
code.append(" native long jsniMeth() /*-{ return 0; }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 2, "JSNI method with return type of long");
+ shouldGenerateWarning(code, 2,
+ "Return value of type 'long' is an opaque, non-numeric value in JS code");
}
public void testMethodArgument() throws UnableToCompleteException {
@@ -75,8 +81,10 @@
code.append(" native void jsniMeth() /*-{ this.@Buggy::print(J)(0); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 3,
- "Passing a long into Java from JSNI (method print)");
+ shouldGenerateWarning(
+ code,
+ 3,
+ "Referencing method \'Buggy.print\': parameter \'x\': \'long\' is an opaque, non-numeric value in JS code");
}
public void testMethodReturn() throws UnableToCompleteException {
@@ -87,8 +95,10 @@
code.append(" $wnd.alert(this.@Buggy::m()()); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 3,
- "Method m returns type long, which cannot be processed in JSNI code");
+ shouldGenerateWarning(
+ code,
+ 3,
+ "Referencing method 'Buggy.m': return type 'long' is an opaque, non-numeric value in JS code");
}
public void testOverloadedMethodWithNoWarning()
@@ -114,8 +124,10 @@
code.append(" $wnd.alert(this.@Buggy::m(I)(10)); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 4,
- "Method m returns type long, which cannot be processed in JSNI code");
+ shouldGenerateWarning(
+ code,
+ 4,
+ "Referencing method 'Buggy.m': return type 'long' is an opaque, non-numeric value in JS code");
}
public void testSuppressWarnings() throws UnableToCompleteException {
diff --git a/dev/core/test/com/google/gwt/dev/util/JsniRefTest.java b/dev/core/test/com/google/gwt/dev/util/JsniRefTest.java
index 47bc926..5dddc44 100644
--- a/dev/core/test/com/google/gwt/dev/util/JsniRefTest.java
+++ b/dev/core/test/com/google/gwt/dev/util/JsniRefTest.java
@@ -27,14 +27,18 @@
JsniRef ref = JsniRef.parse("@some.package.SomeClass::someField");
assertEquals("some.package.SomeClass", ref.className());
assertEquals("someField", ref.memberName());
+ assertEquals("someField", ref.memberSignature());
assertFalse(ref.isMethod());
+ assertTrue(ref.isField());
}
{
JsniRef ref = JsniRef.parse("@some.package.SomeClass::someMeth()");
assertEquals("some.package.SomeClass", ref.className());
assertEquals("someMeth", ref.memberName());
+ assertEquals("someMeth()", ref.memberSignature());
assertTrue(ref.isMethod());
+ assertFalse(ref.isField());
assertEquals(0, ref.paramTypes().length);
}
@@ -44,6 +48,8 @@
+ "[[ZBCDFIJLjava/lang/String;S)");
assertEquals("some.package.SomeClass", ref.className());
assertEquals("someMeth", ref.memberName());
+ assertEquals("someMeth([[ZBCDFIJLjava/lang/String;S)",
+ ref.memberSignature());
assertTrue(ref.isMethod());
assertEquals(9, ref.paramTypes().length);
assertEquals("[[Z", ref.paramTypes()[0]);
@@ -62,7 +68,9 @@
JsniRef ref = JsniRef.parse("some.package.SomeClass::someField");
assertEquals("some.package.SomeClass", ref.className());
assertEquals("someField", ref.memberName());
+ assertEquals("someField", ref.memberSignature());
assertFalse(ref.isMethod());
+ assertTrue(ref.isField());
}
}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
index 65a842d..3a12ab4 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -242,6 +242,7 @@
}
private void writeCreateMethodMapMethod() {
+ srcWriter.println("@SuppressWarnings(\"restriction\")");
srcWriter.println("private static native JavaScriptObject createMethodMap() /*-" + '{');
{
srcWriter.indent();