/* * Copyright 2008 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.javac.testing.impl.JavaResourceBase; import com.google.gwt.dev.javac.testing.impl.MockJavaResource; /** * Test access to longs from JSNI. */ public class JsniReferenceResolverTest extends CheckerTestCase { /** * JSNI references to anonymous inner classes is deprecated. */ public void testAnoymousJsniRef() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static void main() {", " new Object() {", " int foo = 3;", " };", " }", " native void jsniMeth(Object o) /*-{", " o.@Buggy$1::foo;", " }-*/;", "}"); shouldGenerateError(buggy, 8, "Referencing class 'Buggy$1': " + "unable to resolve class"); } /** * JSNI references to anonymous inner classes is deprecated. */ public void testAnoymousJsniRefNested() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static void main() {", " new Object() {", " class A {", " int foo = 3;", " };", " };", " }", " native void jsniMeth(Object o) /*-{", " o.@Buggy$1.A::foo;", " }-*/;", "}"); shouldGenerateError(buggy, 10, "Referencing class 'Buggy$1.A': " + "unable to resolve class"); } public void testArrayBadMember() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy[][]::blah;", " }-*/;", "}"); shouldGenerateError( buggy, 3, "Referencing member 'Buggy[][].blah': 'class' is the only legal reference for arrays and " + "primitive types"); } public void testArrayClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy[][]::class;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy::class;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testClassAssignment() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy::class = null;", " }-*/;", "}"); shouldGenerateError(buggy, 3, "Illegal assignment to class literal 'Buggy.class'"); } public void testCyclicReferences() { { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static int anint = 3;", " native void jsniMeth() /*-{", " $wnd.alert(@Extra::along);", " }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Extra", "class Extra {", " static long along = 3;", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy::anint);", " }-*/;", "}"); shouldGenerateError(buggy, extra, 4, "Referencing field 'Extra.along': " + "type 'long' is not safe to access in JSNI code"); } { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " Extra anExtra = new Extra();", " static int anint = 3;", " native void jsniMeth() /*-{", " $wnd.alert(@Extra::along);", " }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Extra", "class Extra {", " Buggy mattress = new Buggy();", " static long along = 3;", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy::anint);", " }-*/;", "}"); shouldGenerateError(buggy, extra, 5, "Referencing field 'Extra.along': " + "type 'long' is not safe to access in JSNI code"); } } public void testDeprecationField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " @Deprecated static int bar;", "}", "class Other {", " native void jsniMethod() /*-{", " @Buggy::bar;", " }-*/;", "}"); shouldGenerateWarning(buggy, 6, "Referencing field 'Buggy.bar': field 'Buggy.bar' is deprecated"); } public void testDeprecationField_inEnclosingClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " @Deprecated static int bar;", " static class Inner {", " static class InnerInner {", " native void jsniMethod() /*-{", " @Buggy::bar;", " }-*/;", " }", " }", "}"); shouldGenerateNoWarning(buggy); } public void testDeprecationField_deprecatedbyClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated", "class Buggy {", " static int bar;", " native void jsniMethod() /*-{", " @Buggy::bar;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testDeprecationField_deprecatedbyClass_fromOtherClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated", "class DeprecatedClass {", " @Deprecated static int bar;", "}", "class Buggy {", " native void jsniMethod() /*-{", " @DeprecatedClass::bar;", " }-*/;", "}"); shouldGenerateWarnings(buggy, warning(7,"Referencing deprecated class 'DeprecatedClass'"), warning(7, "Referencing field 'DeprecatedClass.bar': field 'DeprecatedClass.bar' is deprecated")); } public void testDeprecationMethod() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " @Deprecated static void foo(){}", "}", "class Other {", " native void jsniMethod() /*-{", " @Buggy::foo();", " }-*/;", "}"); shouldGenerateWarning(buggy, 6, "Referencing method 'Buggy.foo': method 'Buggy.foo()' is deprecated"); } public void testDeprecationMethod_deprecatedbyClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated", "class Buggy {", " static void foo(){}", " native void jsniMethod() /*-{", " @Buggy::foo();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testDeprecationMethod_deprecatedbyClass_fromOtherClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated", "class DeprecatedClass {", " @Deprecated static void foo(){}", "}", "class Buggy {", " native void jsniMethod() /*-{", " @DeprecatedClass::foo();", " }-*/;", "}"); shouldGenerateWarnings(buggy, warning(7,"Referencing deprecated class 'DeprecatedClass'"), warning(7,"Referencing method 'DeprecatedClass.foo': " + "method 'DeprecatedClass.foo()' is deprecated")); } public void testDeprecationSuppression() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated class D {", " static int bar;", "}", "class Buggy {", " @Deprecated static void foo(){}", " @Deprecated static int bar;", " @SuppressWarnings(\"deprecation\")", " native void jsniMethod1() /*-{", " @Buggy::foo();", " @Buggy::bar;", " @D::bar;", " }-*/;", " @SuppressWarnings({\"deprecation\", \"other\"})", " native void jsniMethod2() /*-{", " @Buggy::foo();", " @Buggy::bar;", " @D::bar;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); // Check inherited suppress warnings. buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated class D {", " static int bar;", "}", "@SuppressWarnings(\"deprecation\")", "class Buggy {", " @Deprecated static void foo(){}", " @Deprecated static int bar;", " native void jsniMethod1() /*-{", " @Buggy::foo();", " @Buggy::bar;", " @D::bar;", " }-*/;", " native void jsniMethod2() /*-{", " @Buggy::foo();", " @Buggy::bar;", " @D::bar;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } /** * Test for issue 8093. */ public void testSuppressionNotStrintLiteral1() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " private static final String RAWTYPES = \"rawtypes\";", " @SuppressWarnings(RAWTYPES)", " public void method1() {", " }", "}"); shouldGenerateNoWarning(buggy); } /** * Test for issue 8093. */ public void testSuppressionNotStringLiteral2() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " private static final String UNCHECKED = \"unchecked\";", " @SuppressWarnings({\"rawtypes\", UNCHECKED})", " public void method1() {", " }", "}"); shouldGenerateNoWarning(buggy); } public void testDeprecationType() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "@Deprecated class D {", " static int bar;", "}", "class Buggy {", " native void jsniMethod() /*-{", " @D::bar;", " }-*/;", "}"); shouldGenerateWarning(buggy, 6, "Referencing deprecated class 'D'"); } public void testField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " int foo = 3;", " native void jsniMethod() /*-{", " this.@Buggy::foo;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testFieldAccess() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", "volatile long x = -1;", "native void jsniMeth() /*-{", " $wnd.alert(\"x is: \"+this.@Buggy::x); }-*/;", "}"); shouldGenerateError(buggy, 4, "Referencing field 'Buggy.x': type 'long' is not safe to access in JSNI code"); } public void testFieldAssignment() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " int foo = 3;", " native void jsniMethod() /*-{", " this.@Buggy::foo = 4;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testFieldAssignmentStatic() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static int foo = 3;", " native void jsniMethod() /*-{", " @Buggy::foo = 4;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testFieldConstant() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static final int foo = 3;", " native void jsniMethod() /*-{", " @Buggy::foo;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testFieldConstantAssignment() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static final int foo = 3;", " native void jsniMethod() /*-{", " @Buggy::foo = 4;", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Illegal assignment to compile-time constant 'Buggy.foo'"); buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static final String foo = \"asdf\";", " native void jsniMethod() /*-{", " @Buggy::foo = null;", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Illegal assignment to compile-time constant 'Buggy.foo'"); // Not a compile-time constant. buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static final Object foo = new Object();", " native void jsniMethod() /*-{", " @Buggy::foo = null;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testAssignment_InstanceMethod_toField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Some", "public class Some {", " public void callback() {", " }", " native void installCallback(Some o) /*-{", " $wnd.someCallback = o.@Some::callback();", " }-*/;", "}"); shouldGenerateWarning(buggy, 5, "Instance method reference 'Some.callback' loses its instance ('o') when assigned; " + "to remove this warning either assign to a local variable or construct " + "the proper closure using an anonymous function or by calling " + "Function.prototype.bind"); } public void testAssignment_InstanceMethod_toVariable() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Some", "public class Some {", " public void callback() {", " }", " native void installCallback(Some o) /*-{", " var a = o.@Some::callback();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testJsoStaticMethod() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMeth(Object o) /*-{", " @com.google.gwt.core.client.JavaScriptObject::createObject()();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testAllowsJsoSubclassStaticMethod() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static final class Foo extends com.google.gwt.core.client.JavaScriptObject {", " protected Foo() { };", " static void foo() { };", " }", " native void jsniMeth(Object o) /*-{", " @Buggy.Foo::foo()();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testFieldStatic() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static int foo = 3;", " native void jsniMethod() /*-{", " @Buggy::foo;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testFieldStaticQualified() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static int foo = 3;", " native void jsniMethod() /*-{", " this.@Buggy::foo;", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Unnecessary qualifier on static field 'Buggy.foo'"); } public void testFieldUnqualified() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " int foo = 3;", " native void jsniMethod() /*-{", " @Buggy::foo;", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Missing qualifier on instance field 'Buggy.foo'"); } public void testEnclosingClassField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " int foo = 3;", " native void jsniMethod() /*-{", " this.@Buggy::foo;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testEnclosingClassFieldNotFound() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " int foo = 3;", " native void jsniMethod() /*-{", " this.@Buggy::bar;", " }-*/;", "}"); shouldGenerateError(buggy, 5, "Referencing field 'Buggy.bar': unable to resolve field in class 'some.Buggy'"); } public void testImportedClassField_PartialMatch() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.pack.OtherPackageClass;", "class Buggy {", " native void jsniMethod() /*-{", " this.@PackageClass::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("other.pack.OtherPackageClass", "package other.pack;", "public class OtherPackageClass {", " public int f;", "}"); shouldGenerateError( buggy, otherPackageClass, 5, "Referencing class 'PackageClass': unable to resolve class"); } public void testImportedClassField_Precedence() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.pack.B;", "class Buggy {", " class B {", " int f;", " }", " native void jsniMethod() /*-{", " this.@B::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("other.pack.B", "package other.pack;", "public class B {", "}"); shouldGenerateNoError(buggy, otherPackageClass); } public void testImportedClassField_InnerClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.pack.OtherPackageClass.Inner;", "class Buggy {", " native void jsniMethod() /*-{", " this.@Inner::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("other.pack.OtherPackageClass", "package other.pack;", "public class OtherPackageClass {", " public class Inner {", " public int f;", " }", "}"); shouldGenerateNoWarning(buggy, otherPackageClass); } public void testImportedClassField_InnerClassThroughOuter() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.pack.OtherPackageClass;", "class Buggy {", " native void jsniMethod() /*-{", " this.@OtherPackageClass.Inner::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("other.pack.OtherPackageClass", "package other.pack;", "public class OtherPackageClass {", " public class Inner {", " public int f;", " }", "}"); shouldGenerateNoWarning(buggy, otherPackageClass); } public void testImportedClassField_InnerClassTest1() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " public class Inner {", " public int f;", " }", " native void jsniMethod() /*-{", " this.@Inner::f;", " this.@Buggy.Inner::f;", " this.@some.Buggy.Inner::f;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testImportedClassField_InnerClassTest2() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " public class Inner {", " public int f;", " native void jsniMethod() /*-{", " this.@Inner::f;", " this.@Buggy.Inner::f;", " this.@some.Buggy.Inner::f;", " }-*/;", " }", "}"); shouldGenerateNoWarning(buggy); } public void testImportedClassField_InnerClassTest3() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " public class OtherInner {", " native void jsniMethod() /*-{", " this.@Inner::f;", " this.@Buggy.Inner::f;", " this.@some.Buggy.Inner::f;", " }-*/;", " }", " public class Inner {", " public int f;", " }", "}"); shouldGenerateNoWarning(buggy); } public void testImportedClassField_InnerClassTest4() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " public class OtherInner {", " public class Inner {", " public int f;", " }", " native void jsniMethod() /*-{", " this.@OtherInner.Inner::f;", " this.@Buggy.OtherInner.Inner::f;", " this.@some.Buggy.OtherInner.Inner::f;", " }-*/;", " }", "}"); shouldGenerateNoWarning(buggy); } public void testImportedClassField_InnerClassTest5() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " public class OtherInner {", " public class Inner {", " public int f;", " }", " native void jsniMethod() /*-{", " this.@Inner::f;", " }-*/;", " }", "}"); shouldGenerateNoWarning(buggy); } public void testImplicitImport() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " native void jsniMethod(String s) /*-{", " s.@String::length()();", " }-*/;", "}"); shouldGenerateNoError(buggy); } public void testImportedClassField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.pack.OtherPackageClass;", "class Buggy {", " native void jsniMethod() /*-{", " this.@OtherPackageClass::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("other.pack.OtherPackageClass", "package other.pack;", "public class OtherPackageClass {", " public int f;", "}"); shouldGenerateNoWarning(buggy, otherPackageClass); } public void testImportedClassField_CurrentPackage() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "class Buggy {", " native void jsniMethod() /*-{", " this.@SamePackageClass::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("some.SamePackageClass", "package some;", "public class SamePackageClass {", " public int f;", "}"); shouldGenerateNoWarning(buggy, otherPackageClass); } public void testImportedStarClassField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.pack.*;", "class Buggy {", " native void jsniMethod() /*-{", " this.@OtherPackageClass::f;", " }-*/;", "}"); MockJavaResource otherPackageClass = JavaResourceBase.createMockJavaResource("other.pack.OtherPackageClass", "package other.pack;", "public class OtherPackageClass {", " public int f;", "}"); shouldGenerateNoWarning(buggy, otherPackageClass); } public void testInnerClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " static class Inner {", " static long x = 3;", " }", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy.Inner::x);", " }-*/;", "}"); shouldGenerateError(buggy, 6, "Referencing field 'Buggy.Inner.x': " + "type 'long' is not safe to access in JSNI code"); } public void testInnerClassDollar() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " static class Inner {", " static long x = 3;", " }", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy$Inner::x);", " }-*/;", "}"); shouldGenerateError(buggy, 6, "Referencing field 'Buggy$Inner.x': " + "type 'long' is not safe to access in JSNI code"); } public void testInnerNew() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " class Inner {", " long x = 3;", " Inner(boolean b) { };", " }", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy.Inner::new(Z)(true).toString());", " }-*/;", "}"); // Cannot resolve, missing synthetic enclosing instance. shouldGenerateError(buggy, 7, "Referencing method 'Buggy.Inner.new(Z)': " + "unable to resolve method in class 'Buggy.Inner'"); buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " static class Inner {", " long x = 3;", " Inner(boolean b) { };", " }", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy.Inner::new(Z)(this, true).toString());", " }-*/;", "}"); shouldGenerateNoWarning(buggy); buggy = JavaResourceBase.createMockJavaResource("Buggy", "public class Buggy {", " class Inner {", " long x = 3;", " Inner(boolean b) { };", " }", " native void jsniMeth() /*-{", " $wnd.alert(@Buggy.Inner::new(LBuggy;Z)(this, true).toString());", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } /** * The proper behavior here is a close call. In Development Mode, Java arrays * are completely unusable in JavaScript, so the current reasoning is to allow * them. */ public void testLongArray() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " long[] m() { return new long[] { -1 }; }", " native void jsniMeth() /*-{", " $wnd.alert(this.@Buggy::m()()); }-*/;", "}"); shouldGenerateNoError(buggy); } public void testLongParameter() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMeth(long x) /*-{ return; }-*/;", "}"); shouldGenerateError(buggy, 2, "Parameter 'x': type 'long' is not safe to access in JSNI code"); } public void testLongReturn() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native long jsniMeth() /*-{ return 0; }-*/;", "}"); shouldGenerateError(buggy, 2, "Type 'long' may not be returned from a JSNI method"); } public void testMalformedJsniRef() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy;", " }-*/;", "}"); shouldGenerateError(buggy, 3, "Expected \":\" in JSNI reference\n> @Buggy;\n" + "> ----------^"); } public void testMethod() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " void foo() { }", " native void jsniMethod() /*-{", " this.@Buggy::foo()();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testMethodArgument() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " void print(long x) { }", " native void jsniMeth() /*-{ this.@Buggy::print(J)(0); }-*/;", "}"); shouldGenerateError( buggy, 3, "Parameter 1 of method 'Buggy.print': type 'long' may not be passed out of JSNI code"); } public void testMethodAssignment() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " void foo() { }", " native void jsniMethod() /*-{", " this.@Buggy::foo() = null;", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Illegal assignment to method 'Buggy.foo'"); } /** * Test JSNI references to methods defined in superclass/superinterfaces. */ public void testMethodInheritance() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " interface A1 { void a1(); }", " interface A2 extends A1 { void a2(); }", " static abstract class C1 implements A2 { public abstract void c1(); }", " native void jsniMeth(Object o) /*-{", " o.@Buggy.A1::a1()();", " o.@Buggy.A2::a1()();", " o.@Buggy.A2::a2()();", " o.@Buggy.C1::a1()();", " o.@Buggy.C1::a2()();", " o.@Buggy.C1::c1()();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testMethodReturn() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " long m() { return -1; }", " native void jsniMeth() /*-{", " $wnd.alert(this.@Buggy::m()()); }-*/;", "}"); shouldGenerateError( buggy, 4, "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code"); } public void testMethodStatic() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static void foo() { }", " native void jsniMethod() /*-{", " @Buggy::foo()();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testMethodStaticQualified() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static void foo() { }", " native void jsniMethod() /*-{", " this.@Buggy::foo()();", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Unnecessary qualifier on static method 'Buggy.foo'"); } public void testMethodUnqualified() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " void foo() { }", " native void jsniMethod() /*-{", " @Buggy::foo()();", " }-*/;", "}"); shouldGenerateError(buggy, 4, "Missing qualifier on instance method 'Buggy.foo'"); } public void testNew() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static native Object main() /*-{", " return @Buggy::new()();", " }-*/;", "}"); shouldGenerateNoWarning(buggy); buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " Buggy(boolean b) { }", " static native Object main() /*-{", " return @Buggy::new(Z)(true);", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testOldStyleNullField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static native Object main() /*-{", " return @null::nullField;", " }-*/;", "}"); shouldGenerateError( buggy, 3, "Referencing class 'null': unable to resolve class"); buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static native Object main() /*-{", " return @null::foo;", " }-*/;", "}"); shouldGenerateError( buggy, 3, "Referencing class 'null': unable to resolve class"); } public void testOldStyleNullMethod() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static native Object main() /*-{", " return @null::nullMethod()();", " }-*/;", "}"); shouldGenerateError( buggy, 3, "Referencing class 'null': unable to resolve class"); buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " static native Object main() /*-{", " return @null::foo()();", " }-*/;", "}"); shouldGenerateError( buggy, 3, "Referencing class 'null': unable to resolve class"); } public void testOverloadedMethodWithNoWarning() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " long m(int x) { return -1; }", " int m(String x) { return -1; }", " native void jsniMeth() /*-{", " $wnd.alert(this.@Buggy::m(Ljava/lang/String;)(\"hello\")); }-*/;", "}"); shouldGenerateNoError(buggy); } public void testOverloadedMethodWithWarning() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " long m(int x) { return -1; }", " int m(String x) { return -1; }", " native void jsniMeth() /*-{", " $wnd.alert(this.@Buggy::m(I)(10)); }-*/;", "}"); shouldGenerateError( buggy, 5, "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code"); } public void testPrimitiveBadMember() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @boolean::blah;", " }-*/;", "}"); shouldGenerateError( buggy, 3, "Referencing member 'boolean.blah': " + "'class' is the only legal reference for arrays and primitive types"); } public void testPrimitiveClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @boolean::class;", " }-*/;", "}"); shouldGenerateNoWarning(buggy); } public void testPrimitiveClassRemovedDeprecated() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Z::class;", " }-*/;", "}"); shouldGenerateError(buggy, 3, "Referencing class 'Z': unable to resolve class"); } public void testRefInString() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "import com.google.gwt.core.client.UnsafeNativeLong;", "class Buggy {", " void print(long x) { }", " native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;", "}"); shouldGenerateNoError(buggy); } public void testAmbiguityResolution_NestedClasses() { { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.A", "package some;", "class A {", " static Object f;", " static class B {", " static Object f;", " native void jsniMethod() /*-{", " @CC::f;", " }-*/;", " static class CC {", " static Object f;", " }", " }", " static class B1 {", " static Object f;", " static class CC {", " }", " }", "}"); shouldGenerateNoWarning(buggy); } { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.A", "package some;", "class A {", " static Object f;", " static class B {", " static Object f;", " native void jsniMethod() /*-{", " @CC::f;", " }-*/;", " static class CC {", " }", " }", " static class B1 {", " static Object f;", " static class CC {", " static Object f;", " }", " }", "}"); // Note that the ambiguous CC is resolved to some.A.B.CC and not to A.B1.CC. shouldGenerateError(buggy, 7 , "Referencing field 'CC.f': unable to resolve field in class 'some.A.B.CC'"); } } public void testSuperFieldAccess() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " native void jsniMeth() /*-{", " this.@Buggy::x; ", " }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " public long x = -1;", "}"); shouldGenerateError(buggy, extra, 3, "Referencing field 'Buggy.x': unable to resolve field in class 'Buggy'"); } public void testUnresolvedClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Foo::x;", " }-*/;", "}"); shouldGenerateError(buggy, 3, "Referencing class 'Foo': unable to resolve class"); } public void testUnresolvedField() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy::x;", " }-*/;", "}"); shouldGenerateError(buggy, 3, "Referencing field 'Buggy.x': unable to resolve field in class 'Buggy'"); } public void testUnresolvedMethod() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMethod() /*-{", " @Buggy::x(Ljava/lang/String);", " }-*/;", "}"); shouldGenerateError(buggy, 3, "Referencing method 'Buggy.x(Ljava/lang/String)': " + "unable to resolve method in class 'Buggy'"); } public void testUnsafeAnnotation() { { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "import com.google.gwt.core.client.UnsafeNativeLong;", "class Buggy {", " void print(long x) { }", " @UnsafeNativeLong", " native void jsniMeth() /*-{ this.@Buggy::print(J)(0); }-*/;", "}"); shouldGenerateNoError(buggy); } } public void testViolator() { { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMeth() /*-{", " $wnd.alert(@Extra.Inner::x);", " }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Extra", "class Extra {", " private static class Inner { ", " private static int x = 3;", " }", "}"); shouldGenerateNoError(buggy, extra); } { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " native void jsniMeth() /*-{", " $wnd.alert(@Extra.Inner::x);", " }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Extra", "class Extra {", " private static class Inner { ", " private static long x = 3;", " }", "}"); shouldGenerateError( buggy, extra, 3, "Referencing field 'Extra.Inner.x': type 'long' is not safe to access in JSNI code"); } } public void testWildcardMethodAccess() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " int m(String x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); shouldGenerateNoError(buggy); } public void testWilcardMethodAccess_Ambiguous_withinClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy {", " int m(String x) { return -1; }", " int m(Integer x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); shouldGenerateError( buggy, 5, "Referencing method 'Buggy.m(*)': ambiguous wildcard match; " + "both 'Buggy.m(Ljava/lang/String;)' and " + "'Buggy.m(Ljava/lang/Integer;)' match"); } public void testWildcardMethodAccess_Ambiguous_withSuperClass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Extra{", " public int m(String x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Extra", "class Extra {", " public int m(Integer x) { return -1; }", "}"); shouldGenerateError( buggy, extra, 4, "Referencing method 'Buggy.m(*)': ambiguous wildcard match; " + "both 'public Buggy.m(Ljava/lang/String;)' and " + "'public Extra.m(Ljava/lang/Integer;)' match"); } public void testWildcardMethodAccess_NoConflict_OverrideFromSuperclass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Extra {", " public int m(String x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Extra", "class Extra {", " public int m(String x) { return -1; }", "}"); shouldGenerateNoError(buggy, extra); } public void testWildcardMethodAccess_Conflict_WithSuperclass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " protected int m(String x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " public int m(Object x) { return -1; }", "}"); shouldGenerateError(buggy, extra, 4, "Referencing method 'Buggy.m(*)': ambiguous wildcard match; " + "both 'protected Buggy.m(Ljava/lang/String;)' and " + "'public Super.m(Ljava/lang/Object;)' match"); } public void testWildcardMethodAccess_Conflict_PrivateWithSuperclass() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " private int m(String x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " public int m(Object x) { return -1; }", "}"); shouldGenerateError(buggy, extra, 4, "Referencing method 'Buggy.m(*)': ambiguous wildcard match; " + "both 'private Buggy.m(Ljava/lang/String;)' and " + "'public Super.m(Ljava/lang/Object;)' match"); } public void testWildcardSuperclassMethod_PackagePrivate_DifferentPackage() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.Super;", "class Buggy extends Super {", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("other.Super", "package other;", "public class Super {", " int m(Object x) { return -1; }", "}"); shouldGenerateError(buggy, extra, 5, "Referencing method 'Buggy.m(*)': unable to resolve method in class 'some.Buggy'"); } public void testWildcardSuperclassMethod_PackagePrivate_SamePackage() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " int m(Object x) { return -1; }", "}"); shouldGenerateNoError(buggy, extra); } public void testWildcardSuperclassMethod_Private() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " private int m(Object x) { return -1; }", "}"); shouldGenerateError(buggy, extra, 3, "Referencing method 'Buggy.m(*)': unable to resolve method in class 'Buggy'"); } public void testWildcardSuperclassMethod_Protected() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("some.Buggy", "package some;", "import other.Super;", "class Buggy extends Super {", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("other.Super", "package other;", "public class Super {", " protected int m(Object x) { return -1; }", "}"); shouldGenerateNoError(buggy, extra); } public void testWildcardSuperclassMethod_Public() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " public int m(Object x) { return -1; }", "}"); shouldGenerateNoError(buggy, extra); } public void testWildcardMethodAccess_PotentialConflict() { MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy", "class Buggy extends Super {", " int m(String x) { return -1; }", " native void jsniMeth() /*-{", " this.@Buggy::m(*)(\"hello\"); }-*/;", "}"); MockJavaResource extra = JavaResourceBase.createMockJavaResource("Super", "class Super {", " private int m(Object x) { return -1; }", "}"); shouldGenerateNoError(buggy, extra); } }