/*
 * 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);
  }
}
