Use JAnnotation API for ArtificialRescue
Patch by: bobv
Review by: scottb


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7549 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java b/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java
new file mode 100644
index 0000000..5d3e9bd
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2010 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.jjs;
+
+import com.google.gwt.core.client.impl.ArtificialRescue;
+import com.google.gwt.core.client.impl.ArtificialRescue.Rescue;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.HasEnclosingType;
+import com.google.gwt.dev.jjs.ast.JAnnotation;
+import com.google.gwt.dev.jjs.ast.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JNode;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.impl.JsniRefLookup;
+import com.google.gwt.dev.util.JsniRef;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Process ArtificialRescue annotations.
+ */
+public class ArtificialRescueRecorder {
+  private class Recorder extends JVisitor {
+    private JDeclaredType currentClass;
+
+    @Override
+    public void endVisit(JAnnotation x, Context ctx) {
+      if (x.getType() == artificialRescueType) {
+        ArtificialRescue annotation = JAnnotation.createAnnotation(
+            ArtificialRescue.class, x);
+        for (Rescue rescue : annotation.value()) {
+          process(rescue);
+        }
+      }
+    }
+
+    @Override
+    public void endVisit(JDeclaredType x, Context ctx) {
+      assert currentClass == x;
+    }
+
+    @Override
+    public boolean visit(JDeclaredType x, Context ctx) {
+      currentClass = x;
+
+      /*
+       * We only care about annotations declared on the type itself, so we can
+       * skip the traversal of fields and methods.
+       */
+      accept(x.getAnnotations());
+      return false;
+    }
+
+    private void process(Rescue rescue) {
+      assert rescue != null : "rescue";
+
+      String typeName = rescue.className();
+      JReferenceType classType = (JReferenceType) program.getTypeFromJsniRef(typeName);
+      String[] fields = rescue.fields();
+      boolean instantiable = rescue.instantiable();
+      String[] methods = rescue.methods();
+
+      assert classType != null : "classType " + typeName;
+      assert fields != null : "fields";
+      assert methods != null : "methods";
+
+      if (instantiable) {
+        currentClass.addArtificialRescue(classType);
+
+        // Make sure that a class literal for the type has been allocated
+        program.getLiteralClass(classType);
+      }
+
+      if (classType instanceof JDeclaredType) {
+        List<String> toRescue = new ArrayList<String>();
+        Collections.addAll(toRescue, fields);
+        Collections.addAll(toRescue, methods);
+
+        for (String name : toRescue) {
+          JsniRef ref = JsniRef.parse("@" + classType.getName() + "::" + name);
+          final String[] errors = {null};
+          HasEnclosingType node = JsniRefLookup.findJsniRefTarget(ref, program,
+              new JsniRefLookup.ErrorReporter() {
+                public void reportError(String error) {
+                  errors[0] = error;
+                }
+              });
+          if (errors[0] != null) {
+            // Should have been caught by ArtificialRescueChecker
+            throw new InternalCompilerException(
+                "Unable to artificially rescue " + name + ": " + errors[0]);
+          }
+
+          currentClass.addArtificialRescue((JNode) node);
+          if (node instanceof JField) {
+            JField field = (JField) node;
+            if (!field.isFinal()) {
+              field.setVolatile();
+            }
+          }
+        }
+      }
+    }
+  }
+
+  public static void exec(JProgram program) {
+    new ArtificialRescueRecorder(program).execImpl();
+  }
+
+  private final JDeclaredType artificialRescueType;
+  private final JProgram program;
+
+  private ArtificialRescueRecorder(JProgram program) {
+    this.program = program;
+    artificialRescueType = program.getFromTypeMap(ArtificialRescue.class.getName());
+  }
+
+  private void execImpl() {
+    new Recorder().accept(program);
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index b725548..bcdf051 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -486,7 +486,7 @@
       maybeDumpAST(jprogram);
 
       // (3) Perform Java AST normalizations.
-
+      ArtificialRescueRecorder.exec(jprogram);
       FixAssignmentToUnbox.exec(jprogram);
 
       /*
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotation.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotation.java
index f4a3413..1d2876b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotation.java
@@ -220,9 +220,7 @@
         new Class<?>[] {clazz}, new AnnotationInvocationHandler<T>(clazz,
             annotation));
 
-    @SuppressWarnings("unchecked")
-    T toReturn = (T) o;
-    return toReturn;
+    return clazz.cast(o);
   }
 
   /**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 907c789..45424e0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -87,7 +87,8 @@
    * Only annotations defined in the following packages or sub-packages thereof
    * will be recorded in the Java AST.
    */
-  public static final Set<String> RECORDED_ANNOTATION_PACKAGES = new LinkedHashSet<String>();
+  public static final Set<String> RECORDED_ANNOTATION_PACKAGES = new LinkedHashSet<String>(
+      Arrays.asList("com.google.gwt.core.client.impl"));
 
   static final Map<String, Set<String>> traceMethods = new HashMap<String, Set<String>>();
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index e2fd879..d1820bc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.dev.jjs.impl;
 
-import com.google.gwt.core.client.impl.ArtificialRescue;
 import com.google.gwt.dev.javac.JsniCollector;
 import com.google.gwt.dev.jjs.HasSourceInfo;
 import com.google.gwt.dev.jjs.InternalCompilerException;
@@ -101,7 +100,6 @@
 import com.google.gwt.dev.js.ast.JsModVisitor;
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsProgram;
-import com.google.gwt.dev.util.Empty;
 import com.google.gwt.dev.util.JsniRef;
 import com.google.gwt.dev.util.collect.Lists;
 
@@ -141,7 +139,6 @@
 import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
 import org.eclipse.jdt.internal.compiler.ast.LabeledStatement;
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
 import org.eclipse.jdt.internal.compiler.ast.MessageSend;
 import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
 import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression;
@@ -152,10 +149,8 @@
 import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
 import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
-import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
 import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
 import org.eclipse.jdt.internal.compiler.ast.Statement;
-import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
 import org.eclipse.jdt.internal.compiler.ast.SuperReference;
 import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
 import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement;
@@ -491,8 +486,6 @@
           processEnumType((JEnumType) currentClass);
         }
 
-        processArtificialRescues(x);
-
         currentClassScope = null;
         currentClass = null;
         currentSeparatorPositions = null;
@@ -2560,128 +2553,6 @@
           + value.getClass().getName());
     }
 
-    private void processArtificialRescue(Annotation rescue) {
-      assert rescue != null;
-
-      JReferenceType classType = null;
-      String[] fields = Empty.STRINGS;
-      boolean instantiable = false;
-      String[] methods = Empty.STRINGS;
-      String typeName = null;
-
-      for (MemberValuePair pair : rescue.memberValuePairs()) {
-        String name = String.valueOf(pair.name);
-        Expression value = pair.value;
-
-        if ("className".equals(name)) {
-          typeName = value.constant.stringValue();
-
-          // Invalid references should be caught in ArtificialRescueChecker
-          classType = (JReferenceType) program.getTypeFromJsniRef(typeName);
-
-        } else if ("fields".equals(name)) {
-          if (value instanceof StringLiteral) {
-            fields = new String[] {value.constant.stringValue()};
-          } else if (value instanceof ArrayInitializer) {
-            ArrayInitializer init = (ArrayInitializer) value;
-            fields = new String[init.expressions == null ? 0
-                : init.expressions.length];
-            for (int i = 0, j = fields.length; i < j; i++) {
-              fields[i] = init.expressions[i].constant.stringValue();
-            }
-          }
-
-        } else if ("instantiable".equals(name)) {
-          instantiable = value.constant.booleanValue();
-
-        } else if ("methods".equals(name)) {
-          if (value instanceof StringLiteral) {
-            methods = new String[] {value.constant.stringValue()};
-          } else if (value instanceof ArrayInitializer) {
-            ArrayInitializer init = (ArrayInitializer) value;
-            methods = new String[init.expressions == null ? 0
-                : init.expressions.length];
-            for (int i = 0, j = methods.length; i < j; i++) {
-              methods[i] = init.expressions[i].constant.stringValue();
-            }
-          }
-        } else {
-          throw new InternalCompilerException(
-              "Unknown Rescue annotation member " + name);
-        }
-      }
-
-      assert classType != null : "classType " + typeName;
-      assert fields != null : "fields";
-      assert methods != null : "methods";
-
-      if (instantiable) {
-        currentClass.addArtificialRescue(classType);
-
-        // Make sure that a class literal for the type has been allocated
-        program.getLiteralClass(classType);
-      }
-
-      if (classType instanceof JDeclaredType) {
-        List<String> toRescue = new ArrayList<String>();
-        Collections.addAll(toRescue, fields);
-        Collections.addAll(toRescue, methods);
-
-        for (String name : toRescue) {
-          JsniRef ref = JsniRef.parse("@" + classType.getName() + "::" + name);
-          final String[] errors = {null};
-          HasEnclosingType node = JsniRefLookup.findJsniRefTarget(ref, program,
-              new JsniRefLookup.ErrorReporter() {
-                public void reportError(String error) {
-                  errors[0] = error;
-                }
-              });
-          if (errors[0] != null) {
-            // Should have been caught by ArtificialRescueChecker
-            throw new InternalCompilerException(
-                "Unable to artificially rescue " + name + ": " + errors[0]);
-          }
-
-          currentClass.addArtificialRescue((JNode) node);
-          if (node instanceof JField) {
-            JField field = (JField) node;
-            if (!field.isFinal()) {
-              field.setVolatile();
-            }
-          }
-        }
-      }
-    }
-
-    private void processArtificialRescues(TypeDeclaration x) {
-      if (x.annotations == null) {
-        return;
-      }
-
-      for (Annotation a : x.annotations) {
-        if (!ArtificialRescue.class.getName().equals(
-            CharOperation.toString(((ReferenceBinding) a.resolvedType).compoundName))) {
-          continue;
-        }
-
-        Expression value = ((SingleMemberAnnotation) a).memberValue;
-        assert value != null;
-        if (value instanceof ArrayInitializer) {
-          for (Expression e : ((ArrayInitializer) value).expressions) {
-            processArtificialRescue((Annotation) e);
-          }
-        } else if (value instanceof Annotation) {
-          processArtificialRescue((Annotation) value);
-        } else {
-          throw new InternalCompilerException(
-              "Unable to process annotation with value of type "
-                  + value.getClass().getName());
-        }
-
-        return;
-      }
-    }
-
     /**
      * Helper for creating all JBinaryOperation. Several different JDT nodes can
      * result in binary operations: AND_AND_Expression, Assignment,