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.