JsniChecker should resolve methods defined by super interfaces.

Review by: bobv

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7280 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
index 07c2361..dea6347 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
@@ -56,8 +56,11 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding;
 
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Queue;
 import java.util.Set;
 import java.util.Stack;
 
@@ -374,13 +377,23 @@
           }
         }
       } else {
-        while (clazz != null) {
+        Queue<ReferenceBinding> work = new LinkedList<ReferenceBinding>();
+        work.add(clazz);
+        while (!work.isEmpty()) {
+          clazz = work.remove();
           for (MethodBinding findMethod : clazz.getMethods(methodName.toCharArray())) {
             if (paramTypesMatch(findMethod, jsniRef)) {
               return findMethod;
             }
           }
-          clazz = clazz.superclass();
+          ReferenceBinding[] superInterfaces = clazz.superInterfaces();
+          if (superInterfaces != null) {
+            work.addAll(Arrays.asList(superInterfaces));
+          }
+          ReferenceBinding superclass = clazz.superclass();
+          if (superclass != null) {
+            work.add(superclass);
+          }
         }
       }
       return null;
diff --git a/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java b/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
index 1e45512..0f19de7 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
@@ -357,6 +357,28 @@
         "Parameter 1 of method \'Buggy.print\': type 'long' may not be passed out of JSNI code");
   }
 
+  /**
+   * Test JSNI references to methods defined in superclass/superinterfaces.
+   */
+  public void testMethodInheritance() {
+    StringBuffer code = new StringBuffer();
+    code.append("class Buggy {\n");
+    code.append("  interface A1 { void a1(); }\n");
+    code.append("  interface A2 extends A1 { void a2(); }\n");
+    code.append("  static abstract class C1 implements A2 { public abstract void c1(); }\n");
+    code.append("  native void jsniMeth(Object o) /*-{\n");
+    code.append("    o.@Buggy.A1::a1()();\n");
+    code.append("    o.@Buggy.A2::a1()();\n");
+    code.append("    o.@Buggy.A2::a2()();\n");
+    code.append("    o.@Buggy.C1::a1()();\n");
+    code.append("    o.@Buggy.C1::a2()();\n");
+    code.append("    o.@Buggy.C1::c1()();\n");
+    code.append("  }-*/;\n");
+    code.append("}\n");
+
+    shouldGenerateNoWarning(code);
+  }
+
   public void testMethodReturn() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");