Cleanup of JsniChecker per spoon suggestions.
Suggested by: spoon
Review by: spoon (TBR)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4782 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
index fdd0bc7..4584aa6 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
@@ -36,7 +36,6 @@
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
-import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
@@ -140,27 +139,28 @@
for (String jsniRefString : sloppyRefsVisitor.getJsniRefs()) {
JsniRef jsniRef = JsniRef.parse(jsniRefString);
if (jsniRef != null) {
- Set<String> refErrors = new LinkedHashSet<String>();
ReferenceBinding clazz = findClass(jsniRef);
- if (clazz != null) {
- if (clazz.isAnonymousType()) {
- GWTProblem.recordInCud(
- ProblemSeverities.Warning,
- meth,
- cud,
- "Referencing class '" + jsniRef.className()
- + ": JSNI references to anonymous classes are deprecated",
- null);
+ if (looksLikeAnonymousClass(jsniRef)
+ || (clazz != null && clazz.isAnonymousType())) {
+ GWTProblem.recordInCud(ProblemSeverities.Warning, meth, cud,
+ "Referencing class '" + jsniRef.className()
+ + ": JSNI references to anonymous classes are deprecated",
+ null);
+ } else if (clazz != null) {
+ Set<String> refErrors = new LinkedHashSet<String>();
+ if (jsniRef.isMethod()) {
+ checkMethodRef(clazz, jsniRef, refErrors);
} else {
- if (jsniRef.isMethod()) {
- checkMethodRef(clazz, jsniRef, refErrors);
- } else {
- checkFieldRef(clazz, jsniRef, refErrors);
- }
- if (!refErrors.isEmpty()) {
- errors.put(jsniRefString, refErrors);
- }
+ checkFieldRef(clazz, jsniRef, refErrors);
}
+ if (!refErrors.isEmpty()) {
+ errors.put(jsniRefString, refErrors);
+ }
+ } else {
+ GWTProblem.recordInCud(ProblemSeverities.Warning, meth, cud,
+ "Referencing class '" + jsniRef.className()
+ + ": unable to resolve class, expect subsequent failures",
+ null);
}
}
}
@@ -200,16 +200,14 @@
}
private ReferenceBinding findClass(JsniRef jsniRef) {
- String className = jsniRef.className().replace('$', '.');
- char[][] compoundName = CharOperation.splitOn('.',
- className.toCharArray());
+ char[][] compoundName = getCompoundName(jsniRef);
TypeBinding binding = cud.scope.getType(compoundName, compoundName.length);
if (binding instanceof ProblemReferenceBinding) {
ProblemReferenceBinding prb = (ProblemReferenceBinding) binding;
if (prb.problemId() == ProblemReasons.NotVisible) {
// It's just a visibility problem, so try drilling down manually
- ReferenceBinding drilling = prb.closestReferenceMatch();
+ ReferenceBinding drilling = prb.closestReferenceMatch();
for (int i = prb.compoundName.length; i < compoundName.length; i++) {
drilling = drilling.getMemberType(compoundName[i]);
}
@@ -221,19 +219,16 @@
&& !(binding instanceof ProblemReferenceBinding)) {
return (ReferenceBinding) binding;
}
- // See if it looks like an anonymous inner class, we can't look those up.
- for (char[] part : compoundName) {
- if (Character.isDigit(part[0])) {
- return new ReferenceBinding() {
- {
- tagBits = TagBits.IsAnonymousType;
- }
- };
- }
- }
return null;
}
+ private char[][] getCompoundName(JsniRef jsniRef) {
+ String className = jsniRef.className().replace('$', '.');
+ char[][] compoundName = CharOperation.splitOn('.',
+ className.toCharArray());
+ return compoundName;
+ }
+
private FieldBinding getField(ReferenceBinding clazz, JsniRef jsniRef) {
assert jsniRef.isField();
return clazz.getField(jsniRef.memberName().toCharArray(), false);
@@ -282,6 +277,16 @@
"longJsniRestriction.html"));
}
+ private boolean looksLikeAnonymousClass(JsniRef jsniRef) {
+ char[][] compoundName = getCompoundName(jsniRef);
+ for (char[] part : compoundName) {
+ if (Character.isDigit(part[0])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean paramTypesMatch(MethodBinding method, JsniRef jsniRef) {
StringBuilder methodSig = new StringBuilder();
if (method.parameters != null) {
diff --git a/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java b/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
index 5ebe56e..5a3e358 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
@@ -50,6 +50,28 @@
+ "JSNI references to anonymous classes are deprecated");
}
+ /**
+ * JSNI references to anonymous inner classes is deprecated.
+ */
+ public void testAnoymousJsniRefNested() {
+ StringBuffer code = new StringBuffer();
+ code.append("class Buggy {\n");
+ code.append(" static void main() {\n");
+ code.append(" new Object() {\n");
+ code.append(" class A {\n");
+ code.append(" int foo = 3;\n");
+ code.append(" };\n");
+ code.append(" };\n");
+ code.append(" }\n");
+ code.append(" native void jsniMeth(Object o) /*-{\n");
+ code.append(" o.@Buggy$1.A::foo;\n");
+ code.append(" }-*/;\n");
+ code.append("}\n");
+
+ shouldGenerateWarning(code, 9, "Referencing class \'Buggy$1.A: "
+ + "JSNI references to anonymous classes are deprecated");
+ }
+
public void testCyclicReferences() {
{
StringBuffer buggy = new StringBuffer();
@@ -123,6 +145,21 @@
+ "type 'long' is not safe to access in JSNI code");
}
+ public void testInnerClassDollar() {
+ StringBuffer code = new StringBuffer();
+ code.append("public class Buggy {\n");
+ code.append(" static class Inner {\n");
+ code.append(" long x = 3;\n");
+ code.append(" }\n");
+ code.append(" native void jsniMeth() /*-{\n");
+ code.append(" $wnd.alert(@Buggy$Inner::x);\n");
+ code.append(" }-*/;\n");
+ code.append("}\n");
+
+ shouldGenerateError(code, 5, "Referencing field 'Buggy$Inner.x': "
+ + "type 'long' is not safe to access in JSNI code");
+ }
+
/**
* The proper behavior here is a close call. In hosted mode, Java arrays are
* completely unusable in JavaScript, so the current reasoning is to allow