Revision: 7034 Author: [email protected] Date: Thu Nov 19 13:48:22 2009 Log: JsniChecker should support the "::new" syntax.
Review by: bobv http://code.google.com/p/google-web-toolkit/source/detail?r=7034 Modified: /trunk/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java /trunk/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java Thu Nov 19 13:48:07 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java Thu Nov 19 13:48:22 2009 @@ -45,8 +45,10 @@ import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding; @@ -307,9 +309,37 @@ private MethodBinding getMethod(ReferenceBinding clazz, JsniRef jsniRef) { assert jsniRef.isMethod(); - for (MethodBinding findMethod : clazz.getMethods(jsniRef.memberName().toCharArray())) { - if (paramTypesMatch(findMethod, jsniRef)) { - return findMethod; + String methodName = jsniRef.memberName(); + if ("new".equals(methodName)) { + for (MethodBinding findMethod : clazz.getMethods(INIT_CTOR_CHARS)) { + StringBuilder methodSig = new StringBuilder(); + if (clazz instanceof NestedTypeBinding) { + // Match synthetic args for enclosing instances. + NestedTypeBinding nestedBinding = (NestedTypeBinding) clazz; + if (nestedBinding.enclosingInstances != null) { + for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { + SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; + methodSig.append(arg.type.signature()); + } + } + } + if (findMethod.parameters != null) { + for (TypeBinding binding : findMethod.parameters) { + methodSig.append(binding.signature()); + } + } + if (methodSig.toString().equals(jsniRef.paramTypesString())) { + return findMethod; + } + } + } else { + while (clazz != null) { + for (MethodBinding findMethod : clazz.getMethods(methodName.toCharArray())) { + if (paramTypesMatch(findMethod, jsniRef)) { + return findMethod; + } + } + clazz = clazz.superclass(); } } return null; @@ -373,6 +403,8 @@ return String.valueOf(type.shortReadableName()); } } + + private static final char[] INIT_CTOR_CHARS = "<init>".toCharArray(); private static final char[][] UNSAFE_LONG_ANNOTATION_CHARS = CharOperation.splitOn( '.', UnsafeNativeLong.class.getName().toCharArray()); ======================================= --- /trunk/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java Thu Nov 19 13:48:07 2009 +++ /trunk/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java Thu Nov 19 13:48:22 2009 @@ -235,6 +235,47 @@ shouldGenerateError(code, 6, "Referencing field 'Buggy$Inner.x': " + "type 'long' is not safe to access in JSNI code"); } + + public void testInnerNew() { + StringBuffer code = new StringBuffer(); + code.append("public class Buggy {\n"); + code.append(" class Inner {\n"); + code.append(" long x = 3;\n"); + code.append(" Inner(boolean b) { };\n"); + code.append(" }\n"); + code.append(" native void jsniMeth() /*-{\n"); + code.append(" $wnd.alert(@Buggy.Inner::new(Z)(true).toString());\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + + // Cannot resolve, missing synthetic enclosing instance. + shouldGenerateWarning(code, 7, "Referencing method 'Buggy.Inner.new(Z)': " + + "unable to resolve method, expect subsequent failures"); + + code = new StringBuffer(); + code.append("public class Buggy {\n"); + code.append(" static class Inner {\n"); + code.append(" long x = 3;\n"); + code.append(" Inner(boolean b) { };\n"); + code.append(" }\n"); + code.append(" native void jsniMeth() /*-{\n"); + code.append(" $wnd.alert(@Buggy.Inner::new(Z)(this, true).toString());\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + + code = new StringBuffer(); + code.append("public class Buggy {\n"); + code.append(" class Inner {\n"); + code.append(" long x = 3;\n"); + code.append(" Inner(boolean b) { };\n"); + code.append(" }\n"); + code.append(" native void jsniMeth() /*-{\n"); + code.append(" $wnd.alert(@Buggy.Inner::new(LBuggy;Z)(this, true).toString());\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + } /** * The proper behavior here is a close call. In hosted mode, Java arrays are @@ -308,6 +349,25 @@ 4, "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code"); } + + public void testNew() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" static native Object main() /*-{\n"); + code.append(" return @Buggy::new()();\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + + code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" Buggy(boolean b) { }\n"); + code.append(" static native Object main() /*-{\n"); + code.append(" return @Buggy::new(Z)(true);\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + } public void testNullField() { StringBuffer code = new StringBuffer(); -- http://groups.google.com/group/Google-Web-Toolkit-Contributors
