Roberto Lublinerman has uploaded a new change for review.

  https://gwt-review.googlesource.com/2320


Change subject: Implemented handling of GwtIncompatible annotations.
......................................................................

Implemented handling of GwtIncompatible annotations.

Any class, method or field that has an annotation of type GwtIncompatible
is ignored by the compiler.

Change-Id: I0f995d107b9e24fb7afb8aca95ab99b35f561216
---
M dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
A dev/core/test/com/google/gwt/dev/javac/GwtIncompatibleJdtTest.java
M user/test/com/google/gwt/dev/jjs/CompilerSuite.java
A user/test/com/google/gwt/dev/jjs/test/GwtIncompatibleTest.java
A user/test/com/google/gwt/dev/jjs/test/gwtincompatible/GwtIncompatible.java
5 files changed, 367 insertions(+), 0 deletions(-)



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 dfc37e0..ea44882 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -34,6 +34,7 @@
 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
 import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
 import org.eclipse.jdt.internal.compiler.ast.Block;
 import org.eclipse.jdt.internal.compiler.ast.Clinit;
@@ -62,8 +63,10 @@
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;

 import java.io.IOException;
 import java.io.InputStream;
@@ -225,6 +228,105 @@
     }
   }

+  /**
+ * ParserImpl intercepts parsing of the source to get rid of methods and fields annotated with
+   * a *.GwtIncompatible annotation.
+   */
+  private class ParserImpl extends Parser {
+ public ParserImpl(ProblemReporter problemReporter, boolean optimizeStringLiterals) {
+      super(problemReporter, optimizeStringLiterals);
+    }
+
+ private boolean hasGwtIncompatibleAnnotation(Annotation[] annotations) {
+      if (annotations == null) {
+        return false;
+      }
+      for (Annotation ann : annotations) {
+        String typeName = new String(ann.type.getLastToken());
+        if (typeName.equals("GwtIncompatible")) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+ private TypeDeclaration[] stripGwtIncompatibleTypes(TypeDeclaration[] types) { + List<TypeDeclaration> newTypeDecls = new ArrayList<TypeDeclaration>();
+      for (TypeDeclaration tyDecl : types) {
+        if (!hasGwtIncompatibleAnnotation(tyDecl.annotations)) {
+          newTypeDecls.add(tyDecl);
+ tyDecl.memberTypes = stripGwtIncompatibleElements(tyDecl.memberTypes);
+        }
+      }
+
+      if (newTypeDecls.size() != types.length) {
+ return newTypeDecls.toArray(new TypeDeclaration[newTypeDecls.size()]);
+      } else {
+        return types;
+      }
+    }
+
+    private void stripGwtIncompatibleMethods(TypeDeclaration[] types) {
+      for (TypeDeclaration tyDecl : types) {
+
+        if (tyDecl.methods == null) {
+          continue;
+        }
+
+ List<AbstractMethodDeclaration> newMethods = new ArrayList<AbstractMethodDeclaration>();
+        for (AbstractMethodDeclaration methodDecl : tyDecl.methods) {
+           if (!hasGwtIncompatibleAnnotation(methodDecl.annotations)) {
+            newMethods.add(methodDecl);
+          }
+        }
+
+        if (newMethods.size() != tyDecl.methods.length) {
+ tyDecl.methods = newMethods.toArray(new AbstractMethodDeclaration[newMethods.size()]);
+        }
+      }
+    }
+
+    private void stripGwtIncompatibleFields(TypeDeclaration[] types) {
+      for (TypeDeclaration tyDecl : types) {
+        if (tyDecl.fields == null) {
+          continue;
+        }
+
+ List<FieldDeclaration> newFields = new ArrayList<FieldDeclaration>();
+        for (FieldDeclaration fieldDecl : tyDecl.fields) {
+          if (!hasGwtIncompatibleAnnotation(fieldDecl.annotations)) {
+            newFields.add(fieldDecl);
+          }
+        }
+
+        if (newFields.size() != tyDecl.fields.length) {
+ tyDecl.fields = newFields.toArray(new FieldDeclaration[newFields.size()]);
+        }
+      }
+    }
+
+ private TypeDeclaration[] stripGwtIncompatibleElements(TypeDeclaration[] types) {
+      if (types == null) {
+        return types;
+      }
+
+      types = stripGwtIncompatibleTypes(types);
+      stripGwtIncompatibleMethods(types);
+      stripGwtIncompatibleFields(types);
+      return types;
+    }
+
+
+    @Override
+    public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit,
+        CompilationResult compilationResult) {
+ CompilationUnitDeclaration decl = super.parse(sourceUnit, compilationResult);
+      decl.types = stripGwtIncompatibleElements(decl.types);
+      return decl;
+    }
+  }
+
+
   private class CompilerImpl extends Compiler {
     private TreeLogger logger;
     private int abortCount = 0;
@@ -249,6 +351,14 @@
       throw abortException;
     }

+
+    @Override
+    public void initializeParser() {
+      this.parser = new ParserImpl(this.problemReporter,
+          this.options.parseLiteralExpressionsAsConstants);
+    }
+
+
     @Override
     public void process(CompilationUnitDeclaration cud, int i) {
       try {
diff --git a/dev/core/test/com/google/gwt/dev/javac/GwtIncompatibleJdtTest.java b/dev/core/test/com/google/gwt/dev/javac/GwtIncompatibleJdtTest.java
new file mode 100644
index 0000000..80c5ac9
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/GwtIncompatibleJdtTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2013 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.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
+import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
+import com.google.gwt.dev.resource.Resource;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Test class for GwtIncompatible annotations in {@link com.google.gwt.dev.javac.JdtCompiler}.
+ */
+public class GwtIncompatibleJdtTest extends TestCase {
+
+  static void assertUnitHasErrors(CompilationUnit unit, int numErrors) {
+    assertTrue(unit.isError());
+    assertEquals(numErrors, unit.getProblems().length);
+  }
+
+  static void assertUnitsCompiled(Collection<CompilationUnit> units) {
+    for (CompilationUnit unit : units) {
+      assertFalse(unit.isError());
+      assertTrue(unit.getCompiledClasses().size() > 0);
+    }
+  }
+
+  public void testCompileError() throws Exception {
+ List<CompilationUnitBuilder> builders = new ArrayList<CompilationUnitBuilder>();
+    addAll(builders, JavaResourceBase.getStandardResources());
+ addAll(builders, GWTINCOMPATIBLE_ANNOTATION, GWTINCOMPATIBLE_METHOD_MISSING_ANNOTATION); + List<CompilationUnit> units = JdtCompiler.compile(TreeLogger.NULL, builders);
+    assertUnitsCompiled(units.subList(0, units.size() - 1));
+    assertUnitHasErrors(units.get(units.size() - 1), 1);
+  }
+
+  public void testCompileGwtIncompatible() throws Exception {
+ List<CompilationUnitBuilder> builders = new ArrayList<CompilationUnitBuilder>();
+    addAll(builders, JavaResourceBase.getStandardResources());
+    addAll(builders, GWTINCOMPATIBLE_ANNOTATION, GWTINCOMPATIBLE_METHOD,
+        GWTINCOMPATIBLE_FIELD, GWTINCOMPATIBLE_INNERCLASS);
+ Collection<CompilationUnit> units = JdtCompiler.compile(TreeLogger.NULL, builders);
+    assertUnitsCompiled(units);
+  }
+
+ public static final MockJavaResource GWTINCOMPATIBLE_ANNOTATION = new MockJavaResource(
+      "com.google.gwt.GwtIncompatible") {
+    @Override
+    public CharSequence getContent() {
+      StringBuilder code = new StringBuilder();
+      code.append("package com.google.gwt;\n");
+      code.append("public @interface GwtIncompatible {\n");
+      code.append("  String[] value();\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+ public static final MockJavaResource GWTINCOMPATIBLE_METHOD_MISSING_ANNOTATION =
+      new MockJavaResource("com.google.gwt.GwtIncompatibleTest") {
+    @Override
+    public CharSequence getContent() {
+      StringBuilder code = new StringBuilder();
+      code.append("package com.google.gwt;\n");
+      code.append("import com.google.gwt.GwtIncompatible;\n");
+      code.append("public class GwtIncompatibleTest {\n");
+      code.append("  int test() { return methodDoesNotExist(); }  \n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+ public static final MockJavaResource GWTINCOMPATIBLE_METHOD = new MockJavaResource(
+      "com.google.gwt.GwtIncompatibleMethodTest") {
+    @Override
+    public CharSequence getContent() {
+      StringBuilder code = new StringBuilder();
+      code.append("package com.google.gwt;\n");
+      code.append("import com.google.gwt.GwtIncompatible;\n");
+      code.append("public class GwtIncompatibleMethodTest {\n");
+      code.append("  @GwtIncompatible(\" not compatible \") \n");
+      code.append("  int test() { return methodDoesNotExist(); }  \n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+ public static final MockJavaResource GWTINCOMPATIBLE_FIELD = new MockJavaResource(
+      "com.google.gwt.GwtIncompatibleFieldTest") {
+    @Override
+    public CharSequence getContent() {
+      StringBuilder code = new StringBuilder();
+      code.append("package com.google.gwt;\n");
+      code.append("import com.google.gwt.GwtIncompatible;\n");
+      code.append("public class GwtIncompatibleFieldTest {\n");
+      code.append("  @GwtIncompatible(\" not compatible \") \n");
+      code.append("  int test = methodDoesNotExist();   \n");
+      code.append("  int test() { return 31; }  \n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+ public static final MockJavaResource GWTINCOMPATIBLE_INNERCLASS = new MockJavaResource(
+      "com.google.gwt.GwtIncompatibleInnerTest") {
+    @Override
+    public CharSequence getContent() {
+      StringBuilder code = new StringBuilder();
+      code.append("package com.google.gwt;\n");
+      code.append("import com.google.gwt.GwtIncompatible;\n");
+      code.append("public class GwtIncompatibleInnerTest {\n");
+      code.append("  @GwtIncompatible(\" not compatible \") \n");
+      code.append("  public class Inner {\n");
+      code.append("    int test() { return methodDoesNotExist(); }  \n");
+      code.append("  }\n");
+      code.append("  int test() { return 31; }  \n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+  private void addAll(Collection<CompilationUnitBuilder> units,
+                      Resource... sourceFiles) {
+    for (Resource sourceFile : sourceFiles) {
+      units.add(CompilationUnitBuilder.create(sourceFile));
+    }
+  }
+
+}
diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
index 59832d8..98d00fb 100644
--- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
+++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
@@ -28,6 +28,7 @@
 import com.google.gwt.dev.jjs.test.EnumsTest;
 import com.google.gwt.dev.jjs.test.EnumsWithNameObfuscationTest;
 import com.google.gwt.dev.jjs.test.GenericCastTest;
+import com.google.gwt.dev.jjs.test.GwtIncompatibleTest;
 import com.google.gwt.dev.jjs.test.HostedTest;
 import com.google.gwt.dev.jjs.test.InitialLoadSequenceTest;
 import com.google.gwt.dev.jjs.test.InnerClassTest;
@@ -75,6 +76,7 @@
     suite.addTestSuite(EnumsTest.class);
     suite.addTestSuite(EnumsWithNameObfuscationTest.class);
     suite.addTestSuite(GenericCastTest.class);
+    suite.addTestSuite(GwtIncompatibleTest.class);
     suite.addTestSuite(HostedTest.class);
     suite.addTestSuite(InitialLoadSequenceTest.class);
     suite.addTestSuite(InnerClassTest.class);
diff --git a/user/test/com/google/gwt/dev/jjs/test/GwtIncompatibleTest.java b/user/test/com/google/gwt/dev/jjs/test/GwtIncompatibleTest.java
new file mode 100644
index 0000000..2d5ed27
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/GwtIncompatibleTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 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.test;
+
+import com.google.gwt.dev.jjs.test.gwtincompatible.GwtIncompatible;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests GwtIncompatible annotations.
+ */
+public class GwtIncompatibleTest extends GWTTestCase {
+
+  /**
+   * Class that uses reflection.
+   */
+  @GwtIncompatible("incompatible")
+  private static class Foo  {
+
+    public int getNbrConstructors() {
+ // getConstructors is not available in the emulated java libraries used in GWT
+      // and it would throw an error
+      return  this.getClass().getConstructors().length;
+    }
+  }
+
+  @GwtIncompatible("incompatible")
+ public int incompatibleField = GwtIncompatibleTest.class.getConstructors().length;
+
+  private static class DummyBar {
+    int getClassFooNbrConstructors() {
+      return -1;
+    }
+  }
+
+  private static class Bar extends DummyBar {
+
+    @GwtIncompatible("incompatible")
+    @Override
+    int getClassFooNbrConstructors() {
+      return new Foo().getNbrConstructors();
+    }
+  }
+
+  public String getModuleName() {
+    return "com.google.gwt.dev.jjs.CompilerSuite";
+  }
+
+  public void testIncompatibleClass() {
+    Bar b = new Bar();
+    assertEquals(-1, b.getClassFooNbrConstructors());
+  }
+}
diff --git a/user/test/com/google/gwt/dev/jjs/test/gwtincompatible/GwtIncompatible.java b/user/test/com/google/gwt/dev/jjs/test/gwtincompatible/GwtIncompatible.java
new file mode 100644
index 0000000..e44eb7a
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/gwtincompatible/GwtIncompatible.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013 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.test.gwtincompatible;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The presence of this annotation on a method indicates that the method may
+ * <em>not</em> be used with the
+ * <a href="http://code.google.com/webtoolkit/";>Google Web Toolkit</a> (GWT).
+ * They can cause GWT compilation errors or simply unexpected exceptions
+ * when used in GWT.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({
+    ElementType.TYPE, ElementType.METHOD,
+    ElementType.CONSTRUCTOR, ElementType.FIELD })
+@Documented
+public @interface GwtIncompatible {
+  /**
+ * Describes why the annotated element is incompatible with GWT. Since this is + * generally due to a dependence on a type/method which GWT doesn't support,
+   * it is sufficient to simply reference the unsupported type/method. E.g.
+   * "Class.isInstance".
+   */
+  String value();
+}

--
To view, visit https://gwt-review.googlesource.com/2320
To unsubscribe, visit https://gwt-review.googlesource.com/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0f995d107b9e24fb7afb8aca95ab99b35f561216
Gerrit-PatchSet: 1
Gerrit-Project: gwt
Gerrit-Branch: master
Gerrit-Owner: Roberto Lublinerman <[email protected]>

--
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors
--- You received this message because you are subscribed to the Google Groups "Google Web Toolkit Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to