Revision: 7539
Author: [email protected]
Date: Tue Feb 9 15:22:29 2010
Log: Compiler infrastructure addition to selectively retain Java
annotations in the AST.
Patch by: bobv
Review by: scottb, spoon
http://code.google.com/p/google-web-toolkit/source/detail?r=7539
Added:
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/HasAnnotations.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotation.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotationArgument.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JExternalType.java
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/JAnnotationTest.java
Modified:
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/HasAnnotations.java Tue
Feb 9 15:22:29 2010
@@ -0,0 +1,40 @@
+/*
+ * 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.ast;
+
+import java.util.List;
+
+/**
+ * Provides access to the annotations defined on an AST node.
+ */
+public interface HasAnnotations {
+ /**
+ * Add a annotation to the node.
+ */
+ void addAnnotation(JAnnotation annotation);
+
+ /**
+ * Returns the annotation declared on the node of the given type or
+ * <code>null</code> if no such annotation exists. For annotations on
+ * subclasses of JDeclaredType, this method will not search the
supertypes.
+ */
+ JAnnotation findAnnotation(String className);
+
+ /**
+ * Return the annotations associated with the node.
+ */
+ List<JAnnotation> getAnnotations();
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotation.java Tue
Feb 9 15:22:29 2010
@@ -0,0 +1,292 @@
+/*
+ * 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.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.List;
+
+/**
+ * Represents a java annotation.
+ */
+public class JAnnotation extends JNode implements JAnnotationArgument {
+ /**
+ * Represents a value contained within an annotation. Single-valued and
+ * array-valued properties are both represented by this type.
+ *
+ * @param <T> the type of JAnnotationValue node that the Property
+ * encapsulates.
+ * @see {...@link #of}
+ */
+ public static class Property extends JNode {
+ private final String name;
+ private List<JAnnotationArgument> values;
+
+ public Property(SourceInfo sourceInfo, String name,
+ List<JAnnotationArgument> values) {
+ super(sourceInfo);
+ this.name = name;
+ this.values = Lists.normalize(values);
+ }
+
+ public Property(SourceInfo sourceInfo, String name,
+ JAnnotationArgument value) {
+ this(sourceInfo, name, Lists.create(value));
+ }
+
+ public void addValue(JAnnotationArgument value) {
+ values = Lists.add(values, value);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public JAnnotationArgument getSingleValue() {
+ if (values.size() != 1) {
+ throw new IllegalStateException(
+ "Expecting single-valued property, found " + values.size()
+ + " values");
+ }
+ return values.get(0);
+ }
+
+ public List<JAnnotationArgument> getValues() {
+ return Lists.normalizeUnmodifiable(values);
+ }
+
+ public List<JNode> getValuesAsNodes() {
+ // Lists.normalizeUnmodifiable would have allocated a new list anyway
+ List<JNode> toReturn = Lists.create();
+ for (JAnnotationArgument value : values) {
+ toReturn = Lists.add(toReturn, value.annotationNode());
+ }
+ return toReturn;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void traverse(JVisitor visitor, Context ctx) {
+ if (visitor.visit(this, ctx)) {
+ // This is a shady cast to a raw list
+ List nodes = visitor.acceptImmutable((List) values);
+
+ // JNode and JAnnotationArgument types have disjoint hierarchies
+ if (JAnnotation.class.desiredAssertionStatus()) {
+ for (int i = 0, j = nodes.size(); i < j; i++) {
+ assert nodes.get(i) instanceof
JAnnotationArgument : "Expecting a "
+ + "JAnnotationArgument at index " + i + " found a "
+ + nodes.get(i).getClass().getCanonicalName();
+ }
+ }
+
+ // This is a shady assignment
+ values = nodes;
+ }
+ visitor.endVisit(this, ctx);
+ }
+ }
+
+ /**
+ * This runtime exception is thrown when calling a Class-valued
annotation
+ * method when the referenced class is not available to the JVM.
+ */
+ public static class SourceOnlyClassException extends RuntimeException {
+ private final JClassLiteral literal;
+
+ public SourceOnlyClassException(JClassLiteral literal) {
+ super("The type " + literal.getRefType().getName()
+ + " is available only in the module source");
+ this.literal = literal;
+ }
+
+ public JClassLiteral getLiteral() {
+ return literal;
+ }
+ }
+
+ /**
+ * This handles reflective dispatch for Proxy instances onto the data
stored
+ * in the AST.
+ *
+ * @param <T> the type of Annotation
+ */
+ private static class AnnotationInvocationHandler<T> implements
+ InvocationHandler {
+ private final Class<T> clazz;
+ private final JAnnotation annotation;
+
+ private AnnotationInvocationHandler(Class<T> clazz, JAnnotation
annotation) {
+ this.clazz = clazz;
+ this.annotation = annotation;
+ }
+
+ /**
+ * Handles method invocations.
+ */
+ public Object invoke(Object instance, Method method, Object[]
arguments)
+ throws Throwable {
+
+ // Use the proxy object to handle trivial stuff
+ if (method.getDeclaringClass() == Object.class) {
+ return method.invoke(this, arguments);
+ }
+
+ Property prop = annotation.getProperty(method.getName());
+ if (prop == null) {
+ // This works because we're working with real Methods
+ return method.getDefaultValue();
+ }
+
+ if (method.getReturnType().isArray()) {
+ List<JAnnotationArgument> values = prop.getValues();
+ Object toReturn = Array.newInstance(
+ method.getReturnType().getComponentType(), values.size());
+ for (int i = 0, j = values.size(); i < j; i++) {
+ Object value = evaluate(values.get(i));
+ Array.set(toReturn, i, value);
+ }
+ return toReturn;
+ }
+
+ return evaluate(prop.getSingleValue());
+ }
+
+ /**
+ * Convert a JLiteral value into an Object the caller can work with.
+ */
+ private Object evaluate(JAnnotationArgument value)
+ throws ClassNotFoundException {
+
+ if (value instanceof JValueLiteral) {
+ // Primitives
+ return ((JValueLiteral) value).getValueObj();
+
+ } else if (value instanceof JClassLiteral) {
+ String clazzName = ((JClassLiteral) value).getRefType().getName();
+ try {
+ return Class.forName(clazzName, true, clazz.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new SourceOnlyClassException((JClassLiteral) value);
+ }
+
+ } else if (value instanceof JAnnotation) {
+ // Determine the synthetic annotation's type
+ String clazzName = ((JAnnotation) value).getType().getName();
+ // Load the annotation class
+ Class<? extends Annotation> annotationType =
Class.forName(clazzName,
+ true, clazz.getClassLoader()).asSubclass(Annotation.class);
+ // Creating the backing annotation
+ return createAnnotation(annotationType, (JAnnotation) value);
+ }
+
+ // Unhandled type
+ throw new RuntimeException("Cannot convert "
+ + value.getClass().getCanonicalName() + " into an Object");
+ }
+ }
+
+ /**
+ * Create a synthetic Annotation instance, based on the data in a
JAnnatation.
+ *
+ * @param clazz the type of Annotation
+ * @param annotation the backing data
+ *
+ * @param <T> the type of Annotation
+ * @return an instance of <code>clazz</code>
+ */
+ public static <T extends Annotation> T createAnnotation(Class<T> clazz,
+ JAnnotation annotation) {
+ // Create the annotation as a reflective Proxy instance
+ Object o = Proxy.newProxyInstance(clazz.getClassLoader(),
+ new Class<?>[] {clazz}, new AnnotationInvocationHandler<T>(clazz,
+ annotation));
+
+ @SuppressWarnings("unchecked")
+ T toReturn = (T) o;
+ return toReturn;
+ }
+
+ /**
+ * A utility method to retrieve an annotation of the named type. This
method
+ * will not search supertypes or superinterfaces if <code>x</code> is a
+ * JDeclaredType.
+ *
+ * @return the annotation of the requested type, or <code>null</code>
+ */
+ public static JAnnotation findAnnotation(HasAnnotations x,
+ String annotationTypeName) {
+ for (JAnnotation a : x.getAnnotations()) {
+ if (a.getType().getName().equals(annotationTypeName)) {
+ return a;
+ }
+ }
+ return null;
+ }
+
+ private final JType type;
+ private List<Property> properties = Lists.create();
+
+ public JAnnotation(SourceInfo sourceInfo, JExternalType type) {
+ super(sourceInfo);
+ this.type = type;
+ }
+
+ public JAnnotation(SourceInfo sourceInfo, JInterfaceType type) {
+ super(sourceInfo);
+ this.type = type;
+ }
+
+ public void addValue(Property value) {
+ properties = Lists.add(properties, value);
+ }
+
+ public JNode annotationNode() {
+ return this;
+ }
+
+ public List<Property> getProperties() {
+ return Lists.normalizeUnmodifiable(properties);
+ }
+
+ /**
+ * Returns the named property or <code>null</code> if it does not exist.
+ */
+ public Property getProperty(String name) {
+ for (Property p : properties) {
+ if (p.getName().equals(name)) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ public JType getType() {
+ return type;
+ }
+
+ public void traverse(JVisitor visitor, Context ctx) {
+ if (visitor.visit(this, ctx)) {
+ properties = visitor.acceptImmutable(properties);
+ }
+ visitor.endVisit(this, ctx);
+ }
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JAnnotationArgument.java
Tue Feb 9 15:22:29 2010
@@ -0,0 +1,26 @@
+/*
+ * 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.ast;
+
+/**
+ * A tag interface for JNodes that are legal values for annotation
properties.
+ */
+public interface JAnnotationArgument {
+ /**
+ * A convenience method to avoid explicit casts.
+ */
+ JNode annotationNode();
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JExternalType.java Tue
Feb 9 15:22:29 2010
@@ -0,0 +1,49 @@
+/*
+ * 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.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * Represents a type outside of the client type system, usually a
binary-only
+ * annotation reference.
+ */
+public class JExternalType extends JDeclaredType {
+
+ JExternalType(SourceInfo info, String name) {
+ super(info, name);
+ }
+
+ @Override
+ public String getClassLiteralFactoryMethod() {
+ return "Class.createForInterface";
+ }
+
+ public boolean isAbstract() {
+ return true;
+ }
+
+ public boolean isFinal() {
+ return false;
+ }
+
+ public void traverse(JVisitor visitor, Context ctx) {
+ if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
+ }
+ visitor.endVisit(this, ctx);
+ }
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/JAnnotationTest.java
Tue Feb 9 15:22:29 2010
@@ -0,0 +1,271 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.jjs.ast.JAnnotation;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
+import com.google.gwt.dev.jjs.ast.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JExternalType;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JParameter;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JAnnotation.Property;
+import com.google.gwt.dev.jjs.ast.JAnnotation.SourceOnlyClassException;
+
+/**
+ * Tests AST setup of JAnnotation nodes as well as the reflective proxy for
+ * accessing their data.
+ */
+public class JAnnotationTest extends OptimizerTestBase {
+
+ /**
+ * A test class for binary-only annotations.
+ */
+ public @interface BinaryAnnotation {
+ Class<?> c() default Object.class;
+
+ int i() default 2;
+
+ int[] iOne() default 1;
+
+ int[] iTwo() default {1, 2};
+
+ int[] iZero() default {};
+
+ OtherAnnotation[] o() default {
+ @OtherAnnotation("Hello 1"), @OtherAnnotation("Hello 2")};
+
+ String s() default "Hello String";
+ }
+
+ /**
+ * Used to test binary-only class literal behavior.
+ */
+ public @interface ClassAnnotation {
+ Class<?> value();
+ }
+
+ /**
+ * A test case for meta-annotations.
+ */
+ public @interface OtherAnnotation {
+ String value();
+ }
+
+ private static void assertEquals(int[] a, int[] b) {
+ assertEquals(a.length, b.length);
+ for (int i = 0, j = a.length; i < j; i++) {
+ assertEquals(a[i], b[i]);
+ }
+ }
+
+ public void setUp() {
+ // These packages have annotations required by this test
+ JProgram.RECORDED_ANNOTATION_PACKAGES.add("com.google.gwt.dev.jjs");
+ JProgram.RECORDED_ANNOTATION_PACKAGES.add("test");
+
+ sourceOracle.addOrReplace(new
MockJavaResource("test.SourceClassAnnotation") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;\n");
+ code.append("public @interface SourceClassAnnotation {\n");
+ code.append(" Class<?> value();\n");
+ code.append("}\n");
+ return code;
+ }
+ });
+ sourceOracle.addOrReplace(new MockJavaResource("test.Tag") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;\n");
+ code.append("@Tag\n");
+ code.append("public @interface Tag {\n");
+ code.append("}\n");
+ return code;
+ }
+ });
+ sourceOracle.addOrReplace(new MockJavaResource("test.WithTag") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;\n");
+ code.append("@Tag\n");
+ code.append("public class WithTag {\n");
+ code.append(" @Tag String field;\n");
+ code.append(" @Tag WithTag(){}\n");
+ code.append(" @Tag void method(@Tag String p) {...@tag String
local;}\n");
+ code.append("}\n");
+ return code;
+ }
+ });
+ sourceOracle.addOrReplace(new MockJavaResource("test.WithBinary") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;\n");
+ code.append("import " + BinaryAnnotation.class.getCanonicalName()
+ + ";\n");
+ code.append("import " + ClassAnnotation.class.getCanonicalName()
+ + ";\n");
+ code.append("import " + OtherAnnotation.class.getCanonicalName()
+ + ";\n");
+ code.append("public class WithBinary {\n");
+ code.append(" public static final String EXPR =
\"Expression\";\n");
+ code.append(" @ClassAnnotation("
+ + JAnnotationTest.class.getCanonicalName() + ".class)\n");
+ code.append(" void useBinaryClassReference() {}\n");
+ code.append(" @BinaryAnnotation\n");
+ code.append(" void useDefaults() {}\n");
+ code.append(" @SourceClassAnnotation("
+ + JAnnotationTest.class.getCanonicalName() + ".class)\n");
+ code.append(" void useSourceClassAnnotation() {}\n");
+ code.append(" @BinaryAnnotation(c=Tag.class, i=42, s=\"foo\", o=
@OtherAnnotation(\"Hello \" + EXPR))\n");
+ code.append(" void useValues() {}\n");
+ code.append("}\n");
+ return code;
+ }
+ });
+ }
+
+ public void testAllElementTypes() throws UnableToCompleteException {
+ JProgram program = compileSnippet("void", "new test.WithTag();");
+
+ // ANNOTATION_TYPE
+ JDeclaredType tag = findType(program, "test.Tag");
+ assertEquals(1, tag.getAnnotations().size());
+
+ // TYPE
+ JDeclaredType withTag = findType(program, "test.WithTag");
+ assertEquals(1, withTag.getAnnotations().size());
+
+ // CONSTRUCTOR
+ JMethod constructor = findMethod(withTag, "WithTag");
+ assertEquals(1, constructor.getAnnotations().size());
+
+ // METHOD
+ JMethod method = findMethod(withTag, "method");
+ assertEquals(1, method.getAnnotations().size());
+
+ // FIELD
+ JField field = findField(withTag, "field");
+ assertEquals(1, field.getAnnotations().size());
+
+ // LOCAL_VARIABLE
+ JLocal local = findLocal(method, "local");
+ assertEquals(1, local.getAnnotations().size());
+
+ // PARAMETER
+ JParameter param = method.getParams().get(0);
+ assertEquals(1, param.getAnnotations().size());
+
+ // There are no representations for PACKAGE in our AST
+ }
+
+ public void testAnnotationBinaryOnlyClassLiterals()
+ throws UnableToCompleteException {
+ JProgram program = compileSnippet("void", "new test.WithBinary();");
+
+ JDeclaredType t = findType(program, "test.WithBinary");
+ JMethod m = findMethod(t, "useBinaryClassReference");
+ JAnnotation a = JAnnotation.findAnnotation(m,
+ ClassAnnotation.class.getName());
+ assertNotNull(a);
+
+ ClassAnnotation instance = JAnnotation.createAnnotation(
+ ClassAnnotation.class, a);
+
+ assertSame(JAnnotationTest.class, instance.value());
+ }
+
+ public void testAnnotationProxyCustomValues()
+ throws UnableToCompleteException {
+ JProgram program = compileSnippet("void", "new test.WithBinary();");
+
+ JDeclaredType t = findType(program, "test.WithBinary");
+ JMethod useValues = findMethod(t, "useValues");
+ JAnnotation a = JAnnotation.findAnnotation(useValues,
+ BinaryAnnotation.class.getName());
+ assertNotNull(a);
+ BinaryAnnotation instance = JAnnotation.createAnnotation(
+ BinaryAnnotation.class, a);
+ assertNotNull(instance);
+
+ // A source-only annotation, unavailable to the JVM
+ try {
+ instance.c();
+ } catch (SourceOnlyClassException e) {
+ // Expected
+ assertEquals(findType(program, "test.Tag"),
e.getLiteral().getRefType());
+ }
+ assertEquals(42, instance.i());
+ assertEquals("foo", instance.s());
+ assertEquals(1, instance.o().length);
+ assertEquals("Hello Expression", instance.o()[0].value());
+ }
+
+ public void testAnnotationProxyDefaultValues()
+ throws UnableToCompleteException {
+ JProgram program = compileSnippet("void", "new test.WithBinary();");
+
+ JDeclaredType t = findType(program, "test.WithBinary");
+ JMethod useDefaults = findMethod(t, "useDefaults");
+ JAnnotation a = JAnnotation.findAnnotation(useDefaults,
+ BinaryAnnotation.class.getName());
+ assertNotNull(a);
+ assertTrue(a.getType() instanceof JExternalType);
+
+ BinaryAnnotation instance = JAnnotation.createAnnotation(
+ BinaryAnnotation.class, a);
+ assertNotNull(instance);
+
+ // Test Object methods
+ assertEquals(instance.hashCode(), instance.hashCode());
+ assertNotNull(instance.toString());
+
+ // Test default-valued
+ assertSame(Object.class, instance.c());
+ assertEquals(2, instance.i());
+ assertEquals(new int[] {1}, instance.iOne());
+ assertEquals(new int[] {1, 2}, instance.iTwo());
+ assertEquals(new int[] {}, instance.iZero());
+ assertNotNull(instance.o());
+ assertEquals(2, instance.o().length);
+ assertEquals("Hello 1", instance.o()[0].value());
+ assertEquals("Hello 2", instance.o()[1].value());
+ assertEquals("Hello String", instance.s());
+ }
+
+ public void testSourceAnnotationWithBinaryClass()
+ throws UnableToCompleteException {
+ JProgram program = compileSnippet("void", "new test.WithBinary();");
+
+ JDeclaredType t = findType(program, "test.WithBinary");
+ JMethod m = findMethod(t, "useSourceClassAnnotation");
+ JAnnotation a =
JAnnotation.findAnnotation(m, "test.SourceClassAnnotation");
+ assertNotNull(a);
+
+ Property p = a.getProperty("value");
+ JClassLiteral literal = (JClassLiteral) p.getSingleValue();
+ JExternalType externalType = (JExternalType) literal.getRefType();
+ assertEquals(JAnnotationTest.class.getName(), externalType.getName());
+ }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java Fri
Jun 5 05:17:27 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java Tue
Feb 9 15:22:29 2010
@@ -26,7 +26,7 @@
* ClassLiteralHolder. That field contains the class object allocation
* initializer.
*/
-public class JClassLiteral extends JLiteral {
+public class JClassLiteral extends JLiteral implements JAnnotationArgument
{
/**
* Create an expression that will evaluate, at run time, to the class
literal.
* Cannot be called after optimizations begin.
@@ -116,7 +116,7 @@
JClassLiteral componentLiteral =
program.getLiteralClass(arrayType.getElementType());
call.addArg(componentLiteral);
} else {
- assert (type instanceof JInterfaceType || type instanceof
JPrimitiveType);
+ assert (type instanceof JExternalType || type instanceof
JInterfaceType || type instanceof JPrimitiveType);
}
assert call.getArgs().size() == method.getParams().size() : "Argument
/ param mismatch "
+ call.toString() + " versus " + method.toString();
@@ -162,6 +162,10 @@
refType = type;
this.field = field;
}
+
+ public JNode annotationNode() {
+ return this;
+ }
/**
* Returns the field holding my allocated object.
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java Mon Apr
20 15:21:46 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java Tue Feb
9 15:22:29 2010
@@ -58,6 +58,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
fields = visitor.acceptWithInsertRemoveImmutable(fields);
methods = visitor.acceptWithInsertRemoveImmutable(methods);
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java Wed
Oct 28 09:10:53 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java Tue
Feb 9 15:22:29 2010
@@ -28,7 +28,12 @@
/**
* Base class for any reference type.
*/
-public abstract class JDeclaredType extends JReferenceType {
+public abstract class JDeclaredType extends JReferenceType implements
+ HasAnnotations {
+ /**
+ * Annotations applied to the type. Special serialization treatment.
+ */
+ protected transient List<JAnnotation> annotations = Lists.create();
/**
* The other nodes that this node should implicitly rescue. Special
@@ -65,6 +70,10 @@
public JDeclaredType(SourceInfo info, String name) {
super(info, name);
}
+
+ public void addAnnotation(JAnnotation annotation) {
+ annotations = Lists.add(annotations, annotation);
+ }
public void addArtificialRescue(JNode node) {
artificialRescues = Lists.add(artificialRescues, node);
@@ -127,6 +136,14 @@
}
return true;
}
+
+ public JAnnotation findAnnotation(String className) {
+ return JAnnotation.findAnnotation(this, className);
+ }
+
+ public List<JAnnotation> getAnnotations() {
+ return Lists.normalizeUnmodifiable(annotations);
+ }
public List<JNode> getArtificialRescues() {
return artificialRescues;
@@ -245,6 +262,7 @@
fields = (List<JField>) stream.readObject();
methods = (List<JMethod>) stream.readObject();
artificialRescues = (List<JNode>) stream.readObject();
+ annotations = (List<JAnnotation>) stream.readObject();
}
/**
@@ -280,6 +298,7 @@
stream.writeObject(fields);
stream.writeObject(methods);
stream.writeObject(artificialRescues);
+ stream.writeObject(annotations);
}
/**
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java Tue Nov 10
12:46:07 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java Tue Feb 9
15:22:29 2010
@@ -21,7 +21,6 @@
* Java field definition.
*/
public class JField extends JVariable implements CanBeStatic,
HasEnclosingType {
-
/**
* Determines whether the variable is final, volatile, or neither.
*/
@@ -46,8 +45,8 @@
private final boolean isStatic;
private boolean isVolatile;
- JField(SourceInfo info, String name, JDeclaredType enclosingType,
- JType type, boolean isStatic, Disposition disposition) {
+ JField(SourceInfo info, String name, JDeclaredType enclosingType, JType
type,
+ boolean isStatic, Disposition disposition) {
super(info, name, type, disposition.isFinal());
this.enclosingType = enclosingType;
this.isStatic = isStatic;
@@ -101,6 +100,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
// Do not visit declStmt, it gets visited within its own code block.
}
visitor.endVisit(this, ctx);
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java Mon
Apr 20 15:21:46 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java Tue
Feb 9 15:22:29 2010
@@ -41,6 +41,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
fields = visitor.acceptWithInsertRemoveImmutable(fields);
methods = visitor.acceptWithInsertRemoveImmutable(methods);
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java Mon Oct 26
14:02:26 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java Tue Feb 9
15:22:29 2010
@@ -40,6 +40,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
// Do not visit declStmt, it gets visited within its own code block.
}
visitor.endVisit(this, ctx);
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java Mon Jan 11
09:04:38 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java Tue Feb 9
15:22:29 2010
@@ -30,8 +30,9 @@
/**
* A Java method implementation.
*/
-public final class JMethod extends JNode implements HasEnclosingType,
HasName,
- HasType, CanBeAbstract, CanBeSetFinal, CanBeNative, CanBeStatic {
+public final class JMethod extends JNode implements HasAnnotations,
+ HasEnclosingType, HasName, HasType, CanBeAbstract, CanBeSetFinal,
+ CanBeNative, CanBeStatic {
private static final String TRACE_METHOD_WILDCARD = "*";
@@ -47,6 +48,7 @@
*/
private transient JAbstractMethodBody body = null;
+ private List<JAnnotation> annotations = Lists.create();
private final JDeclaredType enclosingType;
private final boolean isAbstract;
private boolean isFinal;
@@ -84,6 +86,10 @@
this.isFinal = isFinal;
this.isPrivate = isPrivate;
}
+
+ public void addAnnotation(JAnnotation annotation) {
+ annotations = Lists.add(annotations, annotation);
+ }
/**
* Add a method that this method overrides.
@@ -105,6 +111,10 @@
public void addParam(JParameter x) {
params = Lists.add(params, x);
}
+
+ public JAnnotation findAnnotation(String className) {
+ return JAnnotation.findAnnotation(this, className);
+ }
public void freezeParamTypes() {
List<JType> paramTypes = new ArrayList<JType>();
@@ -113,6 +123,10 @@
}
setOriginalTypes(returnType, paramTypes);
}
+
+ public List<JAnnotation> getAnnotations() {
+ return Lists.normalizeUnmodifiable(annotations);
+ }
public JAbstractMethodBody getBody() {
return body;
@@ -253,6 +267,7 @@
}
}
if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
params = visitor.acceptImmutable(params);
if (body != null) {
body = (JAbstractMethodBody) visitor.accept(body);
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java Tue Jan
26 09:41:35 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java Tue Feb
9 15:22:29 2010
@@ -64,6 +64,7 @@
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ annotations = visitor.acceptImmutable(annotations);
}
visitor.endVisit(this, ctx);
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Mon Jan 11
09:04:38 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Tue Feb 9
15:22:29 2010
@@ -83,6 +83,12 @@
"com.google.gwt.lang.EntryMethodHolder",
"com.google.gwt.core.client.prefetch.RunAsyncCode",}));
+ /**
+ * 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>();
+
static final Map<String, Set<String>> traceMethods = new HashMap<String,
Set<String>>();
private static final Comparator<JArrayType> ARRAYTYPE_COMPARATOR = new
ArrayTypeComparator();
@@ -274,6 +280,8 @@
*/
private final ArrayList<HashMap<JType, JArrayType>> dimensions = new
ArrayList<HashMap<JType, JArrayType>>();
+ private final Map<String, JExternalType> externalTypes = new
HashMap<String, JExternalType>();
+
private final Map<String, JField> indexedFields = new HashMap<String,
JField>();
private final Map<String, JMethod> indexedMethods = new HashMap<String,
JMethod>();
@@ -448,6 +456,21 @@
enclosingType.addField(x);
return x;
}
+
+ public JExternalType createExternalType(SourceInfo info, char[][] name) {
+ JExternalType x;
+ String sname = dotify(name);
+ x = externalTypes.get(sname);
+ if (x != null) {
+ return x;
+ }
+
+ x = new JExternalType(info, sname);
+ if (INDEX_TYPES_SET.contains(sname)) {
+ indexedTypes.put(x.getShortName(), x);
+ }
+ return x;
+ }
public JField createField(SourceInfo info, char[] name,
JDeclaredType enclosingType, JType type, boolean isStatic,
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.java Thu
Apr 9 08:41:34 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JValueLiteral.java Tue
Feb 9 15:22:29 2010
@@ -20,11 +20,16 @@
/**
* Base class for any Java literal expression.
*/
-public abstract class JValueLiteral extends JLiteral {
+public abstract class JValueLiteral extends JLiteral implements
+ JAnnotationArgument {
public JValueLiteral(SourceInfo sourceInfo) {
super(sourceInfo);
}
+
+ public JNode annotationNode() {
+ return this;
+ }
public abstract Object getValueObj();
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java Wed Dec
9 09:10:40 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java Tue Feb
9 15:22:29 2010
@@ -16,13 +16,17 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
+
+import java.util.List;
/**
* Base class for any storage location.
*/
public abstract class JVariable extends JNode implements CanBeSetFinal,
- CanHaveInitializer, HasName, HasType {
-
+ CanHaveInitializer, HasAnnotations, HasName, HasType {
+
+ protected List<JAnnotation> annotations = Lists.create();
protected JDeclarationStatement declStmt = null;
private boolean isFinal;
private final String name;
@@ -35,6 +39,18 @@
this.type = type;
this.isFinal = isFinal;
}
+
+ public void addAnnotation(JAnnotation annotation) {
+ annotations = Lists.add(annotations, annotation);
+ }
+
+ public JAnnotation findAnnotation(String className) {
+ return JAnnotation.findAnnotation(this, className);
+ }
+
+ public List<JAnnotation> getAnnotations() {
+ return Lists.normalizeUnmodifiable(annotations);
+ }
public JLiteral getConstInitializer() {
JExpression initializer = getInitializer();
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java Tue Jan 26
11:40:29 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java Tue Feb 9
15:22:29 2010
@@ -130,6 +130,14 @@
public void endVisit(JAbstractMethodBody x, Context ctx) {
endVisit((JNode) x, ctx);
}
+
+ public void endVisit(JAnnotation x, Context ctx) {
+ endVisit((JNode) x, ctx);
+ }
+
+ public void endVisit(JAnnotation.Property x, Context ctx) {
+ endVisit((JNode) x, ctx);
+ }
public void endVisit(JArrayRef x, Context ctx) {
endVisit((JExpression) x, ctx);
@@ -438,6 +446,14 @@
public boolean visit(JAbstractMethodBody x, Context ctx) {
return visit((JNode) x, ctx);
}
+
+ public boolean visit(JAnnotation x, Context ctx) {
+ return visit((JNode) x, ctx);
+ }
+
+ public boolean visit(JAnnotation.Property x, Context ctx) {
+ return visit((JNode) x, ctx);
+ }
public boolean visit(JArrayRef x, Context ctx) {
return visit((JExpression) x, ctx);
@@ -669,11 +685,11 @@
/* NOTE: Skip JFieldRef */
return visit((JVariableRef) x, ctx);
}
-
+
public boolean visit(JsniMethodBody x, Context ctx) {
return visit((JAbstractMethodBody) x, ctx);
}
-
+
public boolean visit(JsniMethodRef x, Context ctx) {
/* NOTE: Skip JMethodRef */
return visit((JExpression) x, ctx);
@@ -690,7 +706,7 @@
public boolean visit(JsonPropInit x, Context ctx) {
return visit((JNode) x, ctx);
}
-
+
public boolean visit(JStatement x, Context ctx) {
return visit((JNode) x, ctx);
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
Tue Jan 26 11:40:29 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
Tue Feb 9 15:22:29 2010
@@ -22,7 +22,10 @@
import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.HasAnnotations;
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
+import com.google.gwt.dev.jjs.ast.JAnnotation;
+import com.google.gwt.dev.jjs.ast.JAnnotationArgument;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
@@ -45,6 +48,7 @@
import com.google.gwt.dev.jjs.ast.JEnumType;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JExpressionStatement;
+import com.google.gwt.dev.jjs.ast.JExternalType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JFloatLiteral;
@@ -86,6 +90,7 @@
import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVariableRef;
import com.google.gwt.dev.jjs.ast.JWhileStatement;
+import com.google.gwt.dev.jjs.ast.JAnnotation.Property;
import com.google.gwt.dev.jjs.ast.JField.Disposition;
import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
@@ -98,6 +103,7 @@
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;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
@@ -169,8 +175,10 @@
import org.eclipse.jdt.internal.compiler.impl.LongConstant;
import org.eclipse.jdt.internal.compiler.impl.ShortConstant;
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.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -372,10 +380,15 @@
*/
public void processType(TypeDeclaration x) {
if (x.binding.isAnnotationType()) {
- // Do not process.
+ // Do not process completely. Use tryGet for binary-only
annotations
+ currentClass = (JDeclaredType) typeMap.tryGet(x.binding);
+ if (currentClass != null) {
+ processHasAnnotations(currentClass, x.annotations);
+ }
return;
}
currentClass = (JDeclaredType) typeMap.get(x.binding);
+ processHasAnnotations(currentClass, x.annotations);
try {
currentClassScope = x.scope;
currentSeparatorPositions =
x.compilationResult.lineSeparatorPositions;
@@ -605,7 +618,10 @@
}
JStringLiteral processConstant(StringConstant x) {
- return
program.getLiteralString(currentMethod.getSourceInfo().makeChild(
+ // May be processing an annotation
+ SourceInfo info = currentMethod == null ?
currentClass.getSourceInfo()
+ : currentMethod.getSourceInfo();
+ return program.getLiteralString(info.makeChild(
JavaASTGenerationVisitor.class, "String literal"),
x.stringValue().toCharArray());
}
@@ -639,6 +655,7 @@
void processConstructor(ConstructorDeclaration x) {
JMethod ctor = (JMethod) typeMap.get(x.binding);
try {
+ processHasAnnotations(ctor, x.annotations);
SourceInfo info = ctor.getSourceInfo();
currentMethod = ctor;
@@ -1423,6 +1440,7 @@
void processField(FieldDeclaration declaration) {
JField field = (JField) typeMap.tryGet(declaration.binding);
+ processHasAnnotations(field, declaration.annotations);
if (field == null) {
/*
* When anonymous classes declare constant fields, the field
declaration
@@ -1469,6 +1487,14 @@
MethodBinding b = x.binding;
JMethod method = (JMethod) typeMap.get(b);
try {
+ processHasAnnotations(method, x.annotations);
+ if (x.arguments != null) {
+ for (int i = 0, j = x.arguments.length; i < j; i++) {
+ JParameter p = (JParameter)
typeMap.get(x.arguments[i].binding);
+ processHasAnnotations(p, x.arguments[i].annotations);
+ }
+ }
+
if (!b.isStatic() && (b.isImplementing() || b.isOverriding())) {
tryFindUpRefs(method, b);
}
@@ -1732,6 +1758,7 @@
JStatement processStatement(LocalDeclaration x) {
SourceInfo info = makeSourceInfo(x);
JLocal local = (JLocal) typeMap.get(x.binding);
+ processHasAnnotations(local, x.annotations);
JLocalRef localRef = new JLocalRef(info, local);
JExpression initializer = dispProcessExpression(x.initialization);
return new JDeclarationStatement(info, localRef, initializer);
@@ -2447,6 +2474,73 @@
}
return variable;
}
+
+ @SuppressWarnings("unchecked")
+ private void processAnnotationProperties(SourceInfo sourceInfo,
+ JAnnotation annotation, ElementValuePair[] elementValuePairs) {
+ if (elementValuePairs == null) {
+ return;
+ }
+
+ for (ElementValuePair pair : elementValuePairs) {
+ String name = CharOperation.charToString(pair.getName());
+ List<JAnnotationArgument> values =
processAnnotationPropertyValue(sourceInfo,
+ pair.getValue());
+ annotation.addValue(new Property(sourceInfo, name, values));
+ }
+ }
+
+ private List<JAnnotationArgument>
processAnnotationPropertyValue(SourceInfo info,
+ Object value) {
+ if (value instanceof TypeBinding) {
+ JType type = (JType) typeMap.tryGet((TypeBinding) value);
+ if (type == null) {
+ // Indicates a binary-only class literal
+ type = program.createExternalType(info,
+ ((ReferenceBinding) value).compoundName);
+ }
+ return Lists.<JAnnotationArgument>
create(program.getLiteralClass(type));
+
+ } else if (value instanceof Constant) {
+ return Lists.create((JAnnotationArgument)
dispatch("processConstant", value));
+
+ } else if (value instanceof Object[]) {
+ Object[] array = (Object[]) value;
+ List<JAnnotationArgument> toReturn = Lists.create();
+ for (int i = 0, j = array.length; i < j; i++) {
+ toReturn = Lists.add(toReturn,
processAnnotationPropertyValue(info,
+ array[i]).get(0));
+ }
+ return toReturn;
+
+ } else if (value instanceof AnnotationBinding) {
+ AnnotationBinding annotationBinding = (AnnotationBinding) value;
+ ReferenceBinding annotationType =
annotationBinding.getAnnotationType();
+ JInterfaceType type = (JInterfaceType)
typeMap.tryGet(annotationType);
+ JAnnotation toReturn;
+ if (type != null) {
+ toReturn = new JAnnotation(info, type);
+ } else {
+ JExternalType external = program.createExternalType(info,
+ annotationType.compoundName);
+ toReturn = new JAnnotation(info, external);
+ }
+
+ // Load the properties for the annotation value
+ processAnnotationProperties(info, toReturn,
+ annotationBinding.getElementValuePairs());
+
+ return Lists.<JAnnotationArgument> create(toReturn);
+ } else if (value instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) value;
+ assert fieldBinding.constant() != null : "Expecting
constant-valued field";
+ return Lists.create((JAnnotationArgument)
dispatch("processConstant",
+ fieldBinding.constant()));
+ }
+
+ throw new InternalCompilerException("Unable to process value "
+ + value.getClass().getName());
+ }
private void processArtificialRescue(Annotation rescue) {
assert rescue != null;
@@ -2587,6 +2681,44 @@
exprArg1, exprArg2);
return binaryOperation;
}
+
+ /**
+ * It is safe to pass a null array.
+ */
+ private <T extends HasAnnotations & HasSourceInfo> void
processHasAnnotations(
+ T x, Annotation[] annotations) {
+ if (annotations == null) {
+ return;
+ }
+
+ for (Annotation a : annotations) {
+ JAnnotation annotation;
+ ReferenceBinding binding = (ReferenceBinding) a.resolvedType;
+ String name = CharOperation.toString(binding.compoundName);
+ boolean record = false;
+ for (String prefix : JProgram.RECORDED_ANNOTATION_PACKAGES) {
+ if (name.startsWith(prefix + ".")) {
+ record = true;
+ break;
+ }
+ }
+ if (!record) {
+ continue;
+ }
+ JInterfaceType annotationType = (JInterfaceType)
typeMap.tryGet(binding);
+ if (annotationType != null) {
+ annotation = new JAnnotation(x.getSourceInfo(), annotationType);
+ } else {
+ // Indicates a binary-only annotation type
+ JExternalType externalType = program.createExternalType(
+ x.getSourceInfo(), binding.compoundName);
+ annotation = new JAnnotation(x.getSourceInfo(), externalType);
+ }
+ processAnnotationProperties(x.getSourceInfo(), annotation,
+ a.computeElementValuePairs());
+ x.addAnnotation(annotation);
+ }
+ }
private JExpression processQualifiedThisOrSuperRef(
QualifiedThisReference x, JClassType qualType) {
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
Fri May 29 15:31:48 2009
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
Tue Feb 9 15:22:29 2010
@@ -23,6 +23,7 @@
import com.google.gwt.dev.jjs.ast.HasName;
import com.google.gwt.dev.jjs.ast.HasType;
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
+import com.google.gwt.dev.jjs.ast.JAnnotation;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
@@ -157,6 +158,34 @@
// nothing to print, parent prints []
return false;
}
+
+ @Override
+ public boolean visit(JAnnotation x, Context ctx) {
+ print('@');
+ print(x.getType().getName());
+ lparen();
+ visitCollectionWithCommas(x.getProperties().iterator());
+ rparen();
+ return false;
+ }
+
+ @Override
+ public boolean visit(JAnnotation.Property x, Context ctx) {
+ print(x.getName());
+ print('=');
+ switch (x.getValues().size()) {
+ case 1:
+ accept(x.getSingleValue().annotationNode());
+ break;
+ case 0:
+ default:
+ print('{');
+ visitCollectionWithCommas(x.getValuesAsNodes().iterator());
+ print('}');
+ break;
+ }
+ return false;
+ }
@Override
public boolean visit(JArrayRef x, Context ctx) {
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
Tue Jan 19 12:32:37 2010
+++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
Tue Feb 9 15:22:29 2010
@@ -22,10 +22,13 @@
import com.google.gwt.dev.javac.impl.MockJavaResource;
import com.google.gwt.dev.javac.impl.MockResourceOracle;
import com.google.gwt.dev.jjs.JavaAstConstructor;
+import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
@@ -63,6 +66,25 @@
JField field = findField(type, fieldName);
return field;
}
+
+ /**
+ * Find a local variable declared within a JMethod.
+ */
+ public static JLocal findLocal(JMethod method, final String localName) {
+ class LocalVisitor extends JVisitor {
+ JLocal found;
+
+ @Override
+ public void endVisit(JLocal x, Context ctx) {
+ if (x.getName().equals(localName)) {
+ found = x;
+ }
+ }
+ }
+ LocalVisitor v = new LocalVisitor();
+ v.accept(method);
+ return v.found;
+ }
public static JMethod findMainMethod(JProgram program) {
return findMethod(program, "onModuleLoad");
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors