Allow annotations to be retrieved from binding.

In this patch refactors the annotation access code in JdtUtil and
fixes the issue of retrieving @UnusedCast from a method call
binding.

Change-Id: I2f18a6235b59d96966d20e9e082b5feccc6499e5
diff --git a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
index e3eb085..2d249d3 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
@@ -210,21 +210,21 @@
       return true;
     }
 
-    private void checkJsFunction(TypeDeclaration type, TypeBinding typeBinding) {
-      ReferenceBinding binding = (ReferenceBinding) typeBinding;
-      if (JdtUtil.getAnnotation(binding, "jsinterop.annotations.JsFunction") == null) {
+    private void checkJsFunction(TypeDeclaration type) {
+      if (JdtUtil.getAnnotationByName(
+          type.annotations, "jsinterop.annotations.JsFunction") == null) {
         return;
       }
-      if (!binding.isFunctionalInterface(type.scope)) {
+      if (!type.binding.isFunctionalInterface(type.scope)) {
         errorOn(type, ERR_JS_FUNCTION_ONLY_ALLOWED_ON_FUNCTIONAL_INTERFACE);
         return;
       }
     }
 
     private ClassState checkType(TypeDeclaration type) {
-      SourceTypeBinding binding = type.binding;
-      checkJsFunction(type, binding);
+      checkJsFunction(type);
 
+      SourceTypeBinding binding = type.binding;
       if (!JdtUtil.isJsoSubclass(binding)) {
         return ClassState.NORMAL;
       }
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
index ada3271..0c13e7e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -711,6 +711,9 @@
     options.sourceLevel = jdtSourceLevel;
     options.targetJDK = jdtSourceLevel;
 
+    // Make sure the annotations are stored in and accessible through the bindings.
+    options.storeAnnotations = true;
+
     // Generate debug info for debugging the output.
     options.produceDebugAttributes =
         ClassFileConstants.ATTR_VARS | ClassFileConstants.ATTR_LINES
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
index f9c23b7..f89f10d 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
@@ -27,13 +27,10 @@
 import com.google.gwt.thirdparty.guava.common.collect.Lists;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
 import org.eclipse.jdt.internal.compiler.impl.StringConstant;
 import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
-import org.eclipse.jdt.internal.compiler.lookup.Binding;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
 import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
@@ -42,7 +39,6 @@
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
-import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 import java.util.Arrays;
@@ -197,12 +193,13 @@
   private JdtUtil() {
   }
 
-  public static String getAnnotationParameterString(AnnotationBinding a, String paramName) {
-    if (a != null) {
-      for (ElementValuePair maybeValue : a.getElementValuePairs()) {
-        if (maybeValue.getValue() instanceof StringConstant &&
-            paramName.equals(String.valueOf(maybeValue.getName()))) {
-          return ((StringConstant) maybeValue.getValue()).stringValue();
+  public static String getAnnotationParameterString(
+      AnnotationBinding annotationBinding, String parameterName) {
+    if (annotationBinding != null) {
+      for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
+        if (parameterNameValuePair.getValue() instanceof StringConstant &&
+            parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
+          return ((StringConstant) parameterNameValuePair.getValue()).stringValue();
         }
       }
     }
@@ -210,76 +207,64 @@
   }
 
   public static boolean getAnnotationParameterBoolean(
-      AnnotationBinding a, String paramName, boolean defaultValue) {
-    Boolean rv = getAnnotationParameterBoolean(a, paramName);
-    return rv == null ? defaultValue : rv;
+      AnnotationBinding annotationBinding, String parameterName, boolean defaultValue) {
+    Boolean booleanParameterValue = getAnnotationParameterBoolean(annotationBinding, parameterName);
+    return booleanParameterValue == null ? defaultValue : booleanParameterValue;
   }
 
-  public static Boolean getAnnotationParameterBoolean(AnnotationBinding a, String paramName) {
-    if (a != null) {
-      for (ElementValuePair maybeValue : a.getElementValuePairs()) {
-        if (maybeValue.getValue() instanceof BooleanConstant &&
-            paramName.equals(String.valueOf(maybeValue.getName()))) {
-          return ((BooleanConstant) maybeValue.getValue()).booleanValue();
+  public static Boolean getAnnotationParameterBoolean(
+      AnnotationBinding annotationBinding, String parameterName) {
+    if (annotationBinding != null) {
+      for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
+        if (parameterNameValuePair.getValue() instanceof BooleanConstant &&
+            parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
+          return ((BooleanConstant) parameterNameValuePair.getValue()).booleanValue();
         }
       }
     }
     return null;
   }
 
-  static AnnotationBinding getAnnotation(AnnotationBinding[] annotations, String nameToFind) {
-    if (annotations != null) {
-      for (AnnotationBinding a : annotations) {
-        ReferenceBinding annBinding = a.getAnnotationType();
-        String annName = CharOperation.toString(annBinding.compoundName);
-        if (nameToFind.equals(annName)) {
-          return a;
-        }
-      }
-    }
-    return null;
-  }
-
-  public static AnnotationBinding getAnnotation(Annotation[] annotations, String nameToFind) {
-    if (annotations != null) {
-      for (Annotation a : annotations) {
-        AnnotationBinding annBinding = a.getCompilerAnnotation();
-        if (annBinding != null) {
-          String annName = CharOperation.toString(annBinding.getAnnotationType().compoundName);
-          if (nameToFind.equals(annName)) {
-            return annBinding;
-          }
-        }
-      }
-    }
-    return null;
-  }
-
-  public static AnnotationBinding getAnnotation(Binding binding, String nameToFind) {
-    if (binding instanceof SourceTypeBinding) {
-      ClassScope scope = ((SourceTypeBinding) binding).scope;
-      return scope != null ? getAnnotation(scope.referenceType().annotations, nameToFind) : null;
-    } else if (binding instanceof ReferenceBinding) {
-      return getAnnotation(((ReferenceBinding) binding).getAnnotations(), nameToFind);
-    } else if (binding instanceof SyntheticMethodBinding) {
-      return null;
-    } else if (binding instanceof MethodBinding) {
-      AbstractMethodDeclaration abMethod = safeSourceMethod((MethodBinding) binding);
-      return abMethod != null ? getAnnotation(abMethod.annotations, nameToFind) : null;
-    } else if (binding instanceof FieldBinding) {
-      return getAnnotation(((FieldBinding) binding).sourceField().annotations, nameToFind);
-    } else {
+  public static AnnotationBinding getAnnotationByName(Annotation[] annotations, String name) {
+    if (annotations == null) {
       return null;
     }
+    for (Annotation annotation : annotations) {
+      AnnotationBinding annotationBinding = annotation.getCompilerAnnotation();
+      if (matchAnnotationName(annotationBinding, name)) {
+        return annotationBinding;
+      }
+    }
+    return null;
+  }
+
+  public static AnnotationBinding getAnnotationByName(
+      AnnotationBinding[] annotationsBindings, String name) {
+    if (annotationsBindings == null) {
+      return null;
+    }
+    for (AnnotationBinding annotationBinding : annotationsBindings) {
+      if (matchAnnotationName(annotationBinding, name)) {
+        return annotationBinding;
+      }
+    }
+    return null;
+  }
+
+  private static boolean matchAnnotationName(AnnotationBinding annotationBinding, String name) {
+    if (annotationBinding == null) {
+      return false;
+    }
+    return name.equals(CharOperation.toString(annotationBinding.getAnnotationType().compoundName));
   }
 
   public static TypeBinding getAnnotationParameterTypeBinding(
-      AnnotationBinding a, String paramName) {
-    if (a != null) {
-      for (ElementValuePair maybeValue : a.getElementValuePairs()) {
-        if (maybeValue.getValue() instanceof Class &&
-            paramName.equals(String.valueOf(maybeValue.getName()))) {
-          return (TypeBinding)  maybeValue.getValue();
+      AnnotationBinding annotationBinding, String parameterName) {
+    if (annotationBinding != null) {
+      for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
+        if (parameterNameValuePair.getValue() instanceof Class &&
+            parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
+          return (TypeBinding) parameterNameValuePair.getValue();
         }
       }
     }
@@ -287,14 +272,14 @@
   }
 
   public static TypeBinding[] getAnnotationParameterTypeBindingArray(
-      AnnotationBinding annotationBinding, String paramName) {
+      AnnotationBinding annotationBinding, String parameterName) {
     if (annotationBinding == null) {
       return null;
     }
 
-    for (ElementValuePair maybeValue : annotationBinding.getElementValuePairs()) {
-      Object value = maybeValue.getValue();
-      if (!paramName.equals(String.valueOf(maybeValue.getName()))) {
+    for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
+      Object value = parameterNameValuePair.getValue();
+      if (!parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
         continue;
       }
       if (value instanceof Object[]) {
@@ -310,15 +295,15 @@
   }
 
   public static StringConstant[] getAnnotationParameterStringConstantArray(
-      AnnotationBinding annotationBinding, String paramName) {
+      AnnotationBinding annotationBinding, String parameterName) {
     if (annotationBinding == null) {
       return null;
     }
-    for (ElementValuePair maybeValue : annotationBinding.getElementValuePairs()) {
-      if (!paramName.equals(String.valueOf(maybeValue.getName()))) {
+    for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
+      if (!parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
         continue;
       }
-      Object value = maybeValue.getValue();
+      Object value = parameterNameValuePair.getValue();
       if (value instanceof Object[]) {
         Object[] values = (Object[]) value;
         StringConstant[] stringConstants = new StringConstant[values.length];
@@ -336,7 +321,7 @@
       return ImmutableSet.of();
     }
     AnnotationBinding suppressWarnings =
-        getAnnotation(annotations, SuppressWarnings.class.getName());
+        getAnnotationByName(annotations, SuppressWarnings.class.getName());
     if (suppressWarnings != null) {
       StringConstant[] values =
           JdtUtil.getAnnotationParameterStringConstantArray(suppressWarnings, "value");
@@ -352,17 +337,6 @@
     return ImmutableSet.of();
   }
 
-  /**
-   * Work around JDT bug.
-   */
-  public static AbstractMethodDeclaration safeSourceMethod(MethodBinding mb) {
-    try {
-      return mb.sourceMethod();
-    } catch (Exception e) {
-      return null;
-    }
-  }
-
   public static String signature(FieldBinding binding) {
     StringBuilder sb = new StringBuilder();
     sb.append(binding.declaringClass.constantPoolName());
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java b/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
index 454e5f8..0db2245 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
@@ -151,7 +151,7 @@
   }
 
   private static AnnotationBinding getInteropAnnotation(Annotation[] annotations, String name) {
-    return JdtUtil.getAnnotation(annotations, "jsinterop.annotations." + name);
+    return JdtUtil.getAnnotationByName(annotations, "jsinterop.annotations." + name);
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 5930ad1..d2cb9b6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -4164,31 +4164,32 @@
 
   private static boolean isUncheckedGenericMethodCall(MessageSend messageSend) {
     if (messageSend.binding.genericMethod() != null) {
-      return JdtUtil.getAnnotation(messageSend.binding.genericMethod(),
-          "javaemul.internal.annotations.UncheckedCast") != null;
+      return JdtUtil.getAnnotationByName(messageSend.binding().getAnnotations(),
+              "javaemul.internal.annotations.UncheckedCast") != null;
     }
     return false;
   }
 
   private static void maybeSetInliningMode(AbstractMethodDeclaration x, JMethod method) {
-    MethodBinding bind = x.binding;
-    if (JdtUtil.getAnnotation(bind, "javaemul.internal.annotations.DoNotInline") != null) {
+    if (JdtUtil.getAnnotationByName(
+        x.annotations, "javaemul.internal.annotations.DoNotInline") != null) {
       method.setInliningMode(InliningMode.DO_NOT_INLINE);
-    } else if (JdtUtil.getAnnotation(bind, "javaemul.internal.annotations.ForceInline") != null) {
+    } else if (JdtUtil.getAnnotationByName(
+        x.annotations, "javaemul.internal.annotations.ForceInline") != null) {
       method.setInliningMode(InliningMode.FORCE_INLINE);
     }
   }
 
   private static void maybeSetHasNoSideEffects(AbstractMethodDeclaration x, JMethod method) {
-    if (JdtUtil.getAnnotation(x.binding,
-        "javaemul.internal.annotations.HasNoSideEffects") != null) {
+    if (JdtUtil.getAnnotationByName(
+        x.annotations, "javaemul.internal.annotations.HasNoSideEffects") != null) {
       method.setHasSideEffects(false);
     }
   }
 
   private void maybeAddMethodSpecialization(AbstractMethodDeclaration x, JMethod method) {
-    AnnotationBinding specializeAnnotation =
-        JdtUtil.getAnnotation(x.binding, "javaemul.internal.annotations.SpecializeMethod");
+    AnnotationBinding specializeAnnotation = JdtUtil.getAnnotationByName(
+        x.annotations, "javaemul.internal.annotations.SpecializeMethod");
     if (specializeAnnotation == null) {
       return;
     }