Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhsestupin2014-07-31 10:31:36 +0000
committerhsestupin2014-07-31 10:31:36 +0000
commit47465edec8c755fbc22cad0b2bc18569cdbb3a77 (patch)
tree09115d0715666c0cb266117eb57bef5e0d4be6b2
parent70a3e4aab7f2dbf629f02c92b69872ac004bbfcd (diff)
downloadorg.aspectj.shadows-aj_BETA_JAVA8_LUNA_c0f9341.tar.gz
org.aspectj.shadows-aj_BETA_JAVA8_LUNA_c0f9341.tar.xz
org.aspectj.shadows-aj_BETA_JAVA8_LUNA_c0f9341.zip
apt support to jdt.coreaj_BETA_JAVA8_LUNA_c0f9341
Signed-off-by: hsestupin <stupin.sergey@gmail.com>
-rw-r--r--org.eclipse.jdt.core/.classpath1
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AjBatchFilerImpl.java207
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java244
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java61
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java163
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java213
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java173
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java296
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java173
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java77
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java144
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java264
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java47
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java174
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java174
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java239
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java51
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java531
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java265
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java71
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java121
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java154
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java713
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java160
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java116
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java328
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java129
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java878
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java30
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java95
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java88
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java125
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java90
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java275
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java144
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java220
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java83
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java479
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java181
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java68
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Archive.java102
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java222
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java1147
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java205
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java364
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Options.java235
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Util.java207
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptBinaryLocalVariableBinding.java27
-rw-r--r--org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptSourceLocalVariableBinding.java38
-rw-r--r--org.eclipse.jdt.core/aspectj/org/aspectj/ajdt/internal/compiler/CompilerAdapter.aj95
-rw-r--r--org.eclipse.jdt.core/build.xml74
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java6
53 files changed, 10700 insertions, 82 deletions
diff --git a/org.eclipse.jdt.core/.classpath b/org.eclipse.jdt.core/.classpath
index edd5c910..98a3d5b8 100644
--- a/org.eclipse.jdt.core/.classpath
+++ b/org.eclipse.jdt.core/.classpath
@@ -9,6 +9,7 @@
<classpathentry kind="src" path="eval"/>
<classpathentry kind="src" path="formatter"/>
<classpathentry kind="src" path="model"/>
+ <classpathentry kind="src" path="apt"/>
<classpathentry kind="src" path="search"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AjBatchFilerImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AjBatchFilerImpl.java
new file mode 100644
index 00000000..228d3eff
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AjBatchFilerImpl.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Stupin - contributions for adding annotation processing support to ajc
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
+
+import javax.lang.model.element.Element;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import java.io.*;
+import java.net.URI;
+
+/**
+ * @author s.stupin
+ */
+public final class AjBatchFilerImpl extends BatchFilerImpl {
+
+ public AjBatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env) {
+ super(dispatchManager, env);
+ }
+
+ @Override
+
+ public FileObject createResource(JavaFileManager.Location location, CharSequence pkg, CharSequence relativeName, Element... originatingElements) throws IOException {
+ final String name = String.valueOf(relativeName);
+ final FileObject resource = super.createResource(location, pkg, relativeName, originatingElements);
+ return name.endsWith(".aj") ? new HookedFileObject(resource) : resource;
+ }
+
+ private final class HookedFileObject implements FileObject {
+
+ private final FileObject fileObject;
+ private boolean _closed = false;
+
+ HookedFileObject(FileObject fileObject) {
+ this.fileObject = fileObject;
+ }
+
+
+ @Override
+ public URI toUri() {
+ return fileObject.toUri();
+ }
+
+
+ @Override
+ public String getName() {
+ return fileObject.getName();
+ }
+
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return fileObject.openInputStream();
+ }
+
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return new ForwardingOutputStream(fileObject.openOutputStream());
+ }
+
+
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ return fileObject.openReader(ignoreEncodingErrors);
+ }
+
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return fileObject.getCharContent(ignoreEncodingErrors);
+ }
+
+
+ @Override
+ public Writer openWriter() throws IOException {
+ return new ForwardingWriter(fileObject.openWriter());
+ }
+
+ @Override
+ public long getLastModified() {
+ return fileObject.getLastModified();
+ }
+
+ @Override
+ public boolean delete() {
+ return fileObject.delete();
+ }
+
+ private void onClose() {
+ if (_closed)
+ return;
+ _closed = true;
+ final String name = fileObject.getName();
+ final CompilationUnit unit = new CompilationUnit(null, name, null /* encoding */);
+ addNewUnit(unit);
+ }
+
+ private final class ForwardingWriter extends Writer {
+
+ private final Writer writer;
+
+ public ForwardingWriter(Writer writer) {
+ this.writer = writer;
+ }
+
+ @Override
+ public void write(int c) throws IOException {
+ writer.write(c);
+ }
+
+ @Override
+ public void write(char[] cbuf) throws IOException {
+ writer.write(cbuf);
+ }
+
+ @Override
+ public void write(String str) throws IOException {
+ writer.write(str);
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException {
+ writer.write(str, off, len);
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ writer.write(cbuf, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ writer.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ writer.close();
+ onClose();
+ }
+
+
+ @Override
+ public Writer append(CharSequence csq) throws IOException {
+ return writer.append(csq);
+ }
+
+
+ @Override
+ public Writer append(CharSequence csq, int start, int end) throws IOException {
+ return writer.append(csq, start, end);
+ }
+
+
+ @Override
+ public Writer append(char c) throws IOException {
+ return writer.append(c);
+ }
+ }
+
+ private final class ForwardingOutputStream extends OutputStream {
+
+ private final OutputStream stream;
+
+ public ForwardingOutputStream(OutputStream stream) {
+ this.stream = stream;
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ stream.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ stream.write(b, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ stream.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ stream.close();
+ onClose();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ stream.write(b);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java
new file mode 100644
index 00000000..e6157081
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.apt.model.ElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.Factory;
+import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+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.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * This class is used to visit the JDT compiler internal AST to discover annotations,
+ * in the course of dispatching to annotation processors.
+ */
+public class AnnotationDiscoveryVisitor extends ASTVisitor {
+ final BaseProcessingEnvImpl _env;
+ final Factory _factory;
+ /**
+ * Collects a many-to-many map of annotation types to
+ * the elements they appear on.
+ */
+ final ManyToMany<TypeElement, Element> _annoToElement;
+
+ public AnnotationDiscoveryVisitor(BaseProcessingEnvImpl env) {
+ _env = env;
+ _factory = env.getFactory();
+ _annoToElement = new ManyToMany<TypeElement, Element>();
+ }
+
+ @Override
+ public boolean visit(Argument argument, BlockScope scope) {
+ Annotation[] annotations = argument.annotations;
+ ReferenceContext referenceContext = scope.referenceContext();
+ if (referenceContext instanceof AbstractMethodDeclaration) {
+ MethodBinding binding = ((AbstractMethodDeclaration) referenceContext).binding;
+ if (binding != null) {
+ TypeDeclaration typeDeclaration = scope.referenceType();
+ typeDeclaration.binding.resolveTypesFor(binding);
+ if (argument.binding != null) {
+ argument.binding = new AptSourceLocalVariableBinding(argument.binding, binding);
+ }
+ }
+ if (annotations != null) {
+ this.resolveAnnotations(
+ scope,
+ annotations,
+ argument.binding);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
+ Annotation[] annotations = constructorDeclaration.annotations;
+ if (annotations != null) {
+ MethodBinding constructorBinding = constructorDeclaration.binding;
+ if (constructorBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) constructorBinding.declaringClass).resolveTypesFor(constructorBinding);
+ this.resolveAnnotations(
+ constructorDeclaration.scope,
+ annotations,
+ constructorBinding);
+ }
+
+ TypeParameter[] typeParameters = constructorDeclaration.typeParameters;
+ if (typeParameters != null) {
+ int typeParametersLength = typeParameters.length;
+ for (int i = 0; i < typeParametersLength; i++) {
+ typeParameters[i].traverse(this, constructorDeclaration.scope);
+ }
+ }
+
+ Argument[] arguments = constructorDeclaration.arguments;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++) {
+ arguments[i].traverse(this, constructorDeclaration.scope);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
+ Annotation[] annotations = fieldDeclaration.annotations;
+ if (annotations != null) {
+ FieldBinding fieldBinding = fieldDeclaration.binding;
+ if (fieldBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) fieldBinding.declaringClass).resolveTypeFor(fieldBinding);
+ this.resolveAnnotations(scope, annotations, fieldBinding);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(TypeParameter typeParameter, ClassScope scope) {
+ Annotation[] annotations = typeParameter.annotations;
+ if (annotations != null) {
+ TypeVariableBinding binding = typeParameter.binding;
+ if (binding == null) {
+ return false;
+ }
+ this.resolveAnnotations(scope.referenceContext.initializerScope, annotations, binding);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(TypeParameter typeParameter, BlockScope scope) {
+ Annotation[] annotations = typeParameter.annotations;
+ if (annotations != null) {
+ TypeVariableBinding binding = typeParameter.binding;
+ if (binding == null) {
+ return false;
+ }
+ // when we get here, it is guaranteed that class type parameters are connected, but method type parameters may not be.
+ MethodBinding methodBinding = (MethodBinding) binding.declaringElement;
+ ((SourceTypeBinding) methodBinding.declaringClass).resolveTypesFor(methodBinding);
+ this.resolveAnnotations(scope, annotations, binding);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
+ Annotation[] annotations = methodDeclaration.annotations;
+ if (annotations != null) {
+ MethodBinding methodBinding = methodDeclaration.binding;
+ if (methodBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) methodBinding.declaringClass).resolveTypesFor(methodBinding);
+ this.resolveAnnotations(
+ methodDeclaration.scope,
+ annotations,
+ methodBinding);
+ }
+
+ TypeParameter[] typeParameters = methodDeclaration.typeParameters;
+ if (typeParameters != null) {
+ int typeParametersLength = typeParameters.length;
+ for (int i = 0; i < typeParametersLength; i++) {
+ typeParameters[i].traverse(this, methodDeclaration.scope);
+ }
+ }
+
+ Argument[] arguments = methodDeclaration.arguments;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++) {
+ arguments[i].traverse(this, methodDeclaration.scope);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
+ SourceTypeBinding binding = memberTypeDeclaration.binding;
+ if (binding == null) {
+ return false;
+ }
+ Annotation[] annotations = memberTypeDeclaration.annotations;
+ if (annotations != null) {
+ this.resolveAnnotations(
+ memberTypeDeclaration.staticInitializerScope,
+ annotations,
+ binding);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
+ SourceTypeBinding binding = typeDeclaration.binding;
+ if (binding == null) {
+ return false;
+ }
+ Annotation[] annotations = typeDeclaration.annotations;
+ if (annotations != null) {
+ this.resolveAnnotations(
+ typeDeclaration.staticInitializerScope,
+ annotations,
+ binding);
+ }
+ return true;
+ }
+
+ private void resolveAnnotations(BlockScope scope, Annotation[] annotations, Binding currentBinding) {
+
+ int length = annotations == null ? 0 : annotations.length;
+ if (length == 0)
+ return;
+
+ boolean old = scope.insideTypeAnnotation;
+ scope.insideTypeAnnotation = true;
+ ASTNode.resolveAnnotations(scope, annotations, currentBinding);
+ scope.insideTypeAnnotation = old;
+ ElementImpl element = (ElementImpl) _factory.newElement(currentBinding);
+ AnnotationBinding [] annotationBindings = element.getPackedAnnotationBindings(); // discovery is never in terms of repeating annotation.
+ for (AnnotationBinding binding : annotationBindings) {
+ if (binding != null) { // binding should be resolved, but in case it's not, ignore it: it could have been wrapped into a container.
+ TypeElement anno = (TypeElement)_factory.newElement(binding.getAnnotationType());
+ _annoToElement.put(anno, element);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java
new file mode 100644
index 00000000..5bac3d5a
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Sergey Stupin - contributions for adding annotation processing support to ajc
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
+
+public class AptProblem extends DefaultProblem {
+
+ // The batch compiler does not depend on org.eclipse.jdt.apt.pluggable.core; this
+ // is just an arbitrary string to it, namespace notwithstanding. However, the IDE
+ // cares about the fact that this string is registered as a marker ID by the
+ // org.eclipse.jdt.apt.pluggable.core plug-in.
+ private static final String MARKER_ID = "org.eclipse.jdt.apt.pluggable.core.compileProblem"; //$NON-NLS-1$
+
+ /** May be null, if it was not possible to identify problem context */
+ public final ReferenceContext _referenceContext;
+
+ public AptProblem(
+ ReferenceContext referenceContext,
+ char[] originatingFileName,
+ String message,
+ int id,
+ String[] stringArguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int line,
+ int column)
+ {
+ super(originatingFileName,
+ message,
+ id,
+ stringArguments,
+ severity,
+ startPosition,
+ endPosition,
+ line,
+ column);
+ _referenceContext = referenceContext;
+ }
+
+ @Override
+ public int getCategoryID() {
+ return CAT_UNSPECIFIED;
+ }
+
+ @Override
+ public String getMarkerType() {
+ return MARKER_ID;
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java
new file mode 100644
index 00000000..5eb45c53
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * This class is the central dispatch point for Java 6 annotation processing.
+ * This is created and configured by the JDT core; specifics depend on how
+ * compilation is being performed, ie from the command line, via the Tool
+ * interface, or within the IDE. This class manages the discovery of annotation
+ * processors and other information spanning multiple rounds of processing;
+ * context that is valid only within a single round is managed by
+ * {@link RoundDispatcher}. There may be multiple instances of this class;
+ * there is in general one of these for every Compiler that has annotation
+ * processing enabled. Within the IDE there will typically be one for every
+ * Java project, because each project potentially has a separate processor path.
+ *
+ * TODO: do something useful with _supportedOptions and _supportedAnnotationTypes.
+ */
+public abstract class BaseAnnotationProcessorManager extends AbstractAnnotationProcessorManager
+ implements IProcessorProvider
+{
+
+ protected PrintWriter _out;
+ protected PrintWriter _err;
+ protected BaseProcessingEnvImpl _processingEnv;
+ protected boolean _isFirstRound = true;
+
+ /**
+ * The list of processors that have been loaded so far. A processor on this
+ * list has been initialized, but may not yet have been called to process().
+ */
+ protected List<ProcessorInfo> _processors = new ArrayList<ProcessorInfo>();
+
+ // Tracing
+ protected boolean _printProcessorInfo = false;
+ protected boolean _printRounds = false;
+ protected int _round;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configure(org.eclipse.jdt.internal.compiler.batch.Main, java.lang.String[])
+ */
+ @Override
+ public void configure(Object batchCompiler, String[] options) {
+ // Implemented by BatchAnnotationProcessorManager.
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configureFromPlatform(org.eclipse.jdt.internal.compiler.Compiler, java.lang.Object)
+ */
+ @Override
+ public void configureFromPlatform(Compiler compiler, Object compilationUnitLocator, Object javaProject) {
+ // Implemented by IdeAnnotationProcessorManager.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<ProcessorInfo> getDiscoveredProcessors() {
+ return _processors;
+ }
+
+ @Override
+ public ICompilationUnit[] getDeletedUnits() {
+ return _processingEnv.getDeletedUnits();
+ }
+
+ @Override
+ public ICompilationUnit[] getNewUnits() {
+ return _processingEnv.getNewUnits();
+ }
+
+ @Override
+ public ReferenceBinding[] getNewClassFiles() {
+ return _processingEnv.getNewClassFiles();
+ }
+
+ @Override
+ public void reset() {
+ _processingEnv.reset();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setErr(java.io.PrintWriter)
+ */
+ @Override
+ public void setErr(PrintWriter err) {
+ _err = err;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setOut(java.io.PrintWriter)
+ */
+ @Override
+ public void setOut(PrintWriter out) {
+ _out = out;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setProcessors(java.lang.Object[])
+ */
+ @Override
+ public void setProcessors(Object[] processors) {
+ // Only meaningful in batch mode.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * A single "round" of processing, in the sense implied in
+ * {@link javax.annotation.processing.Processor}.
+ * <p>
+ * The Java 6 Processor spec contains ambiguities about how processors that support "*" are
+ * handled. Eclipse tries to match Sun's implementation in javac. What that actually does is
+ * analogous to inspecting the set of annotions found in the root units and adding an
+ * "imaginary" annotation if the set is empty. Processors are then called in order of discovery;
+ * for each processor, the intersection between the set of root annotations and the set of
+ * annotations the processor supports is calculated, and if it is non-empty, the processor is
+ * called. If the processor returns <code>true</code> then the intersection (including the
+ * imaginary annotation if one exists) is removed from the set of root annotations and the loop
+ * continues, until the set is empty. Of course, the imaginary annotation is not actually
+ * included in the set of annotations passed in to the processor. A processor's process() method
+ * is not called until its intersection set is non-empty, but thereafter it is called on every
+ * round. Note that even if a processor is not called in the first round, if it is called in
+ * subsequent rounds, it will be called in the order in which the processors were discovered,
+ * rather than being added to the end of the list.
+ */
+ @Override
+ public void processAnnotations(CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound) {
+ RoundEnvImpl roundEnv = new RoundEnvImpl(units, referenceBindings, isLastRound, _processingEnv);
+ if (_isFirstRound) {
+ _isFirstRound = false;
+ }
+
+ PrintWriter traceProcessorInfo = _printProcessorInfo ? _out : null;
+ PrintWriter traceRounds = _printRounds ? _out : null;
+ if (traceRounds != null) {
+ traceRounds.println("Round " + ++_round + ':'); //$NON-NLS-1$
+ }
+ RoundDispatcher dispatcher = new RoundDispatcher(
+ this, roundEnv, roundEnv.getRootAnnotations(), traceProcessorInfo, traceRounds);
+ dispatcher.round();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
new file mode 100644
index 00000000..1b828f55
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - derived base class from BatchMessagerImpl
+ *
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic.Kind;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.apt.model.AnnotationMemberValue;
+import org.eclipse.jdt.internal.compiler.apt.model.AnnotationMirrorImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.ExecutableElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.VariableElementImpl;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+import org.eclipse.jdt.internal.compiler.util.Util;
+
+public class BaseMessagerImpl {
+
+ static final String[] NO_ARGUMENTS = new String[0];
+
+ /**
+ * Create a CategorizedProblem that can be reported to an ICompilerRequestor, etc.
+ *
+ * @param e the element against which to report the message. If the element is not
+ * in the set of elements being compiled in the current round, the reference context
+ * and filename will be set to null.
+ * @return
+ */
+ public static AptProblem createProblem(Kind kind, CharSequence msg, Element e,
+ AnnotationMirror a, AnnotationValue v) {
+ ReferenceContext referenceContext = null;
+ Annotation[] elementAnnotations = null;
+ int startPosition = 0;
+ int endPosition = 0;
+ if (e != null) {
+ switch(e.getKind()) {
+ case ANNOTATION_TYPE :
+ case INTERFACE :
+ case CLASS :
+ case ENUM :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) e;
+ Binding typeBinding = typeElementImpl._binding;
+ if (typeBinding instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) typeBinding;
+ TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext();
+ referenceContext = typeDeclaration;
+ elementAnnotations = typeDeclaration.annotations;
+ startPosition = typeDeclaration.sourceStart;
+ endPosition = typeDeclaration.sourceEnd;
+ }
+ break;
+ case PACKAGE :
+ // nothing to do: there is no reference context for a package
+ break;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e;
+ Binding binding = executableElementImpl._binding;
+ if (binding instanceof MethodBinding) {
+ MethodBinding methodBinding = (MethodBinding) binding;
+ AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod();
+ if (sourceMethod != null) {
+ referenceContext = sourceMethod;
+ elementAnnotations = sourceMethod.annotations;
+ startPosition = sourceMethod.sourceStart;
+ endPosition = sourceMethod.sourceEnd;
+ }
+ }
+ break;
+ case ENUM_CONSTANT :
+ break;
+ case EXCEPTION_PARAMETER :
+ break;
+ case FIELD :
+ case PARAMETER :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) e;
+ binding = variableElementImpl._binding;
+ if (binding instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ FieldDeclaration fieldDeclaration = fieldBinding.sourceField();
+ if (fieldDeclaration != null) {
+ ReferenceBinding declaringClass = fieldBinding.declaringClass;
+ if (declaringClass instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) declaringClass;
+ TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext();
+ referenceContext = typeDeclaration;
+ }
+ elementAnnotations = fieldDeclaration.annotations;
+ startPosition = fieldDeclaration.sourceStart;
+ endPosition = fieldDeclaration.sourceEnd;
+ }
+ } else if (binding instanceof AptSourceLocalVariableBinding){
+ AptSourceLocalVariableBinding parameterBinding = (AptSourceLocalVariableBinding) binding;
+ LocalDeclaration parameterDeclaration = parameterBinding.declaration;
+ if (parameterDeclaration != null) {
+ MethodBinding methodBinding = parameterBinding.methodBinding;
+ if (methodBinding != null) {
+ referenceContext = methodBinding.sourceMethod();
+ }
+ elementAnnotations = parameterDeclaration.annotations;
+ startPosition = parameterDeclaration.sourceStart;
+ endPosition = parameterDeclaration.sourceEnd;
+ }
+ }
+ break;
+ case INSTANCE_INIT :
+ case STATIC_INIT :
+ break;
+ case LOCAL_VARIABLE :
+ break;
+ case TYPE_PARAMETER :
+ default:
+ break;
+ }
+ }
+ StringBuilder builder = new StringBuilder();
+ if (msg != null) {
+ builder.append(msg);
+ }
+ if (a != null && elementAnnotations != null) {
+ AnnotationBinding annotationBinding = ((AnnotationMirrorImpl) a)._binding;
+ Annotation annotation = null;
+ for (int i = 0; annotation == null && i < elementAnnotations.length; i++) {
+ if (annotationBinding == elementAnnotations[i].getCompilerAnnotation()) {
+ annotation = elementAnnotations[i];
+ }
+ }
+ if (annotation != null) {
+ startPosition = annotation.sourceStart;
+ endPosition = annotation.sourceEnd;
+ if (v != null && v instanceof AnnotationMemberValue) {
+ MethodBinding methodBinding = ((AnnotationMemberValue) v).getMethodBinding();
+ MemberValuePair[] memberValuePairs = annotation.memberValuePairs();
+ MemberValuePair memberValuePair = null;
+ for (int i = 0; memberValuePair == null && i < memberValuePairs.length; i++) {
+ if (methodBinding == memberValuePairs[i].binding) {
+ memberValuePair = memberValuePairs[i];
+ }
+ }
+ if (memberValuePair != null) {
+ startPosition = memberValuePair.sourceStart;
+ endPosition = memberValuePair.sourceEnd;
+ }
+ }
+ }
+ }
+ int lineNumber = 0;
+ int columnNumber = 1;
+ char[] fileName = null;
+ if (referenceContext != null) {
+ CompilationResult result = referenceContext.compilationResult();
+ fileName = result.fileName;
+ int[] lineEnds = null;
+ lineNumber = startPosition >= 0
+ ? Util.getLineNumber(startPosition, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1)
+ : 0;
+ columnNumber = startPosition >= 0
+ ? Util.searchColumnNumber(result.getLineSeparatorPositions(), lineNumber,startPosition)
+ : 0;
+ }
+ int severity;
+ switch(kind) {
+ case ERROR :
+ severity = ProblemSeverities.Error;
+ break;
+ default :
+ // There is no "INFO" equivalent in JDT
+ severity = ProblemSeverities.Warning;
+ break;
+ }
+ return new AptProblem(
+ referenceContext,
+ fileName,
+ String.valueOf(builder),
+ 0,
+ NO_ARGUMENTS,
+ severity,
+ startPosition,
+ endPosition,
+ lineNumber,
+ columnNumber);
+ }
+
+ public BaseMessagerImpl() {
+ super();
+ }
+
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
new file mode 100644
index 00000000..e4e1fdd3
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.apt.model.ElementsImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.Factory;
+import org.eclipse.jdt.internal.compiler.apt.model.TypesImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Implementation of ProcessingEnvironment that is common to batch and IDE environments.
+ */
+public abstract class BaseProcessingEnvImpl implements ProcessingEnvironment {
+
+ // Initialized in subclasses:
+ protected Filer _filer;
+ protected Messager _messager;
+ protected Map<String, String> _processorOptions;
+ protected Compiler _compiler;
+
+ // Initialized in this base class:
+ protected Elements _elementUtils;
+ protected Types _typeUtils;
+ private List<ICompilationUnit> _addedUnits;
+ private List<ReferenceBinding> _addedClassFiles;
+ private List<ICompilationUnit> _deletedUnits;
+ private boolean _errorRaised;
+ private Factory _factory;
+
+ public BaseProcessingEnvImpl() {
+ _addedUnits = new ArrayList<ICompilationUnit>();
+ _addedClassFiles = new ArrayList<ReferenceBinding>();
+ _deletedUnits = new ArrayList<ICompilationUnit>();
+ _elementUtils = new ElementsImpl(this);
+ _typeUtils = new TypesImpl(this);
+ _factory = new Factory(this);
+ _errorRaised = false;
+ }
+
+ public void addNewUnit(ICompilationUnit unit) {
+ _addedUnits.add(unit);
+ }
+
+ public void addNewClassFile(ReferenceBinding binding) {
+ _addedClassFiles.add(binding);
+ }
+
+ public Compiler getCompiler() {
+ return _compiler;
+ }
+
+ public ICompilationUnit[] getDeletedUnits() {
+ ICompilationUnit[] result = new ICompilationUnit[_deletedUnits.size()];
+ _deletedUnits.toArray(result);
+ return result;
+ }
+
+ public ICompilationUnit[] getNewUnits() {
+ ICompilationUnit[] result = new ICompilationUnit[_addedUnits.size()];
+ _addedUnits.toArray(result);
+ return result;
+ }
+
+ @Override
+ public Elements getElementUtils() {
+ return _elementUtils;
+ }
+
+ @Override
+ public Filer getFiler() {
+ return _filer;
+ }
+
+ @Override
+ public Messager getMessager() {
+ return _messager;
+ }
+
+ @Override
+ public Map<String, String> getOptions() {
+ return _processorOptions;
+ }
+
+ @Override
+ public Types getTypeUtils() {
+ return _typeUtils;
+ }
+
+ public LookupEnvironment getLookupEnvironment() {
+ return _compiler.lookupEnvironment;
+ }
+
+ @Override
+ public SourceVersion getSourceVersion() {
+ if (this._compiler.options.sourceLevel <= ClassFileConstants.JDK1_5) {
+ return SourceVersion.RELEASE_5;
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK1_6) {
+ return SourceVersion.RELEASE_6;
+ }
+ try {
+ return SourceVersion.valueOf("RELEASE_7"); //$NON-NLS-1$
+ } catch(IllegalArgumentException e) {
+ // handle call on a JDK 6
+ return SourceVersion.RELEASE_6;
+ }
+ }
+
+ /**
+ * Called when AnnotationProcessorManager has retrieved the list of
+ * newly generated compilation units (ie, once per round)
+ */
+ public void reset() {
+ _addedUnits.clear();
+ _addedClassFiles.clear();
+ _deletedUnits.clear();
+ }
+
+ /**
+ * Has an error been raised in any of the rounds of processing in this build?
+ * @return
+ */
+ public boolean errorRaised()
+ {
+ return _errorRaised;
+ }
+
+ /**
+ * Set or clear the errorRaised flag. Typically this will be set by the Messager
+ * when an error has been raised, and it will never be cleared.
+ */
+ public void setErrorRaised(boolean b)
+ {
+ _errorRaised = true;
+ }
+
+ public Factory getFactory()
+ {
+ return _factory;
+ }
+
+ public ReferenceBinding[] getNewClassFiles() {
+ ReferenceBinding[] result = new ReferenceBinding[_addedClassFiles.size()];
+ _addedClassFiles.toArray(result);
+ return result;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
new file mode 100644
index 00000000..bc225c26
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+import javax.annotation.processing.Processor;
+import javax.tools.StandardLocation;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * Java 6 annotation processor manager used when compiling from the command line
+ * or via the javax.tools.JavaCompiler interface.
+ *
+ * @see org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeAnnotationProcessorManager
+ */
+public class BatchAnnotationProcessorManager extends BaseAnnotationProcessorManager {
+
+ /**
+ * Processors that have been set by calling CompilationTask.setProcessors().
+ */
+ private List<Processor> _setProcessors = null;
+ private Iterator<Processor> _setProcessorIter = null;
+
+ /**
+ * Processors named with the -processor option on the command line.
+ */
+ private List<String> _commandLineProcessors;
+ private Iterator<String> _commandLineProcessorIter = null;
+
+ private ServiceLoader<Processor> _serviceLoader = null;
+ private Iterator<Processor> _serviceLoaderIter;
+
+ private ClassLoader _procLoader;
+
+ // Set this to true in order to trace processor discovery when -XprintProcessorInfo is specified
+ private final static boolean VERBOSE_PROCESSOR_DISCOVERY = true;
+ private boolean _printProcessorDiscovery = false;
+
+ /**
+ * Zero-arg constructor so this object can be easily created via reflection.
+ * A BatchAnnotationProcessorManager cannot be used until its
+ * {@link #configure(Object, String[])} method has been called.
+ */
+ public BatchAnnotationProcessorManager() {
+ }
+
+ @Override
+ public void configure(Object batchCompiler, String[] commandLineArguments) {
+ if (null != _processingEnv) {
+ throw new IllegalStateException(
+ "Calling configure() more than once on an AnnotationProcessorManager is not supported"); //$NON-NLS-1$
+ }
+ BatchProcessingEnvImpl processingEnv = new BatchProcessingEnvImpl(this, (Main) batchCompiler, commandLineArguments);
+ _processingEnv = processingEnv;
+ _procLoader = processingEnv.getFileManager().getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH);
+ parseCommandLine(commandLineArguments);
+ _round = 0;
+ }
+
+ /**
+ * If a -processor option was specified in command line arguments,
+ * parse it into a list of qualified classnames.
+ *
+ * @param commandLineArguments contains one string for every space-delimited token on the command line
+ */
+ private void parseCommandLine(String[] commandLineArguments) {
+ List<String> commandLineProcessors = null;
+ for (int i = 0; i < commandLineArguments.length; ++i) {
+ String option = commandLineArguments[i];
+ if ("-XprintProcessorInfo".equals(option)) { //$NON-NLS-1$
+ _printProcessorInfo = true;
+ _printProcessorDiscovery = VERBOSE_PROCESSOR_DISCOVERY;
+ } else if ("-XprintRounds".equals(option)) { //$NON-NLS-1$
+ _printRounds = true;
+ } else if ("-processor".equals(option)) { //$NON-NLS-1$
+ commandLineProcessors = new ArrayList<String>();
+ String procs = commandLineArguments[++i];
+ for (String proc : procs.split(",")) { //$NON-NLS-1$
+ commandLineProcessors.add(proc);
+ }
+ break;
+ }
+ }
+ _commandLineProcessors = commandLineProcessors;
+ if (null != _commandLineProcessors) {
+ _commandLineProcessorIter = _commandLineProcessors.iterator();
+ }
+ }
+
+ @Override
+ public ProcessorInfo discoverNextProcessor() {
+ try {
+ if (null != _setProcessors) {
+ // If setProcessors() was called, use that list until it's empty and then stop.
+ if (_setProcessorIter.hasNext()) {
+ Processor p = _setProcessorIter.next();
+ p.init(_processingEnv);
+ ProcessorInfo pi = new ProcessorInfo(p);
+ _processors.add(pi);
+ if (_printProcessorDiscovery && null != _out) {
+ _out.println("API specified processor: " + pi); //$NON-NLS-1$
+ }
+ return pi;
+ }
+ return null;
+ }
+
+ if (null != _commandLineProcessors) {
+ // If there was a -processor option, iterate over processor names,
+ // creating and initializing processors, until no more names are found, then stop.
+ if (_commandLineProcessorIter.hasNext()) {
+ String proc = _commandLineProcessorIter.next();
+ try {
+ Class<?> clazz = _procLoader.loadClass(proc);
+ Object o = clazz.newInstance();
+ Processor p = (Processor) o;
+ p.init(_processingEnv);
+ ProcessorInfo pi = new ProcessorInfo(p);
+ _processors.add(pi);
+ if (_printProcessorDiscovery && null != _out) {
+ _out.println("Command line specified processor: " + pi); //$NON-NLS-1$
+ }
+ return pi;
+ } catch (Exception e) {
+ // TODO: better error handling
+ throw new AbortCompilation(null, e);
+ }
+ }
+ return null;
+ }
+ // if no processors were explicitly specified with setProcessors()
+ // or the command line, search the processor path with ServiceLoader.
+ String resPath = "META-INF/services/" + Processor.class.getName();
+ Enumeration<URL> resources = _procLoader.getResources(resPath);
+ if (resources != null) {
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ parse(url);
+ }
+ }
+ if (null == _serviceLoader) {
+ _serviceLoader = ServiceLoader.load(Processor.class, _procLoader);
+ _serviceLoaderIter = _serviceLoader.iterator();
+ }
+ try {
+ if (_serviceLoaderIter.hasNext()) {
+ Processor p = _serviceLoaderIter.next();
+ p.init(_processingEnv);
+ ProcessorInfo pi = new ProcessorInfo(p);
+ _processors.add(pi);
+ if (_printProcessorDiscovery && null != _out) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Discovered processor service "); //$NON-NLS-1$
+ sb.append(pi);
+ sb.append("\n supporting "); //$NON-NLS-1$
+ sb.append(pi.getSupportedAnnotationTypesAsString());
+ sb.append("\n in "); //$NON-NLS-1$
+ sb.append(getProcessorLocation(p));
+ _out.println(sb.toString());
+ }
+ return pi;
+ }
+ } catch (ServiceConfigurationError e) {
+ // TODO: better error handling
+ throw new AbortCompilation(null, e);
+ }
+ } catch (Throwable e) {
+ throw new IllegalStateException(e);
+ }
+ return null;
+ }
+
+ private Iterator<String> parse(URL u)
+ throws ServiceConfigurationError, IOException {
+ InputStream in = null;
+ BufferedReader r = null;
+ ArrayList<String> names = new ArrayList<String>();
+ try {
+ in = u.openStream();
+ r = new BufferedReader(new InputStreamReader(in, "utf-8"));
+ int lc = 1;
+ while ((lc = parseLine(r, lc, names)) >= 0) ;
+ } catch (IOException x) {
+ throw new IllegalStateException("Error reading configuration file", x);
+ } finally {
+ try {
+ if (r != null) r.close();
+ if (in != null) in.close();
+ } catch (IOException y) {
+ throw new IllegalStateException("Error closing configuration file", y);
+ }
+ }
+ return names.iterator();
+ }
+
+ private int parseLine(BufferedReader r, int lc, List<String> names)
+ throws IOException, ServiceConfigurationError {
+ String ln = r.readLine();
+ if (ln == null) {
+ return -1;
+ }
+ int ci = ln.indexOf('#');
+ if (ci >= 0) ln = ln.substring(0, ci);
+ ln = ln.trim();
+ int n = ln.length();
+ if (n != 0) {
+ if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+ throw new IllegalStateException("Illegal configuration-file syntax");
+ int cp = ln.codePointAt(0);
+ if (!Character.isJavaIdentifierStart(cp))
+ throw new IllegalStateException("Illegal provider-class name: " + ln);
+ for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
+ cp = ln.codePointAt(i);
+ if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+ throw new IllegalStateException("Illegal provider-class name: " + ln);
+ }
+ if (!names.contains(ln))
+ names.add(ln);
+ }
+ return lc + 1;
+ }
+
+ /**
+ * Used only for debugging purposes. Generates output like "file:jar:D:/temp/jarfiles/myJar.jar!/".
+ * Surely this code already exists in several hundred other places?
+ *
+ * @return the location whence a processor class was loaded.
+ */
+ private String getProcessorLocation(Processor p) {
+ // Get the classname in a form that can be passed to ClassLoader.getResource(),
+ // e.g., "pa/pb/pc/Outer$Inner.class"
+ boolean isMember = false;
+ Class<?> outerClass = p.getClass();
+ StringBuilder innerName = new StringBuilder();
+ while (outerClass.isMemberClass()) {
+ innerName.insert(0, outerClass.getSimpleName());
+ innerName.insert(0, '$');
+ isMember = true;
+ outerClass = outerClass.getEnclosingClass();
+ }
+ String path = outerClass.getName();
+ path = path.replace('.', '/');
+ if (isMember) {
+ path = path + innerName;
+ }
+ path = path + ".class"; //$NON-NLS-1$
+
+ // Find the URL for the class resource and strip off the resource name itself
+ String location = _procLoader.getResource(path).toString();
+ if (location.endsWith(path)) {
+ location = location.substring(0, location.length() - path.length());
+ }
+ return location;
+ }
+
+ @Override
+ public void reportProcessorException(Processor p, Exception e) {
+ // TODO: if (verbose) report the processor
+ throw new AbortCompilation(null, e);
+ }
+
+ @Override
+ public void setProcessors(Object[] processors) {
+ if (!_isFirstRound) {
+ throw new IllegalStateException("setProcessors() cannot be called after processing has begun"); //$NON-NLS-1$
+ }
+ // Cast all the processors here, rather than failing later.
+ // But don't call init() until the processor is actually needed.
+ _setProcessors = new ArrayList<Processor>(processors.length);
+ for (Object o : processors) {
+ Processor p = (Processor) o;
+ _setProcessors.add(p);
+ }
+ _setProcessorIter = _setProcessors.iterator();
+
+ // processors set this way take precedence over anything on the command line
+ _commandLineProcessors = null;
+ _commandLineProcessorIter = null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java
new file mode 100644
index 00000000..cd7a1960
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * philippe.marschall@netcetera.ch - Fix for 338370
+ * IBM Corporation - Fix for validating relative name
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.FilerException;
+import javax.lang.model.element.Element;
+import javax.tools.*;
+import javax.tools.JavaFileManager.Location;
+
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Implementation of Filer used when compilation is driven by command line
+ * or by Tool interface. This version does not need to keep track of
+ * dependencies.
+ */
+public class BatchFilerImpl implements Filer {
+
+ protected final BaseAnnotationProcessorManager _dispatchManager;
+ protected final BaseProcessingEnvImpl _env;
+ protected final JavaFileManager _fileManager;
+ protected final HashSet<URI> _createdFiles;
+
+ public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env)
+ {
+ _dispatchManager = dispatchManager;
+ _fileManager = env._fileManager;
+ _env = env;
+ _createdFiles = new HashSet<URI>();
+ }
+
+ public void addNewUnit(ICompilationUnit unit) {
+ _env.addNewUnit(unit);
+ }
+
+ public void addNewClassFile(ReferenceBinding binding) {
+ _env.addNewClassFile(binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#createClassFile(java.lang.CharSequence, javax.lang.model.element.Element[])
+ */
+ @Override
+ public JavaFileObject createClassFile(CharSequence name,
+ Element... originatingElements) throws IOException {
+ JavaFileObject jfo = _fileManager.getJavaFileForOutput(
+ StandardLocation.CLASS_OUTPUT, name.toString(), JavaFileObject.Kind.CLASS, null);
+ URI uri = jfo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("Class file already created : " + name); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#createResource(javax.tools.JavaFileManager.Location, java.lang.CharSequence, java.lang.CharSequence, javax.lang.model.element.Element[])
+ */
+ @Override
+ public FileObject createResource(Location location, CharSequence pkg,
+ CharSequence relativeName, Element... originatingElements)
+ throws IOException {
+ validateName(relativeName);
+ FileObject fo = _fileManager.getFileForOutput(
+ location, pkg.toString(), relativeName.toString(), null);
+ URI uri = fo.toUri();
+ if (_createdFiles.contains(uri)) {
+ Iterator<URI> it = _createdFiles.iterator();
+ StringBuilder sb = new StringBuilder("\n----\n");
+ while (it.hasNext()) {
+ URI next = it.next();
+ sb.append(next).append("\n");
+ }
+ throw new FilerException("createResource. Resource already created : " + location + '/' + pkg + '/' + relativeName + " --- uri = " + uri + sb.toString()); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ return fo;
+ }
+
+ private static void validateName(CharSequence relativeName) {
+ int length = relativeName.length();
+ if (length == 0) {
+ throw new IllegalArgumentException("relative path cannot be empty"); //$NON-NLS-1$
+ }
+ String path = relativeName.toString();
+ if (path.indexOf('\\') != -1) {
+ // normalize the path with '/'
+ path = path.replace('\\', '/');
+ }
+ if (path.charAt(0) == '/') {
+ throw new IllegalArgumentException("relative path is absolute"); //$NON-NLS-1$
+ }
+ boolean hasDot = false;
+ for (int i = 0; i < length; i++) {
+ switch(path.charAt(i)) {
+ case '/' :
+ if (hasDot) {
+ throw new IllegalArgumentException("relative name " + relativeName + " is not relative"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ break;
+ case '.' :
+ hasDot = true;
+ break;
+ default:
+ hasDot = false;
+ }
+ }
+ if (hasDot) {
+ throw new IllegalArgumentException("relative name " + relativeName + " is not relative"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#createSourceFile(java.lang.CharSequence, javax.lang.model.element.Element[])
+ */
+ @Override
+ public JavaFileObject createSourceFile(CharSequence name,
+ Element... originatingElements) throws IOException {
+ JavaFileObject jfo = _fileManager.getJavaFileForOutput(
+ StandardLocation.SOURCE_OUTPUT, name.toString(), JavaFileObject.Kind.SOURCE, null);
+ URI uri = jfo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("Source file already created : " + name); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ // hook the file object's writers to create compilation unit and add to addedUnits()
+ return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#getResource(javax.tools.JavaFileManager.Location, java.lang.CharSequence, java.lang.CharSequence)
+ */
+ @Override
+ public FileObject getResource(Location location, CharSequence pkg,
+ CharSequence relativeName) throws IOException {
+ validateName(relativeName);
+ FileObject fo = _fileManager.getFileForInput(
+ location, pkg.toString(), relativeName.toString());
+ if (fo == null) {
+ throw new FileNotFoundException("Resource does not exist : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$
+ }
+ URI uri = fo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("getResource. Resource already created : " + location + '/' + pkg + '/' + relativeName + " --- uri = " + uri); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ return fo;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java
new file mode 100644
index 00000000..7d971d16
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2009 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic.Kind;
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.internal.compiler.batch.Main;
+
+/**
+ * An implementation of Messager that reports messages via the Compiler
+ */
+public class BatchMessagerImpl extends BaseMessagerImpl implements Messager {
+
+ private final Main _compiler;
+ private final BaseProcessingEnvImpl _processingEnv;
+
+ public BatchMessagerImpl(BaseProcessingEnvImpl processingEnv, Main compiler) {
+ _compiler = compiler;
+ _processingEnv = processingEnv;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg) {
+ printMessage(kind, msg, null, null, null);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg, Element e) {
+ printMessage(kind, msg, e, null, null);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg, Element e,
+ AnnotationMirror a) {
+ printMessage(kind, msg, e, a, null);
+
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationValue)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg, Element e,
+ AnnotationMirror a, AnnotationValue v) {
+ if (kind == Kind.ERROR) {
+ _processingEnv.setErrorRaised(true);
+ }
+ CategorizedProblem problem = createProblem(kind, msg, e, a, v);
+ if (problem != null) {
+ this._compiler.addExtraProblems(problem);
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
new file mode 100644
index 00000000..3723ea53
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.lang.reflect.Field;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.tools.JavaFileManager;
+
+import org.eclipse.jdt.internal.compiler.apt.util.EclipseFileManager;
+import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+/**
+ * The implementation of ProcessingEnvironment that is used when compilation is
+ * driven by the command line or by the Tool interface. This environment uses
+ * the JavaFileManager provided by the compiler.
+ * @see org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeProcessingEnvImpl
+ */
+public class BatchProcessingEnvImpl extends BaseProcessingEnvImpl {
+
+ protected final BaseAnnotationProcessorManager _dispatchManager;
+ protected final JavaFileManager _fileManager;
+ protected final Main _compilerOwner;
+
+ public BatchProcessingEnvImpl(BaseAnnotationProcessorManager dispatchManager, Main batchCompiler,
+ String[] commandLineArguments)
+ {
+ super();
+ _compilerOwner = batchCompiler;
+ _compiler = batchCompiler.batchCompiler;
+ _dispatchManager = dispatchManager;
+ Class<?> c = null;
+ try {
+ c = Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl"); //$NON-NLS-1$
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ Field field = null;
+ JavaFileManager javaFileManager = null;
+ if (c != null) {
+ try {
+ field = c.getField("fileManager"); //$NON-NLS-1$
+ } catch (SecurityException e) {
+ // ignore
+ } catch (IllegalArgumentException e) {
+ // ignore
+ } catch (NoSuchFieldException e) {
+ // ignore
+ }
+ }
+ if (field != null) {
+ try {
+ javaFileManager = (JavaFileManager) field.get(batchCompiler);
+ } catch (IllegalArgumentException e) {
+ // ignore
+ } catch (IllegalAccessException e) {
+ // ignore
+ }
+ }
+ if (javaFileManager != null) {
+ _fileManager = javaFileManager;
+ } else {
+ String encoding = (String) batchCompiler.options.get(CompilerOptions.OPTION_Encoding);
+ Charset charset = encoding != null ? Charset.forName(encoding) : null;
+ JavaFileManager manager = new EclipseFileManager(batchCompiler.compilerLocale, charset);
+ ArrayList<String> options = new ArrayList<String>();
+ for (String argument : commandLineArguments) {
+ options.add(argument);
+ }
+ for (Iterator<String> iterator = options.iterator(); iterator.hasNext(); ) {
+ manager.handleOption(iterator.next(), iterator);
+ }
+ _fileManager = manager;
+ }
+ _processorOptions = Collections.unmodifiableMap(parseProcessorOptions(commandLineArguments));
+ _filer = new AjBatchFilerImpl(_dispatchManager, this);
+ _messager = new BatchMessagerImpl(this, _compilerOwner);
+ }
+
+ /**
+ * Parse the -A command line arguments so that they can be delivered to
+ * processors with {@link javax.annotation.processing.ProcessingEnvironment#getOptions()}. In Sun's Java 6
+ * version of javac, unlike in the Java 5 apt tool, only the -A options are
+ * passed to processors, not the other command line options; that behavior
+ * is repeated here.
+ * @param args the equivalent of the args array from the main() method.
+ * @return a map of key to value, or key to null if there is no value for
+ * a particular key. The "-A" is stripped from the key, so a command-line
+ * argument like "-Afoo=bar" will result in an entry with key "foo" and
+ * value "bar".
+ */
+ private Map<String, String> parseProcessorOptions(String[] args) {
+ Map<String, String> options = new LinkedHashMap<String, String>();
+ for (String arg : args) {
+ if (!arg.startsWith("-A")) { //$NON-NLS-1$
+ continue;
+ }
+ int equals = arg.indexOf('=');
+ if (equals == 2) {
+ // option begins "-A=" - not valid
+ Exception e = new IllegalArgumentException("-A option must have a key before the equals sign"); //$NON-NLS-1$
+ throw new AbortCompilation(null, e);
+ }
+ if (equals == arg.length() - 1) {
+ // option ends with "=" - not valid
+ options.put(arg.substring(2, equals), null);
+ } else if (equals == -1) {
+ // no value
+ options.put(arg.substring(2), null);
+ } else {
+ // value and key
+ options.put(arg.substring(2, equals), arg.substring(equals + 1));
+ }
+ }
+ return options;
+ }
+
+ public JavaFileManager getFileManager() {
+ return _fileManager;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return _compilerOwner.compilerLocale;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java
new file mode 100644
index 00000000..e27669f5
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2014 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import javax.tools.ForwardingJavaFileObject;
+import javax.tools.JavaFileObject;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * A delegating JavaFileObject that hooks the close() methods of the Writer
+ * or OutputStream objects that it produces, and notifies the annotation
+ * dispatch manager when a new compilation unit is produced.
+ */
+public class HookedJavaFileObject extends
+ ForwardingJavaFileObject<JavaFileObject>
+{
+ // A delegating Writer that passes all commands to its contained Writer,
+ // but hooks close() to notify the annotation dispatch manager of the new unit.
+ private class ForwardingWriter extends Writer {
+ private final Writer _w;
+ ForwardingWriter(Writer w) {
+ _w = w;
+ }
+ @Override
+ public Writer append(char c) throws IOException {
+ return _w.append(c);
+ }
+ @Override
+ public Writer append(CharSequence csq, int start, int end)
+ throws IOException {
+ return _w.append(csq, start, end);
+ }
+ @Override
+ public Writer append(CharSequence csq) throws IOException {
+ return _w.append(csq);
+ }
+ // This is the only interesting method - it has to notify the
+ // dispatch manager of the new file.
+ @Override
+ public void close() throws IOException {
+ _w.close();
+ closed();
+ }
+ @Override
+ public void flush() throws IOException {
+ _w.flush();
+ }
+ @Override
+ public void write(char[] cbuf) throws IOException {
+ _w.write(cbuf);
+ }
+ @Override
+ public void write(int c) throws IOException {
+ _w.write(c);
+ }
+ @Override
+ public void write(String str, int off, int len)
+ throws IOException {
+ _w.write(str, off, len);
+ }
+ @Override
+ public void write(String str) throws IOException {
+ _w.write(str);
+ }
+ @Override
+ public void write(char[] cbuf, int off, int len)
+ throws IOException {
+ _w.write(cbuf, off, len);
+ }
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return new ForwardingWriter(this._w);
+ }
+ @Override
+ public int hashCode() {
+ return _w.hashCode();
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ForwardingWriter other = (ForwardingWriter) obj;
+ if (_w == null) {
+ if (other._w != null)
+ return false;
+ } else if (!_w.equals(other._w))
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "ForwardingWriter wrapping " + _w.toString(); //$NON-NLS-1$
+ }
+ }
+
+ // A delegating Writer that passes all commands to its contained Writer,
+ // but hooks close() to notify the annotation dispatch manager of the new unit.
+ private class ForwardingOutputStream extends OutputStream {
+ private final OutputStream _os;
+
+ ForwardingOutputStream(OutputStream os) {
+ _os = os;
+ }
+
+ @Override
+ public void close() throws IOException {
+ _os.close();
+ closed();
+ }
+ @Override
+ public void flush() throws IOException {
+ _os.flush();
+ }
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ _os.write(b, off, len);
+ }
+ @Override
+ public void write(byte[] b) throws IOException {
+ _os.write(b);
+ }
+ @Override
+ public void write(int b) throws IOException {
+ _os.write(b);
+ }
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return new ForwardingOutputStream(this._os);
+ }
+ @Override
+ public int hashCode() {
+ return _os.hashCode();
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ForwardingOutputStream other = (ForwardingOutputStream) obj;
+ if (_os == null) {
+ if (other._os != null)
+ return false;
+ } else if (!_os.equals(other._os))
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "ForwardingOutputStream wrapping " + _os.toString(); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * The Filer implementation that we need to notify when a new file is created.
+ */
+ protected final BatchFilerImpl _filer;
+
+ /**
+ * The name of the file that is created; this is passed to the CompilationUnit constructor,
+ * and ultimately to the java.io.File constructor, so it is a normal pathname, just like
+ * what would be on the compiler command line.
+ */
+ protected final String _fileName;
+
+
+
+ /**
+ * A compilation unit is created when the writer or stream is closed. Only do this once.
+ */
+ private boolean _closed = false;
+
+ private String _typeName;
+
+ public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer) {
+ super(fileObject);
+ _filer = filer;
+ _fileName = fileName;
+ _typeName = typeName;
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return new ForwardingOutputStream(super.openOutputStream());
+ }
+
+ @Override
+ public Writer openWriter() throws IOException {
+ return new ForwardingWriter(super.openWriter());
+ }
+
+ protected void closed() {
+ if (!_closed) {
+ _closed = true;
+ //TODO: support encoding
+ switch(this.getKind()) {
+ case SOURCE :
+ CompilationUnit unit = new CompilationUnit(null, _fileName, null /* encoding */);
+ _filer.addNewUnit(unit);
+ break;
+ case CLASS :
+ IBinaryType binaryType = null;
+ try {
+ binaryType = ClassFileReader.read(_fileName);
+ } catch (ClassFormatException e) {
+ /* When the annotation processor produces garbage, javac seems to show some resilience, by hooking the source type,
+ which since is resolved can answer annotations during discovery - Not sure if this sanctioned by the spec, to be taken
+ up with Oracle. Here we mimic the bug, see that addNewClassFile is simply collecting ReferenceBinding's, so adding
+ a SourceTypeBinding works just fine.
+ */
+ ReferenceBinding type = this._filer._env._compiler.lookupEnvironment.getType(CharOperation.splitOn('.', _typeName.toCharArray()));
+ if (type != null)
+ _filer.addNewClassFile(type);
+ } catch (IOException e) {
+ // ignore
+ }
+ if (binaryType != null) {
+ char[] name = binaryType.getName();
+ ReferenceBinding type = this._filer._env._compiler.lookupEnvironment.getType(CharOperation.splitOn('/', name));
+ if (type != null && type.isValidBinding()) {
+ if (type.isBinaryBinding()) {
+ _filer.addNewClassFile(type);
+ } else {
+ BinaryTypeBinding binaryBinding = new BinaryTypeBinding(type.getPackage(), binaryType, this._filer._env._compiler.lookupEnvironment, true);
+ if (binaryBinding != null)
+ _filer.addNewClassFile(binaryBinding);
+ }
+ }
+ }
+ break;
+ case HTML:
+ case OTHER:
+ break;
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java
new file mode 100644
index 00000000..e776ad6c
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.util.List;
+
+import javax.annotation.processing.Processor;
+
+/**
+ * Implementors know how to discover annotation processors, and maintain a list of processors that
+ * have been discovered and initialized so far.
+ */
+public interface IProcessorProvider {
+
+ /**
+ * Return the next processor that can be discovered, according to the order and discovery rules
+ * of the provider (see, for instance, {@link Processor}.
+ * @return a ProcessorInfo wrapping an initialized Processor, or <code>null</code> if there are
+ * no more processors to be discovered.
+ */
+ ProcessorInfo discoverNextProcessor();
+
+ /**
+ * @return the list of all processors that have been discovered so far. This list will grow when
+ * {@link #discoverNextProcessor()} is called.
+ */
+ List<ProcessorInfo> getDiscoveredProcessors();
+
+ /**
+ * Called when a processor throws an exception. This may abort compilation, throw an
+ * unchecked exception, etc; the caller should not assume that this method will return.
+ *
+ * @param p the processor, if known, or null if not.
+ * @param e
+ */
+ void reportProcessorException(Processor p, Exception e);
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java
new file mode 100644
index 00000000..53a9f6d2
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.processing.Processor;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Cached information associated with a {@link Processor} in the context
+ * of annotation processor dispatch.
+ * <p>
+ * This class supports inclusion in a collection by implementing
+ * equals() and hashCode(). Its concept of identity is based on
+ * the class object of the Processor that it wraps; so, for instance,
+ * it is not possible to have a Set that contains more than one
+ * instance of a particular Processor class. In fact, it is possible
+ * to have more than one instance of a Processor if there are multiple
+ * build threads, but within the context of a particular dispatch
+ * manager, there will only be one of any given Processor class.
+ */
+public class ProcessorInfo {
+ final Processor _processor;
+ final Set<String> _supportedOptions;
+ final SourceVersion _supportedSourceVersion;
+
+ private final Pattern _supportedAnnotationTypesPattern;
+ private final boolean _supportsStar;
+ private boolean _hasBeenCalled;
+
+ /**
+ * Create a ProcessorInfo wrapping a particular Processor. The Processor must already have been
+ * initialized (that is,
+ * {@link Processor#init(javax.annotation.processing.ProcessingEnvironment)} must already have
+ * been called). Its getSupportedXXX() methods will be called and the results will be cached.
+ */
+ public ProcessorInfo(Processor p)
+ {
+ _processor = p;
+ _hasBeenCalled = false;
+ _supportedSourceVersion = p.getSupportedSourceVersion();
+ _supportedOptions = p.getSupportedOptions();
+ Set<String> supportedAnnotationTypes = p.getSupportedAnnotationTypes();
+
+ boolean supportsStar = false;
+ if (null != supportedAnnotationTypes && !supportedAnnotationTypes.isEmpty()) {
+ StringBuilder regex = new StringBuilder();
+ Iterator<String> iName = supportedAnnotationTypes.iterator();
+ while (true) {
+ String name = iName.next();
+ supportsStar |= "*".equals(name); //$NON-NLS-1$
+ String escapedName1 = name.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$
+ String escapedName2 = escapedName1.replace("*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
+ regex.append(escapedName2);
+ if (!iName.hasNext()) {
+ break;
+ }
+ regex.append('|');
+ }
+ _supportedAnnotationTypesPattern = Pattern.compile(regex.toString());
+ }
+ else {
+ _supportedAnnotationTypesPattern = null;
+ }
+ _supportsStar = supportsStar;
+ }
+
+ /**
+ * Compute the subset of <code>annotations</code> that are described by <code>annotationTypes</code>,
+ * and determine whether the processor should be called. A processor will be called if it has
+ * any annotations to process, or if it supports "*", or if it was called in a previous round.
+ * If the return value of this method is true once for a given processor, then it will always be true on
+ * subsequent calls.
+ *
+ * @param annotations a set of annotation types
+ * @param result an empty modifiable set, which upon return will contain a subset of <code>annotations</code>, which may be empty but will not be null.
+ * @return true if the processor should be called on this round.
+ */
+ public boolean computeSupportedAnnotations(Set<TypeElement> annotations, Set<TypeElement> result)
+ {
+ if (null != annotations && !annotations.isEmpty() && null != _supportedAnnotationTypesPattern) {
+ for (TypeElement annotation : annotations) {
+ Matcher matcher = _supportedAnnotationTypesPattern.matcher(annotation.getQualifiedName().toString());
+ if (matcher.matches()) {
+ result.add(annotation);
+ }
+ }
+ }
+ boolean call = _hasBeenCalled || _supportsStar || !result.isEmpty();
+ _hasBeenCalled |= call;
+ return call;
+ }
+
+ /**
+ * @return true if the processor included "*" among its list of supported annotations.
+ */
+ public boolean supportsStar()
+ {
+ return _supportsStar;
+ }
+
+ /**
+ * Must be called at the beginning of a build to ensure that no information is
+ * carried over from the previous build. In particular, processors are
+ * required to be called on every round after the round in which they are
+ * first called; this method resets the "has been called" flag.
+ */
+ public void reset()
+ {
+ _hasBeenCalled = false;
+ }
+
+ @Override
+ public int hashCode() {
+ return _processor.getClass().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ProcessorInfo other = (ProcessorInfo) obj;
+ if (!_processor.getClass().equals(other._processor.getClass()))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString()
+ {
+ return _processor.getClass().getName();
+ }
+
+ /**
+ * @return a string representing the set of supported annotation types, in a format
+ * suitable for debugging. The format is unspecified and subject to change.
+ */
+ public String getSupportedAnnotationTypesAsString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ Iterator<String> iAnnots = _processor.getSupportedAnnotationTypes().iterator();
+ boolean hasNext = iAnnots.hasNext();
+ while (hasNext) {
+ sb.append(iAnnots.next());
+ hasNext = iAnnots.hasNext();
+ if (hasNext) {
+ sb.append(',');
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+}
+
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java
new file mode 100644
index 00000000..5cf784e2
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Manages context during a single round of annotation processing.
+ */
+public class RoundDispatcher {
+
+ private final Set<TypeElement> _unclaimedAnnotations;
+ private final RoundEnvironment _roundEnv;
+ private final IProcessorProvider _provider;
+ private boolean _searchForStar = false;
+ private final PrintWriter _traceProcessorInfo;
+ private final PrintWriter _traceRounds;
+
+ /**
+ * Processors discovered so far. This list may grow during the
+ * course of a round, as additional processors are discovered.
+ */
+ private final List<ProcessorInfo> _processors;
+
+ /**
+ * @param rootAnnotations a possibly empty but non-null set of annotations on the
+ * root compilation units of this round. A local copy of the set will be made, to
+ * avoid modifying the set passed in.
+ * @param traceProcessorInfo a PrintWriter that processor trace output will be sent
+ * to, or null if tracing is not desired.
+ * @param traceRounds
+ */
+ public RoundDispatcher(
+ IProcessorProvider provider,
+ RoundEnvironment env,
+ Set<TypeElement> rootAnnotations,
+ PrintWriter traceProcessorInfo,
+ PrintWriter traceRounds)
+ {
+ _provider = provider;
+ _processors = provider.getDiscoveredProcessors();
+ _roundEnv = env;
+ _unclaimedAnnotations = new HashSet<TypeElement>(rootAnnotations);
+ _traceProcessorInfo = traceProcessorInfo;
+ _traceRounds = traceRounds;
+ }
+
+ /**
+ * Handle a complete round, dispatching to all appropriate processors.
+ */
+ public void round()
+ {
+ if (null != _traceRounds) {
+ StringBuilder sbElements = new StringBuilder();
+ sbElements.append("\tinput files: {"); //$NON-NLS-1$
+ Iterator<? extends Element> iElements = _roundEnv.getRootElements().iterator();
+ boolean hasNext = iElements.hasNext();
+ while (hasNext) {
+ sbElements.append(iElements.next());
+ hasNext = iElements.hasNext();
+ if (hasNext) {
+ sbElements.append(',');
+ }
+ }
+ sbElements.append('}');
+ _traceRounds.println(sbElements.toString());
+
+ StringBuilder sbAnnots = new StringBuilder();
+ sbAnnots.append("\tannotations: ["); //$NON-NLS-1$
+ Iterator<TypeElement> iAnnots = _unclaimedAnnotations.iterator();
+ hasNext = iAnnots.hasNext();
+ while (hasNext) {
+ sbAnnots.append(iAnnots.next());
+ hasNext = iAnnots.hasNext();
+ if (hasNext) {
+ sbAnnots.append(',');
+ }
+ }
+ sbAnnots.append(']');
+ _traceRounds.println(sbAnnots.toString());
+
+ _traceRounds.println("\tlast round: " + _roundEnv.processingOver()); //$NON-NLS-1$
+ }
+
+ // If there are no root annotations, try to find a processor that claims "*"
+ _searchForStar = _unclaimedAnnotations.isEmpty();
+
+ // Iterate over all the already-found processors, giving each one a chance at the unclaimed
+ // annotations. If a processor is called at all, it is called on every subsequent round
+ // including the final round, but it may be called with an empty set of annotations.
+ for (ProcessorInfo pi : _processors) {
+
+ handleProcessor(pi);
+ }
+
+ // If there are any unclaimed annotations, or if there were no root annotations and
+ // we have not yet run into a processor that claimed "*", continue discovery.
+ while (_searchForStar || !_unclaimedAnnotations.isEmpty()) {
+ ProcessorInfo pi = _provider.discoverNextProcessor();
+ if (null == pi) {
+ // There are no more processors to be discovered.
+ break;
+ }
+ handleProcessor(pi);
+ }
+
+ // TODO: If !unclaimedAnnos.isEmpty(), issue a warning.
+ }
+
+ /**
+ * Evaluate a single processor. Depending on the unclaimed annotations,
+ * the annotations this processor supports, and whether it has already been
+ * called in a previous round, possibly call its process() method.
+ */
+ private void handleProcessor(ProcessorInfo pi)
+ {
+ try {
+ Set<TypeElement> annotationsToProcess = new HashSet<TypeElement>();
+ boolean shouldCall = pi.computeSupportedAnnotations(
+ _unclaimedAnnotations, annotationsToProcess);
+ if (shouldCall) {
+ boolean claimed = pi._processor.process(annotationsToProcess, _roundEnv);
+ if (null != _traceProcessorInfo && !_roundEnv.processingOver()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Processor "); //$NON-NLS-1$
+ sb.append(pi._processor.getClass().getName());
+ sb.append(" matches ["); //$NON-NLS-1$
+ Iterator<TypeElement> i = annotationsToProcess.iterator();
+ boolean hasNext = i.hasNext();
+ while (hasNext) {
+ sb.append(i.next());
+ hasNext = i.hasNext();
+ if (hasNext) {
+ sb.append(' ');
+ }
+ }
+ sb.append("] and returns "); //$NON-NLS-1$
+ sb.append(claimed);
+ _traceProcessorInfo.println(sb.toString());
+ }
+ if (claimed) {
+ // The processor claimed its annotations.
+ _unclaimedAnnotations.removeAll(annotationsToProcess);
+ if (pi.supportsStar()) {
+ _searchForStar = false;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // If a processor throws an exception (as opposed to reporting an error),
+ // report it and abort compilation by throwing AbortCompilation.
+ _provider.reportProcessorException(pi._processor, e);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java
new file mode 100644
index 00000000..2ef03e1a
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * IBM Corporation - Fix for bug 328575
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+import org.eclipse.jdt.internal.compiler.apt.model.Factory;
+import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+
+public class RoundEnvImpl implements RoundEnvironment
+{
+ private final BaseProcessingEnvImpl _processingEnv;
+ private final boolean _isLastRound;
+ private final CompilationUnitDeclaration[] _units;
+ private final ManyToMany<TypeElement, Element> _annoToUnit;
+ private final ReferenceBinding[] _binaryTypes;
+ private final Factory _factory;
+ private Set<Element> _rootElements = null;
+
+ public RoundEnvImpl(CompilationUnitDeclaration[] units, ReferenceBinding[] binaryTypeBindings, boolean isLastRound, BaseProcessingEnvImpl env) {
+ _processingEnv = env;
+ _isLastRound = isLastRound;
+ _units = units;
+ _factory = _processingEnv.getFactory();
+
+ // Discover the annotations that will be passed to Processor.process()
+ AnnotationDiscoveryVisitor visitor = new AnnotationDiscoveryVisitor(_processingEnv);
+ if (_units != null) {
+ for (CompilationUnitDeclaration unit : _units) {
+ unit.scope.suppressImportErrors = true;
+ unit.traverse(visitor, unit.scope);
+ unit.scope.suppressImportErrors = false;
+ }
+ }
+ _annoToUnit = visitor._annoToElement;
+ if (binaryTypeBindings != null) collectAnnotations(binaryTypeBindings);
+ _binaryTypes = binaryTypeBindings;
+ }
+
+ private void collectAnnotations(ReferenceBinding[] referenceBindings) {
+ for (ReferenceBinding referenceBinding : referenceBindings) {
+ // collect all annotations from the binary types
+ if (referenceBinding instanceof ParameterizedTypeBinding) {
+ referenceBinding = ((ParameterizedTypeBinding) referenceBinding).genericType();
+ }
+ AnnotationBinding[] annotationBindings = Factory.getPackedAnnotationBindings(referenceBinding.getAnnotations());
+ for (AnnotationBinding annotationBinding : annotationBindings) {
+ TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
+ Element element = _factory.newElement(referenceBinding);
+ _annoToUnit.put(anno, element);
+ }
+ FieldBinding[] fieldBindings = referenceBinding.fields();
+ for (FieldBinding fieldBinding : fieldBindings) {
+ annotationBindings = Factory.getPackedAnnotationBindings(fieldBinding.getAnnotations());
+ for (AnnotationBinding annotationBinding : annotationBindings) {
+ TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
+ Element element = _factory.newElement(fieldBinding);
+ _annoToUnit.put(anno, element);
+ }
+ }
+ MethodBinding[] methodBindings = referenceBinding.methods();
+ for (MethodBinding methodBinding : methodBindings) {
+ annotationBindings = Factory.getPackedAnnotationBindings(methodBinding.getAnnotations());
+ for (AnnotationBinding annotationBinding : annotationBindings) {
+ TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
+ Element element = _factory.newElement(methodBinding);
+ _annoToUnit.put(anno, element);
+ }
+ }
+ ReferenceBinding[] memberTypes = referenceBinding.memberTypes();
+ collectAnnotations(memberTypes);
+ }
+ }
+
+ /**
+ * Return the set of annotation types that were discovered on the root elements.
+ * This does not include inherited annotations, only those directly on the root
+ * elements.
+ * @return a set of annotation types, possibly empty.
+ */
+ public Set<TypeElement> getRootAnnotations()
+ {
+ return Collections.unmodifiableSet(_annoToUnit.getKeySet());
+ }
+
+ @Override
+ public boolean errorRaised()
+ {
+ return _processingEnv.errorRaised();
+ }
+
+ /**
+ * From the set of root elements and their enclosed elements, return the subset that are annotated
+ * with {@code a}. If {@code a} is annotated with the {@link java.lang.annotation.Inherited}
+ * annotation, include those elements that inherit the annotation from their superclasses.
+ * Note that {@link java.lang.annotation.Inherited} only applies to classes (i.e. TypeElements).
+ */
+ @Override
+ public Set<? extends Element> getElementsAnnotatedWith(TypeElement a)
+ {
+ if (a.getKind() != ElementKind.ANNOTATION_TYPE) {
+ throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$
+ }
+ Binding annoBinding = ((TypeElementImpl)a)._binding;
+ if (0 != (annoBinding.getAnnotationTagBits() & TagBits.AnnotationInherited)) {
+ Set<Element> annotatedElements = new HashSet<Element>(_annoToUnit.getValues(a));
+ // For all other root elements that are TypeElements, and for their recursively enclosed
+ // types, add each element if it has a superclass are annotated with 'a'
+ ReferenceBinding annoTypeBinding = (ReferenceBinding) annoBinding;
+ for (TypeElement element : ElementFilter.typesIn(getRootElements())) {
+ ReferenceBinding typeBinding = (ReferenceBinding)((TypeElementImpl)element)._binding;
+ addAnnotatedElements(annoTypeBinding, typeBinding, annotatedElements);
+ }
+ return Collections.unmodifiableSet(annotatedElements);
+ }
+ return Collections.unmodifiableSet(_annoToUnit.getValues(a));
+ }
+
+ /**
+ * For every type in types that is a class and that is annotated with anno, either directly or by inheritance,
+ * add that type to result. Recursively descend on each types's child classes as well.
+ * @param anno the compiler binding for an annotation type
+ * @param type a type, not necessarily a class
+ * @param result must be a modifiable Set; will accumulate annotated classes
+ */
+ private void addAnnotatedElements(ReferenceBinding anno, ReferenceBinding type, Set<Element> result) {
+ if (type.isClass()) {
+ if (inheritsAnno(type, anno)) {
+ result.add(_factory.newElement(type));
+ }
+ }
+ for (ReferenceBinding element : type.memberTypes()) {
+ addAnnotatedElements(anno, element, result);
+ }
+ }
+
+ /**
+ * Check whether an element has a superclass that is annotated with an @Inherited annotation.
+ * @param element must be a class (not an interface, enum, etc.).
+ * @param anno must be an annotation type, and must be @Inherited
+ * @return true if element has a superclass that is annotated with anno
+ */
+ private boolean inheritsAnno(ReferenceBinding element, ReferenceBinding anno) {
+ ReferenceBinding searchedElement = element;
+ do {
+ if (searchedElement instanceof ParameterizedTypeBinding) {
+ searchedElement = ((ParameterizedTypeBinding) searchedElement).genericType();
+ }
+ AnnotationBinding[] annos = Factory.getPackedAnnotationBindings(searchedElement.getAnnotations());
+ for (AnnotationBinding annoBinding : annos) {
+ if (annoBinding.getAnnotationType() == anno) { //$IDENTITY-COMPARISON$
+ // element is annotated with anno
+ return true;
+ }
+ }
+ } while (null != (searchedElement = searchedElement.superclass()));
+ return false;
+ }
+
+ @Override
+ public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a)
+ {
+ String canonicalName = a.getCanonicalName();
+ if (canonicalName == null) {
+ // null for anonymous and local classes or an array of those
+ throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$
+ }
+ TypeElement annoType = _processingEnv.getElementUtils().getTypeElement(canonicalName);
+ return getElementsAnnotatedWith(annoType);
+ }
+
+ @Override
+ public Set<? extends Element> getRootElements()
+ {
+ if (_units == null) {
+ return Collections.emptySet();
+ }
+ if (_rootElements == null) {
+ Set<Element> elements = new HashSet<Element>(_units.length);
+ for (CompilationUnitDeclaration unit : _units) {
+ if (null == unit.scope || null == unit.scope.topLevelTypes)
+ continue;
+ for (SourceTypeBinding binding : unit.scope.topLevelTypes) {
+ Element element = _factory.newElement(binding);
+ if (null == element) {
+ throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + binding); //$NON-NLS-1$
+ }
+ elements.add(element);
+ }
+ }
+ if (this._binaryTypes != null) {
+ for (ReferenceBinding typeBinding : _binaryTypes) {
+ Element element = _factory.newElement(typeBinding);
+ if (null == element) {
+ throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + typeBinding); //$NON-NLS-1$
+ }
+ elements.add(element);
+ }
+ }
+ _rootElements = elements;
+ }
+ return _rootElements;
+ }
+
+ @Override
+ public boolean processingOver()
+ {
+ return _isLastRound;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java
new file mode 100644
index 00000000..9a90b335
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Vladimir Piskarev and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vladimir Piskarev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+public class AnnotationMemberValue extends AnnotationValueImpl {
+
+ private final MethodBinding _methodBinding;
+
+ /**
+ * @param value
+ * The JDT representation of a compile-time constant. See
+ * {@link ElementValuePair#getValue()} for possible object types:
+ * <ul>
+ * <li>{@link org.eclipse.jdt.internal.compiler.impl.Constant} for member
+ * of primitive type or String</li>
+ * <li>{@link TypeBinding} for a member value of type
+ * {@link java.lang.Class}</li>
+ * <li>{@link FieldBinding} for an enum constant</li>
+ * <li>{@link AnnotationBinding} for an annotation instance</li>
+ * <li><code>Object[]</code> for a member value of array type, where the
+ * array entries are one of the above</li>
+ * </ul>
+ * @param methodBinding the method binding that defined this member value pair
+ */
+ public AnnotationMemberValue(BaseProcessingEnvImpl env, Object value, MethodBinding methodBinding) {
+ super(env, value, methodBinding.returnType);
+ _methodBinding = methodBinding;
+ }
+
+ /**
+ * @return the method binding that defined this member value pair.
+ */
+ public MethodBinding getMethodBinding() {
+ return _methodBinding;
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java
new file mode 100644
index 00000000..74c728aa
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java
@@ -0,0 +1,531 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.MirroredTypesException;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+public class AnnotationMirrorImpl implements AnnotationMirror, InvocationHandler {
+
+ public final BaseProcessingEnvImpl _env;
+ public final AnnotationBinding _binding;
+
+ /* package */ AnnotationMirrorImpl(BaseProcessingEnvImpl env, AnnotationBinding binding) {
+ _env = env;
+ _binding = binding;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AnnotationMirrorImpl) {
+ if (this._binding == null) {
+ return ((AnnotationMirrorImpl) obj)._binding == null;
+ }
+ return equals(this._binding, ((AnnotationMirrorImpl) obj)._binding);
+ }
+ return obj == null ? false : obj.equals(this); // obj could be wrapped by a proxy.
+ }
+
+ private static boolean equals(AnnotationBinding annotationBinding, AnnotationBinding annotationBinding2) {
+ if (annotationBinding.getAnnotationType() != annotationBinding2.getAnnotationType()) return false; //$IDENTITY-COMPARISON$
+ final ElementValuePair[] elementValuePairs = annotationBinding.getElementValuePairs();
+ final ElementValuePair[] elementValuePairs2 = annotationBinding2.getElementValuePairs();
+ final int length = elementValuePairs.length;
+ if (length != elementValuePairs2.length) return false;
+ loop: for (int i = 0; i < length; i++) {
+ ElementValuePair pair = elementValuePairs[i];
+ // loop on the given pair to make sure one will match
+ for (int j = 0; j < length; j++) {
+ ElementValuePair pair2 = elementValuePairs2[j];
+ if (pair.binding == pair2.binding) {
+ if (pair.value == null) {
+ if (pair2.value == null) {
+ continue loop;
+ }
+ return false;
+ } else {
+ if (pair2.value == null) return false;
+ if (pair2.value instanceof Object[] && pair.value instanceof Object[]) {
+ if (!Arrays.equals((Object[]) pair.value, (Object[]) pair2.value)) {
+ return false;
+ }
+ } else if (!pair2.value.equals(pair.value)){
+ return false;
+ }
+ }
+ continue loop;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public DeclaredType getAnnotationType() {
+ return (DeclaredType) _env.getFactory().newTypeMirror(_binding.getAnnotationType());
+ }
+
+ /**
+ * @return all the members of this annotation mirror that have explicit values.
+ * Default values are not included.
+ */
+ public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValues() {
+ if (this._binding == null) {
+ return Collections.emptyMap();
+ }
+ ElementValuePair[] pairs = _binding.getElementValuePairs();
+ Map<ExecutableElement, AnnotationValue> valueMap =
+ new LinkedHashMap<ExecutableElement, AnnotationValue>(pairs.length);
+ for (ElementValuePair pair : pairs) {
+ MethodBinding method = pair.getMethodBinding();
+ if (method == null) {
+ // ideally we should be able to create a fake ExecutableElementImpl
+ continue;
+ }
+ ExecutableElement e = new ExecutableElementImpl(_env, method);
+ AnnotationValue v = new AnnotationMemberValue(_env, pair.getValue(), method);
+ valueMap.put(e, v);
+ }
+ return Collections.unmodifiableMap(valueMap);
+ }
+
+ /**
+ * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror)
+ * @return all the members of this annotation mirror that have explicit or default
+ * values.
+ */
+ public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults() {
+ if (this._binding == null) {
+ return Collections.emptyMap();
+ }
+ ElementValuePair[] pairs = _binding.getElementValuePairs();
+ ReferenceBinding annoType = _binding.getAnnotationType();
+ Map<ExecutableElement, AnnotationValue> valueMap =
+ new LinkedHashMap<ExecutableElement, AnnotationValue>();
+ for (MethodBinding method : annoType.methods()) {
+ // if binding is in ElementValuePair list, then get value from there
+ boolean foundExplicitValue = false;
+ for (int i = 0; i < pairs.length; ++i) {
+ MethodBinding explicitBinding = pairs[i].getMethodBinding();
+ if (method == explicitBinding) {
+ ExecutableElement e = new ExecutableElementImpl(_env, explicitBinding);
+ AnnotationValue v = new AnnotationMemberValue(_env, pairs[i].getValue(), explicitBinding);
+ valueMap.put(e, v);
+ foundExplicitValue = true;
+ break;
+ }
+ }
+ // else get default value if one exists
+ if (!foundExplicitValue) {
+ Object defaultVal = method.getDefaultValue();
+ if (null != defaultVal) {
+ ExecutableElement e = new ExecutableElementImpl(_env, method);
+ AnnotationValue v = new AnnotationMemberValue(_env, defaultVal, method);
+ valueMap.put(e, v);
+ }
+ }
+ }
+ return Collections.unmodifiableMap(valueMap);
+ }
+
+ public int hashCode() {
+ if (this._binding == null) return this._env.hashCode();
+ return this._binding.hashCode();
+ }
+
+ /*
+ * Used by getAnnotation(), which returns a reflective proxy of the annotation class. When processors then
+ * invoke methods such as value() on the annotation proxy, this method is called.
+ * <p>
+ * A challenge here is that the processor was not necessarily compiled against the same annotation
+ * definition that the compiler is looking at right now, not to mention that the annotation itself
+ * may be defective in source. So the actual type of the value may be quite different than the
+ * type expected by the caller, which will result in a ClassCastException, which is ugly for the
+ * processor to try to catch. So we try to catch and correct this type mismatch where possible.
+ * <p>
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ if (this._binding == null) return null;
+ final String methodName = method.getName();
+ if ( args == null || args.length == 0 ) {
+ if( methodName.equals("hashCode") ) { //$NON-NLS-1$
+ return new Integer( hashCode() );
+ }
+ else if( methodName.equals("toString") ) { //$NON-NLS-1$
+ return toString();
+ }
+ else if( methodName.equals("annotationType")) { //$NON-NLS-1$
+ return proxy.getClass().getInterfaces()[0];
+ }
+ }
+ else if ( args.length == 1 && methodName.equals("equals") ) { //$NON-NLS-1$
+ return new Boolean( equals( args[0] ) );
+ }
+
+ // If it's not one of the above methods, it must be an annotation member, so it cannot take any arguments
+ if ( args != null && args.length != 0 ) {
+ throw new NoSuchMethodException("method " + method.getName() + formatArgs(args) + " does not exist on annotation " + toString()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ final MethodBinding methodBinding = getMethodBinding(methodName);
+ if ( methodBinding == null ) {
+ throw new NoSuchMethodException("method " + method.getName() + "() does not exist on annotation" + toString()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ Object actualValue = null;
+ boolean foundMethod = false;
+ ElementValuePair[] pairs = _binding.getElementValuePairs();
+ for (ElementValuePair pair : pairs) {
+ if (methodName.equals(new String(pair.getName()))) {
+ actualValue = pair.getValue();
+ foundMethod = true;
+ break;
+ }
+ }
+ if (!foundMethod) {
+ // couldn't find explicit value; see if there's a default
+ actualValue = methodBinding.getDefaultValue();
+ }
+ Class<?> expectedType = method.getReturnType();
+ TypeBinding actualType = methodBinding.returnType;
+ return getReflectionValue(actualValue, actualType, expectedType);
+ }
+
+ /*
+ * (non-Javadoc)
+ * Sun implementation shows the values. We avoid that here,
+ * because getting the values is not idempotent.
+ */
+ @Override
+ public String toString() {
+ if (this._binding == null) {
+ return "@any()"; //$NON-NLS-1$
+ }
+ return "@" + _binding.getAnnotationType().debugName(); //$NON-NLS-1$
+ }
+
+ /**
+ * Used for constructing exception message text.
+ * @return a string like "(a, b, c)".
+ */
+ private String formatArgs(final Object[] args)
+ {
+ // estimate that each class name (plus the separators) is 10 characters long plus 2 for "()".
+ final StringBuilder builder = new StringBuilder(args.length * 8 + 2 );
+ builder.append('(');
+ for( int i=0; i<args.length; i++ )
+ {
+ if( i > 0 )
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(args[i].getClass().getName());
+ }
+ builder.append(')');
+ return builder.toString();
+ }
+
+ /**
+ * Find a particular annotation member by name.
+ * @return a compiler method binding, or null if no member was found.
+ */
+ private MethodBinding getMethodBinding(String name) {
+ ReferenceBinding annoType = _binding.getAnnotationType();
+ MethodBinding[] methods = annoType.getMethods(name.toCharArray());
+ for (MethodBinding method : methods) {
+ // annotation members have no parameters
+ if (method.parameters.length == 0) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Convert an annotation member value from JDT into Reflection, and from whatever its actual type
+ * is into whatever type the reflective invoker of a method is expecting.
+ * <p>
+ * Only certain types are permitted as member values. Specifically, a member must be a constant,
+ * and must be either a primitive type, String, Class, an enum constant, an annotation, or an
+ * array of any of those. Multidimensional arrays are not permitted.
+ *
+ * @param actualValue the value as represented by {@link ElementValuePair#getValue()}
+ * @param actualType the return type of the corresponding {@link MethodBinding}
+ * @param expectedType the type that the reflective method invoker is expecting
+ * @return an object of the expected type representing the annotation member value,
+ * or an appropriate dummy value (such as null) if no value is available
+ */
+ private Object getReflectionValue(Object actualValue, TypeBinding actualType, Class<?> expectedType)
+ {
+ if (null == expectedType) {
+ // With no expected type, we can't even guess at a conversion
+ return null;
+ }
+ if (null == actualValue) {
+ // Return a type-appropriate equivalent of null
+ return Factory.getMatchingDummyValue(expectedType);
+ }
+ if (expectedType.isArray()) {
+ if (Class.class.equals(expectedType.getComponentType())) {
+ // package Class[]-valued return as a MirroredTypesException
+ if (actualType.isArrayType() && actualValue instanceof Object[] &&
+ ((ArrayBinding)actualType).leafComponentType.erasure().id == TypeIds.T_JavaLangClass) {
+ Object[] bindings = (Object[])actualValue;
+ List<TypeMirror> mirrors = new ArrayList<TypeMirror>(bindings.length);
+ for (int i = 0; i < bindings.length; ++i) {
+ if (bindings[i] instanceof TypeBinding) {
+ mirrors.add(_env.getFactory().newTypeMirror((TypeBinding)bindings[i]));
+ }
+ }
+ throw new MirroredTypesException(mirrors);
+ }
+ // TODO: actual value is not a TypeBinding[]. Should we return a TypeMirror[] around an ErrorType?
+ return null;
+ }
+ // Handle arrays of types other than Class, e.g., int[], MyEnum[], ...
+ return convertJDTArrayToReflectionArray(actualValue, actualType, expectedType);
+ }
+ else if (Class.class.equals(expectedType)) {
+ // package the Class-valued return as a MirroredTypeException
+ if (actualValue instanceof TypeBinding) {
+ TypeMirror mirror = _env.getFactory().newTypeMirror((TypeBinding)actualValue);
+ throw new MirroredTypeException(mirror);
+ }
+ else {
+ // TODO: actual value is not a TypeBinding. Should we return a TypeMirror around an ErrorType?
+ return null;
+ }
+ }
+ else {
+ // Handle unitary values of type other than Class, e.g., int, MyEnum, ...
+ return convertJDTValueToReflectionType(actualValue, actualType, expectedType);
+ }
+ }
+
+ /**
+ * Convert an array of JDT types as obtained from ElementValuePair.getValue()
+ * (e.g., an Object[] containing IntConstant elements) to the type expected by
+ * a reflective method invocation (e.g., int[]).
+ * <p>
+ * This does not handle arrays of Class, but it does handle primitives, enum constants,
+ * and types such as String.
+ * @param jdtValue the actual value returned by ElementValuePair.getValue() or MethodBinding.getDefault()
+ * @param jdtType the return type of the annotation method binding
+ * @param expectedType the type that the invoker of the method is expecting; must be an array type
+ * @return an Object which is, e.g., an int[]; or null, if an array cannot be created.
+ */
+ private Object convertJDTArrayToReflectionArray(Object jdtValue, TypeBinding jdtType, Class<?> expectedType)
+ {
+ assert null != expectedType && expectedType.isArray();
+ if (!jdtType.isArrayType()) {
+ // the compiler says that the type binding isn't an array type; this probably means
+ // that there's some sort of syntax error.
+ return null;
+ }
+ Object[] jdtArray;
+ // See bug 261969: it's legal to pass a solo element for an array-typed value
+ if (jdtValue != null && !(jdtValue instanceof Object[])) {
+ // Create an array of the expected type
+ jdtArray = (Object[]) Array.newInstance(jdtValue.getClass(), 1);
+ jdtArray[0] = jdtValue;
+ } else {
+ jdtArray = (Object[])jdtValue;
+ }
+ TypeBinding jdtLeafType = jdtType.leafComponentType();
+ Class<?> expectedLeafType = expectedType.getComponentType();
+ final int length = jdtArray.length;
+ final Object returnArray = Array.newInstance(expectedLeafType, length);
+ for (int i = 0; i < length; ++i) {
+ Object jdtElementValue = jdtArray[i];
+ if (expectedLeafType.isPrimitive() || String.class.equals(expectedLeafType)) {
+ if (jdtElementValue instanceof Constant) {
+ if (boolean.class.equals(expectedLeafType)) {
+ Array.setBoolean(returnArray, i, ((Constant)jdtElementValue).booleanValue());
+ }
+ else if (byte.class.equals(expectedLeafType)) {
+ Array.setByte(returnArray, i, ((Constant)jdtElementValue).byteValue());
+ }
+ else if (char.class.equals(expectedLeafType)) {
+ Array.setChar(returnArray, i, ((Constant)jdtElementValue).charValue());
+ }
+ else if (double.class.equals(expectedLeafType)) {
+ Array.setDouble(returnArray, i, ((Constant)jdtElementValue).doubleValue());
+ }
+ else if (float.class.equals(expectedLeafType)) {
+ Array.setFloat(returnArray, i, ((Constant)jdtElementValue).floatValue());
+ }
+ else if (int.class.equals(expectedLeafType)) {
+ Array.setInt(returnArray, i, ((Constant)jdtElementValue).intValue());
+ }
+ else if (long.class.equals(expectedLeafType)) {
+ Array.setLong(returnArray, i, ((Constant)jdtElementValue).longValue());
+ }
+ else if (short.class.equals(expectedLeafType)) {
+ Array.setShort(returnArray, i, ((Constant)jdtElementValue).shortValue());
+ }
+ else if (String.class.equals(expectedLeafType)) {
+ Array.set(returnArray, i, ((Constant)jdtElementValue).stringValue());
+ }
+ }
+ else {
+ // Primitive or string is expected, but our actual value cannot be coerced into one.
+ // TODO: if the actual value is an array of primitives, should we unpack the first one?
+ Factory.setArrayMatchingDummyValue(returnArray, i, expectedLeafType);
+ }
+ }
+ else if (expectedLeafType.isEnum()) {
+ Object returnVal = null;
+ if (jdtLeafType != null && jdtLeafType.isEnum() && jdtElementValue instanceof FieldBinding) {
+ FieldBinding binding = (FieldBinding)jdtElementValue;
+ try {
+ Field returnedField = null;
+ returnedField = expectedLeafType.getField( new String(binding.name) );
+ if (null != returnedField) {
+ returnVal = returnedField.get(null);
+ }
+ }
+ catch (NoSuchFieldException nsfe) {
+ // return null
+ }
+ catch (IllegalAccessException iae) {
+ // return null
+ }
+ }
+ Array.set(returnArray, i, returnVal);
+ }
+ else if (expectedLeafType.isAnnotation()) {
+ // member value is expected to be an annotation type. Wrap it in an Annotation proxy.
+ Object returnVal = null;
+ if (jdtLeafType.isAnnotationType() && jdtElementValue instanceof AnnotationBinding) {
+ AnnotationMirrorImpl annoMirror =
+ (AnnotationMirrorImpl)_env.getFactory().newAnnotationMirror((AnnotationBinding)jdtElementValue);
+ returnVal = Proxy.newProxyInstance(expectedLeafType.getClassLoader(),
+ new Class[]{ expectedLeafType }, annoMirror );
+ }
+ Array.set(returnArray, i, returnVal);
+ }
+ else {
+ Array.set(returnArray, i, null);
+ }
+ }
+ return returnArray;
+ }
+
+ /**
+ * Convert a JDT annotation value as obtained from ElementValuePair.getValue()
+ * (e.g., IntConstant, FieldBinding, etc.) to the type expected by a reflective
+ * method invocation (e.g., int, an enum constant, etc.).
+ * @return a value of type {@code expectedType}, or a dummy value of that type if
+ * the actual value cannot be converted.
+ */
+ private Object convertJDTValueToReflectionType(Object jdtValue, TypeBinding actualType, Class<?> expectedType) {
+ if (expectedType.isPrimitive() || String.class.equals(expectedType)) {
+ if (jdtValue instanceof Constant) {
+ if (boolean.class.equals(expectedType)) {
+ return ((Constant)jdtValue).booleanValue();
+ }
+ else if (byte.class.equals(expectedType)) {
+ return ((Constant)jdtValue).byteValue();
+ }
+ else if (char.class.equals(expectedType)) {
+ return ((Constant)jdtValue).charValue();
+ }
+ else if (double.class.equals(expectedType)) {
+ return ((Constant)jdtValue).doubleValue();
+ }
+ else if (float.class.equals(expectedType)) {
+ return ((Constant)jdtValue).floatValue();
+ }
+ else if (int.class.equals(expectedType)) {
+ return ((Constant)jdtValue).intValue();
+ }
+ else if (long.class.equals(expectedType)) {
+ return ((Constant)jdtValue).longValue();
+ }
+ else if (short.class.equals(expectedType)) {
+ return ((Constant)jdtValue).shortValue();
+ }
+ else if (String.class.equals(expectedType)) {
+ return ((Constant)jdtValue).stringValue();
+ }
+ }
+ // Primitive or string is expected, but our actual value cannot be coerced into one.
+ // TODO: if the actual value is an array of primitives, should we unpack the first one?
+ return Factory.getMatchingDummyValue(expectedType);
+ }
+ else if (expectedType.isEnum()) {
+ Object returnVal = null;
+ if (actualType != null && actualType.isEnum() && jdtValue instanceof FieldBinding) {
+
+ FieldBinding binding = (FieldBinding)jdtValue;
+ try {
+ Field returnedField = null;
+ returnedField = expectedType.getField( new String(binding.name) );
+ if (null != returnedField) {
+ returnVal = returnedField.get(null);
+ }
+ }
+ catch (NoSuchFieldException nsfe) {
+ // return null
+ }
+ catch (IllegalAccessException iae) {
+ // return null
+ }
+ }
+ return null == returnVal ? Factory.getMatchingDummyValue(expectedType) : returnVal;
+ }
+ else if (expectedType.isAnnotation()) {
+ // member value is expected to be an annotation type. Wrap it in an Annotation proxy.
+ if (actualType.isAnnotationType() && jdtValue instanceof AnnotationBinding) {
+ AnnotationMirrorImpl annoMirror =
+ (AnnotationMirrorImpl)_env.getFactory().newAnnotationMirror((AnnotationBinding)jdtValue);
+ return Proxy.newProxyInstance(expectedType.getClassLoader(),
+ new Class[]{ expectedType }, annoMirror );
+ }
+ else {
+ // No way to cast a non-annotation value to an annotation type; return null to caller
+ return null;
+ }
+ }
+ else {
+ return Factory.getMatchingDummyValue(expectedType);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java
new file mode 100644
index 00000000..36a93296
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.DoubleConstant;
+import org.eclipse.jdt.internal.compiler.impl.FloatConstant;
+import org.eclipse.jdt.internal.compiler.impl.LongConstant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
+
+public class AnnotationValueImpl implements AnnotationValue, TypeIds {
+
+ /*
+ * Additions to T_* constants in TypeIds.
+ */
+ private static final int T_AnnotationMirror = -1;
+ private static final int T_EnumConstant = -2;
+ private static final int T_ClassObject = -3;
+ private static final int T_ArrayType = -4;
+
+ private final BaseProcessingEnvImpl _env;
+
+ /**
+ * The annotation value, as it would be returned by
+ * {@link #getValue()}. For instance, an Integer (for an int
+ * constant), a VariableElement (for an enum constant), or
+ * a List<AnnotationValueImpl> containing multiple such (for an array type).
+ */
+ private final Object _value;
+
+ /**
+ * The type stored in _value, represented as a T_* value from {@link TypeIds}
+ * or one of the additional T_* values defined in this class.
+ */
+ private final int _kind;
+
+ /**
+ * @param value
+ * The JDT representation of a compile-time constant. See
+ * {@link ElementValuePair#getValue()} for possible object types:
+ * <ul>
+ * <li>{@link org.eclipse.jdt.internal.compiler.impl.Constant} for member
+ * of primitive type or String</li>
+ * <li>{@link TypeBinding} for a member value of type
+ * {@link java.lang.Class}</li>
+ * <li>{@link FieldBinding} for an enum constant</li>
+ * <li>{@link AnnotationBinding} for an annotation instance</li>
+ * <li><code>Object[]</code> for a member value of array type, where the
+ * array entries are one of the above</li>
+ * </ul>
+ * @param type
+ * The JDT representation of the type of the constant, as determined
+ * by the return type of the element. This is needed because the type
+ * of the value may have been widened (e.g., byte to int) by the compiler
+ * and we need to call the proper visitor. This is used only for base types.
+ * If it is null or not a BaseTypeBinding, it is ignored and the type is
+ * determined from the type of the value.
+ */
+ public AnnotationValueImpl(BaseProcessingEnvImpl env, Object value, TypeBinding type) {
+ _env = env;
+ int kind[] = new int[1];
+ if (type == null) {
+ _value = convertToMirrorType(value, type, kind);
+ _kind = kind[0];
+ } else if (type.isArrayType()) {
+ List<AnnotationValue> convertedValues = null;
+ TypeBinding valueType = ((ArrayBinding)type).elementsType();
+ if (value instanceof Object[]) {
+ Object[] values = (Object[])value;
+ convertedValues = new ArrayList<AnnotationValue>(values.length);
+ for (Object oneValue : values) {
+ convertedValues.add(new AnnotationValueImpl(_env, oneValue, valueType));
+ }
+ } else {
+ convertedValues = new ArrayList<AnnotationValue>(1);
+ convertedValues.add(new AnnotationValueImpl(_env, value, valueType));
+ }
+ _value = Collections.unmodifiableList(convertedValues);
+ _kind = T_ArrayType;
+ } else {
+ _value = convertToMirrorType(value, type, kind);
+ _kind = kind[0];
+ }
+ }
+
+ /**
+ * Convert the JDT representation of a single constant into its javax.lang.model
+ * representation. For instance, convert a StringConstant into a String, or
+ * a FieldBinding into a VariableElement. This does not handle the case where
+ * value is an Object[].
+ * @param value the JDT object
+ * @param type the return type of the annotation member. If null or not a
+ * BaseTypeBinding, this is ignored and the value is inspected to determine type.
+ * @param kind an int array whose first element will be set to the type of the
+ * converted object, represented with T_* values from TypeIds or from this class.
+ * @return
+ */
+ private Object convertToMirrorType(Object value, TypeBinding type, int kind[]) {
+ if (type == null) {
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ } else if (type instanceof BaseTypeBinding || type.id == TypeIds.T_JavaLangString) {
+ if (value == null) {
+ if (type instanceof BaseTypeBinding
+ || type.id == TypeIds.T_JavaLangString) {
+ // return a string with error in it to reflect a value that could not be resolved
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ } else if (type.isAnnotationType()) {
+ kind[0] = T_AnnotationMirror;
+ return _env.getFactory().newAnnotationMirror(null);
+ }
+ } else if (value instanceof Constant) {
+ if (type instanceof BaseTypeBinding) {
+ kind[0] = ((BaseTypeBinding)type).id;
+ }
+ else if (type.id == TypeIds.T_JavaLangString) {
+ kind[0] = ((Constant)value).typeID();
+ } else {
+ // error case
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ switch (kind[0]) {
+ case T_boolean:
+ return ((Constant)value).booleanValue();
+ case T_byte:
+ return ((Constant)value).byteValue();
+ case T_char:
+ return ((Constant)value).charValue();
+ case T_double:
+ return ((Constant)value).doubleValue();
+ case T_float:
+ return ((Constant)value).floatValue();
+ case T_int:
+ try {
+ if (value instanceof LongConstant
+ || value instanceof DoubleConstant
+ || value instanceof FloatConstant) {
+ // error case
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ return ((Constant)value).intValue();
+ } catch (ShouldNotImplement e) {
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ case T_JavaLangString:
+ return ((Constant)value).stringValue();
+ case T_long:
+ return ((Constant)value).longValue();
+ case T_short:
+ return ((Constant)value).shortValue();
+ }
+ }
+ } else if (type.isEnum()) {
+ if (value instanceof FieldBinding) {
+ kind[0] = T_EnumConstant;
+ return (VariableElement) _env.getFactory().newElement((FieldBinding) value);
+ } else {
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ } else if (type.isAnnotationType()) {
+ if (value instanceof AnnotationBinding) {
+ kind[0] = T_AnnotationMirror;
+ return _env.getFactory().newAnnotationMirror((AnnotationBinding) value);
+ }
+ } else if (value instanceof TypeBinding) {
+ kind[0] = T_ClassObject;
+ return _env.getFactory().newTypeMirror((TypeBinding) value);
+ }
+ // error case
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+
+ @SuppressWarnings("unchecked") // Need to cast Object _value to a List<AnnotationValue>
+ @Override
+ public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
+ switch (_kind) {
+ case TypeIds.T_boolean:
+ return v.visitBoolean((Boolean)_value, p);
+ case TypeIds.T_byte:
+ return v.visitByte((Byte)_value, p);
+ case TypeIds.T_char:
+ return v.visitChar((Character)_value, p);
+ case TypeIds.T_double:
+ return v.visitDouble((Double)_value, p);
+ case TypeIds.T_float:
+ return v.visitFloat((Float)_value, p);
+ case TypeIds.T_int:
+ return v.visitInt((Integer)_value, p);
+ case TypeIds.T_JavaLangString:
+ return v.visitString((String)_value, p);
+ case TypeIds.T_long:
+ return v.visitLong((Long)_value, p);
+ case TypeIds.T_short:
+ return v.visitShort((Short)_value, p);
+ case T_EnumConstant:
+ return v.visitEnumConstant((VariableElement)_value, p);
+ case T_ClassObject:
+ return v.visitType((TypeMirror)_value, p);
+ case T_AnnotationMirror:
+ return v.visitAnnotation((AnnotationMirror)_value, p);
+ case T_ArrayType:
+ return v.visitArray((List<AnnotationValue>)_value, p);
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return _value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AnnotationValueImpl) {
+ return this._value.equals(((AnnotationValueImpl) obj)._value);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return this._value.hashCode() + this._kind;
+ }
+
+ @Override
+ public String toString() {
+ if (null == _value) {
+ return "null"; //$NON-NLS-1$
+ }
+ return _value.toString();
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java
new file mode 100644
index 00000000..8e7ab867
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 BEA Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+
+/**
+ * Implementation of ArrayType, which represents an array of some type.
+ */
+public class ArrayTypeImpl extends TypeMirrorImpl implements ArrayType {
+
+ ArrayTypeImpl(BaseProcessingEnvImpl env, ArrayBinding binding) {
+ super(env, binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ArrayType#getComponentType()
+ */
+ @Override
+ public TypeMirror getComponentType() {
+ return _env.getFactory().newTypeMirror(((ArrayBinding)_binding).elementsType());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitArray(this, p);
+ }
+
+ protected AnnotationBinding[] getAnnotationBindings() {
+ AnnotationBinding[] oldies = ((ArrayBinding)_binding).getTypeAnnotations();
+ AnnotationBinding[] newbies = Binding.NO_ANNOTATIONS;
+ // Strip out the annotations on sub arrays
+ for (int i = 0, length = oldies == null ? 0 : oldies.length; i < length; i++) {
+ if (oldies[i] == null) {
+ System.arraycopy(oldies, 0, newbies = new AnnotationBinding[i], 0, i);
+ return newbies;
+ }
+ }
+ return newbies;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.ARRAY;
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java
new file mode 100644
index 00000000..95c61033
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of DeclaredType, which refers to a particular usage or instance of a type.
+ * Contrast with {@link TypeElement}, which is an element that potentially defines a family
+ * of DeclaredTypes.
+ */
+public class DeclaredTypeImpl extends TypeMirrorImpl implements DeclaredType {
+
+ private final ElementKind _elementKindHint;
+
+ /* package */ DeclaredTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding) {
+ super(env, binding);
+ _elementKindHint = null;
+ }
+
+ /**
+ * Create a DeclaredType that knows in advance what kind of element to produce from asElement().
+ * This is useful in the case where the type binding is to an unresolved type, but we know
+ * from context what type it is - e.g., an annotation type.
+ */
+ /* package */ DeclaredTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind elementKindHint) {
+ super(env, binding);
+ _elementKindHint = elementKindHint;
+ }
+
+ @Override
+ public Element asElement() {
+ // The JDT compiler does not distinguish between type elements and declared types
+ return _env.getFactory().newElement((ReferenceBinding)_binding, _elementKindHint);
+ }
+
+ @Override
+ public TypeMirror getEnclosingType() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ ReferenceBinding enclosingType = binding.enclosingType();
+ if (enclosingType != null) {
+ return _env.getFactory().newTypeMirror(enclosingType);
+ }
+ return _env.getFactory().getNoType(TypeKind.NONE);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see javax.lang.model.type.DeclaredType#getTypeArguments()
+ * @see javax.lang.model.element.TypeElement#getTypeParameters().
+ */
+ @Override
+ public List<? extends TypeMirror> getTypeArguments() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (binding.isParameterizedType()) {
+ ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)_binding;
+ TypeBinding[] arguments = ptb.arguments;
+ int length = arguments == null ? 0 : arguments.length;
+ if (length == 0) return Collections.emptyList();
+ List<TypeMirror> args = new ArrayList<TypeMirror>(length);
+ for (TypeBinding arg : arguments) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ if (binding.isGenericType()) {
+ TypeVariableBinding[] typeVariables = binding.typeVariables();
+ List<TypeMirror> args = new ArrayList<TypeMirror>(typeVariables.length);
+ for (TypeBinding arg : typeVariables) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitDeclared(this, p);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.DECLARED;
+ }
+
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java
new file mode 100644
index 00000000..5e1bb694
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Element represents any defined Java language element - a package,
+ * a method, a class or interface. Contrast with DeclaredType.
+ */
+public abstract class ElementImpl
+ implements javax.lang.model.element.Element, IElementInfo
+{
+ public final BaseProcessingEnvImpl _env;
+ public final Binding _binding;
+
+ protected ElementImpl(BaseProcessingEnvImpl env, Binding binding) {
+ _env = env;
+ _binding = binding;
+ }
+
+ @Override
+ public TypeMirror asType() {
+ return _env.getFactory().newTypeMirror(_binding);
+ }
+
+ /**
+ * @return the set of compiler annotation bindings on this element
+ */
+ protected abstract AnnotationBinding[] getAnnotationBindings();
+
+ /* Package any repeating annotations into containers, return others as is.
+ In the compiler bindings repeating annotations are left in as is, hence
+ this step. The return value would match what one would expect to see in
+ a class file.
+ */
+ public final AnnotationBinding [] getPackedAnnotationBindings() {
+ return Factory.getPackedAnnotationBindings(getAnnotationBindings());
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+ A annotation = _env.getFactory().getAnnotation(getPackedAnnotationBindings(), annotationClass);
+ if (annotation != null || this.getKind() != ElementKind.CLASS || annotationClass.getAnnotation(Inherited.class) == null)
+ return annotation;
+
+ ElementImpl superClass = (ElementImpl) _env.getFactory().newElement(((ReferenceBinding) this._binding).superclass());
+ return superClass == null ? null : superClass.getAnnotation(annotationClass);
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return _env.getFactory().getAnnotationMirrors(getPackedAnnotationBindings());
+ }
+
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ A [] annotations = _env.getFactory().getAnnotationsByType(Factory.getUnpackedAnnotationBindings(getPackedAnnotationBindings()), annotationType);
+ if (annotations.length != 0 || this.getKind() != ElementKind.CLASS || annotationType.getAnnotation(Inherited.class) == null)
+ return annotations;
+
+ ElementImpl superClass = (ElementImpl) _env.getFactory().newElement(((ReferenceBinding) this._binding).superclass());
+ return superClass == null ? annotations : superClass.getAnnotationsByType(annotationType);
+ }
+
+ @Override
+ public Set<Modifier> getModifiers() {
+ // Most subclasses implement this; this default is appropriate for
+ // PackageElement and TypeParameterElement.
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Name getSimpleName() {
+ return new NameImpl(_binding.shortReadableName());
+ }
+
+ @Override
+ public int hashCode() {
+ return _binding.hashCode();
+ }
+
+ // TODO: equals() implemented as == of JDT bindings. Valid within
+ // a single Compiler instance; breaks in IDE if processors cache values.
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ElementImpl other = (ElementImpl) obj;
+ if (_binding == null) {
+ if (other._binding != null)
+ return false;
+ } else if (_binding != other._binding)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return _binding.toString();
+ }
+
+ @Override
+ public String getFileName() {
+ // Subclasses should override and return something of value
+ return null;
+ }
+
+ /**
+ * @return the package containing this element. The package of a PackageElement is itself.
+ * @see javax.lang.model.util.Elements#getPackageOf(javax.lang.model.element.Element)
+ */
+ abstract /* package */ PackageElement getPackage();
+
+ /**
+ * Subclassed by VariableElementImpl, TypeElementImpl, and ExecutableElementImpl.
+ * This base implementation suffices for other types.
+ * @see Elements#hides
+ * @return true if this element hides {@code hidden}
+ */
+ public boolean hides(Element hidden)
+ {
+ return false;
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
new file mode 100644
index 00000000..4e8eafea
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
@@ -0,0 +1,713 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2013 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Fix for bug 341494
+ * IBM Corporation - Fix for bug 328575
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Javadoc;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+/**
+ * Utilities for working with language elements.
+ * There is one of these for every ProcessingEnvironment.
+ */
+public class ElementsImpl implements Elements {
+
+ // Used for parsing Javadoc comments: matches initial delimiter, followed by whitespace
+ private static final Pattern INITIAL_DELIMITER = Pattern.compile("^\\s*/\\*+"); //$NON-NLS-1$
+
+ private final BaseProcessingEnvImpl _env;
+
+ /*
+ * The processing env creates and caches an ElementsImpl. Other clients should
+ * not create their own; they should ask the env for it.
+ */
+ public ElementsImpl(BaseProcessingEnvImpl env) {
+ _env = env;
+ }
+
+ /**
+ * Return all the annotation mirrors on this element, including inherited annotations.
+ * Annotations are inherited only if the annotation type is meta-annotated with @Inherited,
+ * and the annotation is on a class: e.g., annotations are not inherited for interfaces, methods,
+ * or fields.
+ */
+ @Override
+ public List<? extends AnnotationMirror> getAllAnnotationMirrors(Element e) {
+ // if e is a class, walk up its superclass hierarchy looking for @Inherited annotations not already in the list
+ if (e.getKind() == ElementKind.CLASS && e instanceof TypeElementImpl) {
+ List<AnnotationBinding> annotations = new ArrayList<AnnotationBinding>();
+ // A class can only have one annotation of a particular annotation type.
+ Set<ReferenceBinding> annotationTypes = new HashSet<ReferenceBinding>();
+ ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)e)._binding;
+ boolean checkIfInherited = false;
+ while (null != binding) {
+ if (binding instanceof ParameterizedTypeBinding) {
+ binding = ((ParameterizedTypeBinding) binding).genericType();
+ }
+ for (AnnotationBinding annotation : Factory.getPackedAnnotationBindings(binding.getAnnotations())) {
+ if (annotation == null) continue;
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+ if (checkIfInherited && (annotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0)
+ continue;
+ if (!annotationTypes.contains(annotationType)) {
+ annotationTypes.add(annotationType);
+ annotations.add(annotation);
+ }
+ }
+ binding = binding.superclass();
+ checkIfInherited = true;
+ }
+ List<AnnotationMirror> list = new ArrayList<AnnotationMirror>(annotations.size());
+ for (AnnotationBinding annotation : annotations) {
+ list.add(_env.getFactory().newAnnotationMirror(annotation));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ else {
+ return e.getAnnotationMirrors();
+ }
+ }
+
+ /**
+ * Compute a list of all the visible entities in this type. Specifically:
+ * <ul>
+ * <li>All nested types declared in this type, including interfaces and enums</li>
+ * <li>All protected or public nested types declared in this type's superclasses
+ * and superinterfaces, that are not hidden by a name collision</li>
+ * <li>All methods declared in this type, including constructors but not
+ * including static or instance initializers, and including abstract
+ * methods and unimplemented methods declared in interfaces</li>
+ * <li>All protected or public methods declared in this type's superclasses,
+ * that are not overridden by another method, but not including constructors
+ * or initializers. Includes abstract methods and methods declared in
+ * superinterfaces but not implemented</li>
+ * <li>All fields declared in this type, including constants</li>
+ * <li>All non-private fields declared in this type's superclasses and
+ * superinterfaces, that are not hidden by a name collision.</li>
+ * </ul>
+ */
+ @Override
+ public List<? extends Element> getAllMembers(TypeElement type) {
+ if (null == type || !(type instanceof TypeElementImpl)) {
+ return Collections.emptyList();
+ }
+ ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)type)._binding;
+ // Map of element simple name to binding
+ Map<String, ReferenceBinding> types = new HashMap<String, ReferenceBinding>();
+ // Javac implementation does not take field name collisions into account
+ List<FieldBinding> fields = new ArrayList<FieldBinding>();
+ // For methods, need to compare parameters, not just names
+ Map<String, Set<MethodBinding>> methods = new HashMap<String, Set<MethodBinding>>();
+ Set<ReferenceBinding> superinterfaces = new LinkedHashSet<ReferenceBinding>();
+ boolean ignoreVisibility = true;
+ while (null != binding) {
+ addMembers(binding, ignoreVisibility, types, fields, methods);
+ Set<ReferenceBinding> newfound = new LinkedHashSet<ReferenceBinding>();
+ collectSuperInterfaces(binding, superinterfaces, newfound);
+ for (ReferenceBinding superinterface : newfound) {
+ addMembers(superinterface, false, types, fields, methods);
+ }
+ superinterfaces.addAll(newfound);
+ binding = binding.superclass();
+ ignoreVisibility = false;
+ }
+ List<Element> allMembers = new ArrayList<Element>();
+ for (ReferenceBinding nestedType : types.values()) {
+ allMembers.add(_env.getFactory().newElement(nestedType));
+ }
+ for (FieldBinding field : fields) {
+ allMembers.add(_env.getFactory().newElement(field));
+ }
+ for (Set<MethodBinding> sameNamedMethods : methods.values()) {
+ for (MethodBinding method : sameNamedMethods) {
+ allMembers.add(_env.getFactory().newElement(method));
+ }
+ }
+ return allMembers;
+ }
+
+ /**
+ * Recursively depth-first walk the tree of superinterfaces of a type, collecting
+ * all the unique superinterface bindings. (Note that because of generics, a type may
+ * have multiple unique superinterface bindings corresponding to the same interface
+ * declaration.)
+ * @param existing bindings already in this set will not be re-added or recursed into
+ * @param newfound newly found bindings will be added to this set
+ */
+ private void collectSuperInterfaces(ReferenceBinding type,
+ Set<ReferenceBinding> existing, Set<ReferenceBinding> newfound) {
+ for (ReferenceBinding superinterface : type.superInterfaces()) {
+ if (!existing.contains(superinterface) && !newfound.contains(superinterface)) {
+ newfound.add(superinterface);
+ collectSuperInterfaces(superinterface, existing, newfound);
+ }
+ }
+ }
+
+ /**
+ * Add the members of a type to the maps of subtypes, fields, and methods. Add only those
+ * which are non-private and which are not overridden by an already-discovered member.
+ * For fields, add them all; javac implementation does not take field hiding into account.
+ * @param binding the type whose members will be added to the lists
+ * @param ignoreVisibility if true, all members will be added regardless of whether they
+ * are private, overridden, etc.
+ * @param types a map of type simple name to type binding
+ * @param fields a list of field bindings
+ * @param methods a map of method simple name to set of method bindings with that name
+ */
+ private void addMembers(ReferenceBinding binding, boolean ignoreVisibility, Map<String, ReferenceBinding> types,
+ List<FieldBinding> fields, Map<String, Set<MethodBinding>> methods)
+ {
+ for (ReferenceBinding subtype : binding.memberTypes()) {
+ if (ignoreVisibility || !subtype.isPrivate()) {
+ String name = new String(subtype.sourceName());
+ if (null == types.get(name)) {
+ types.put(name, subtype);
+ }
+ }
+ }
+ for (FieldBinding field : binding.fields()) {
+ if (ignoreVisibility || !field.isPrivate()) {
+ fields.add(field);
+ }
+ }
+ for (MethodBinding method : binding.methods()) {
+ if (!method.isSynthetic() && (ignoreVisibility || (!method.isPrivate() && !method.isConstructor()))) {
+ String methodName = new String(method.selector);
+ Set<MethodBinding> sameNamedMethods = methods.get(methodName);
+ if (null == sameNamedMethods) {
+ // New method name. Create a set for it and add it to the list.
+ // We don't expect many methods with same name, so only 4 slots:
+ sameNamedMethods = new HashSet<MethodBinding>(4);
+ methods.put(methodName, sameNamedMethods);
+ sameNamedMethods.add(method);
+ }
+ else {
+ // We already have a method with this name. Is this method overridden?
+ boolean unique = true;
+ if (!ignoreVisibility) {
+ for (MethodBinding existing : sameNamedMethods) {
+ MethodVerifier verifier = _env.getLookupEnvironment().methodVerifier();
+ if (verifier.doesMethodOverride(existing, method)) {
+ unique = false;
+ break;
+ }
+ }
+ }
+ if (unique) {
+ sameNamedMethods.add(method);
+ }
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getBinaryName(javax.lang.model.element.TypeElement)
+ */
+ @Override
+ public Name getBinaryName(TypeElement type) {
+ TypeElementImpl typeElementImpl = (TypeElementImpl) type;
+ ReferenceBinding referenceBinding = (ReferenceBinding) typeElementImpl._binding;
+ return new NameImpl(
+ CharOperation.replaceOnCopy(referenceBinding.constantPoolName(), '/', '.'));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getConstantExpression(java.lang.Object)
+ */
+ @Override
+ public String getConstantExpression(Object value) {
+ if (!(value instanceof Integer)
+ && !(value instanceof Byte)
+ && !(value instanceof Float)
+ && !(value instanceof Double)
+ && !(value instanceof Long)
+ && !(value instanceof Short)
+ && !(value instanceof Character)
+ && !(value instanceof String)
+ && !(value instanceof Boolean)) {
+ throw new IllegalArgumentException("Not a valid wrapper type : " + value.getClass()); //$NON-NLS-1$
+ }
+ if (value instanceof Character) {
+ StringBuilder builder = new StringBuilder();
+ builder.append('\'').append(value).append('\'');
+ return String.valueOf(builder);
+ } else if (value instanceof String) {
+ StringBuilder builder = new StringBuilder();
+ builder.append('\"').append(value).append('\"');
+ return String.valueOf(builder);
+ } else if (value instanceof Float) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(value).append('f');
+ return String.valueOf(builder);
+ } else if (value instanceof Long) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(value).append('L');
+ return String.valueOf(builder);
+ } else if (value instanceof Short) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("(short)").append(value); //$NON-NLS-1$
+ return String.valueOf(builder);
+ } else if (value instanceof Byte) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("(byte)0x"); //$NON-NLS-1$
+ int intValue = ((Byte) value).byteValue();
+ String hexString = Integer.toHexString(intValue & 0xFF);
+ if (hexString.length() < 2) {
+ builder.append('0');
+ }
+ builder.append(hexString);
+ return String.valueOf(builder);
+ }
+ return String.valueOf(value);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getDocComment(javax.lang.model.element.Element)
+ */
+ @Override
+ public String getDocComment(Element e) {
+ char[] unparsed = getUnparsedDocComment(e);
+ return formatJavadoc(unparsed);
+ }
+
+ /**
+ * Return the entire javadoc comment on e, including the comment characters and whitespace
+ * @param e an Element of any sort, possibly with a javadoc comment.
+ * @return a String, or null if the comment is not available
+ */
+ private char[] getUnparsedDocComment(Element e)
+ {
+ Javadoc javadoc = null;
+ ReferenceContext referenceContext = null;
+ switch(e.getKind()) {
+ case ANNOTATION_TYPE :
+ case CLASS :
+ case ENUM :
+ case INTERFACE :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) e;
+ ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding;
+ if (referenceBinding instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) referenceBinding;
+ referenceContext = sourceTypeBinding.scope.referenceContext;
+ javadoc = ((TypeDeclaration) referenceContext).javadoc;
+ }
+ break;
+ case PACKAGE :
+ // might need to handle javadoc of package-info.java file
+ PackageElementImpl packageElementImpl = (PackageElementImpl) e;
+ PackageBinding packageBinding = (PackageBinding) packageElementImpl._binding;
+ char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME);
+ ReferenceBinding type = this._env.getLookupEnvironment().getType(compoundName);
+ if (type != null && type.isValidBinding() && (type instanceof SourceTypeBinding)) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type;
+ referenceContext = sourceTypeBinding.scope.referenceContext;
+ javadoc = ((TypeDeclaration) referenceContext).javadoc;
+ }
+ break;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e;
+ MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding;
+ AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod();
+ if (sourceMethod != null) {
+ javadoc = sourceMethod.javadoc;
+ referenceContext = sourceMethod;
+ }
+ break;
+ case ENUM_CONSTANT :
+ case FIELD :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) e;
+ FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding;
+ FieldDeclaration sourceField = fieldBinding.sourceField();
+ if (sourceField != null) {
+ javadoc = sourceField.javadoc;
+ if (fieldBinding.declaringClass instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) fieldBinding.declaringClass;
+ referenceContext = sourceTypeBinding.scope.referenceContext;
+ }
+ }
+ break;
+ default:
+ return null;
+ }
+ if (javadoc != null && referenceContext != null) {
+ char[] contents = referenceContext.compilationResult().getCompilationUnit().getContents();
+ if (contents != null) {
+ return CharOperation.subarray(contents, javadoc.sourceStart, javadoc.sourceEnd - 1);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Strip the comment characters from a javadoc comment. Assume the comment is already
+ * missing its closing delimiter.
+ *
+ * Javac's behavior with regard to tab expansion and trimming of whitespace and
+ * asterisks is bizarre and undocumented. We do our best here to emulate it.
+ */
+ private static String formatJavadoc(char[] unparsed)
+ {
+ if (unparsed == null || unparsed.length < 5) { // delimiters take 5 chars
+ return null;
+ }
+
+ String[] lines = new String(unparsed).split("\n"); //$NON-NLS-1$
+ Matcher delimiterMatcher = INITIAL_DELIMITER.matcher(lines[0]);
+ if (!delimiterMatcher.find()) {
+ return null;
+ }
+ int iOpener = delimiterMatcher.end();
+ lines[0] = lines[0].substring(iOpener);
+ if (lines.length == 1) {
+ // single-line comment. Should trim(), but javac doesn't.
+ // we should however remove the starting whitespaces
+ StringBuilder sb = new StringBuilder();
+ char[] chars = lines[0].toCharArray();
+ boolean startingWhitespaces = true;
+ for (char c : chars) {
+ if (Character.isWhitespace(c))
+ if (startingWhitespaces) {
+ continue;
+ } else {
+ sb.append(c);
+ } else {
+ startingWhitespaces = false;
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ // if the first line ends with spaces after the /** then we want to insert a line separator
+ int firstLine = lines[0].trim().length() > 0 ? 0 : 1;
+
+ // If the last line is now empty, skip it
+ int lastLine = lines[lines.length - 1].trim().length() > 0 ? lines.length - 1 : lines.length - 2;
+
+ StringBuilder sb = new StringBuilder();
+ if (lines[0].length() != 0 && firstLine == 1) {
+ // insert a line separator only if the remaining chars on the line are whitespaces
+ sb.append('\n');
+ }
+ boolean preserveLineSeparator = lines[0].length() == 0;
+ for (int line = firstLine; line <= lastLine; ++line) {
+ char[] chars = lines[line].toCharArray();
+ int starsIndex = getStars(chars);
+ int leadingWhitespaces = 0;
+ boolean recordLeadingWhitespaces = true;
+ for (int i = 0, max = chars.length; i < max; i++) {
+ char c = chars[i];
+ switch(c) {
+ case ' ' :
+ if (starsIndex == -1) {
+ if (recordLeadingWhitespaces) {
+ leadingWhitespaces++;
+ } else {
+ sb.append(c);
+ }
+ } else if (i >= starsIndex) {
+ sb.append(c);
+ }
+ break;
+ default :
+ // convert leadingwhitespaces to spaces
+ recordLeadingWhitespaces = false;
+ if (leadingWhitespaces != 0) {
+ int numberOfTabs = leadingWhitespaces / 8;
+ if (numberOfTabs != 0) {
+ for (int j = 0, max2 = numberOfTabs; j < max2; j++) {
+ sb.append(" "); //$NON-NLS-1$
+ }
+ if ((leadingWhitespaces % 8) >= 1) {
+ sb.append(' ');
+ }
+ } else if (line != 0) {
+ // we don't want to preserve the leading spaces for the first line
+ for (int j = 0, max2 = leadingWhitespaces; j < max2; j++) {
+ sb.append(' ');
+ }
+ }
+ leadingWhitespaces = 0;
+ sb.append(c);
+ } else if (c == '\t') {
+ if (i >= starsIndex) {
+ sb.append(c);
+ }
+ } else if (c != '*' || i > starsIndex) {
+ sb.append(c);
+ }
+ }
+ }
+
+ // append a newline at the end of each line except the last, even if we skipped the last entirely
+ int end = lines.length - 1;
+ if (line < end) {
+ sb.append('\n');
+ } else if (preserveLineSeparator && line == end) {
+ sb.append('\n');
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the index of the last leading stars on this line, -1 if none.
+ *
+ * @param line the given line
+ * @return the computed index
+ */
+ private static int getStars(char[] line) {
+ loop: for (int i = 0, max = line.length; i < max; i++) {
+ char c = line[i];
+ if (!Character.isWhitespace(c)) {
+ if (c == '*') {
+ // only whitespaces before the first star
+ // consume all stars and return the last index
+ for (int j = i + 1; j < max; j++) {
+ if (line[j] != '*') {
+ return j;
+ }
+ }
+ return max - 1;
+ }
+ // no need to continue
+ break loop;
+ }
+ }
+ return -1;
+ }
+ /**
+ * @return all the annotation instance's explicitly set values, plus default values
+ * for all the annotation members that are not explicitly set but that have
+ * defaults. By comparison, {@link AnnotationMirror#getElementValues()} only
+ * returns the explicitly set values.
+ * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(javax.lang.model.element.AnnotationMirror)
+ */
+ @Override
+ public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults(
+ AnnotationMirror a) {
+ return ((AnnotationMirrorImpl)a).getElementValuesWithDefaults();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getName(java.lang.CharSequence)
+ */
+ @Override
+ public Name getName(CharSequence cs) {
+ return new NameImpl(cs);
+ }
+
+ @Override
+ public PackageElement getPackageElement(CharSequence name) {
+ LookupEnvironment le = _env.getLookupEnvironment();
+ if (name.length() == 0) {
+ return new PackageElementImpl(_env, le.defaultPackage);
+ }
+ char[] packageName = name.toString().toCharArray();
+ PackageBinding packageBinding = le.createPackage(CharOperation.splitOn('.', packageName));
+ if (packageBinding == null) {
+ return null;
+ }
+ return new PackageElementImpl(_env, packageBinding);
+ }
+
+ @Override
+ public PackageElement getPackageOf(Element type) {
+ switch(type.getKind()) {
+ case ANNOTATION_TYPE :
+ case CLASS :
+ case ENUM :
+ case INTERFACE :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) type;
+ ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(referenceBinding.fPackage);
+ case PACKAGE :
+ return (PackageElement) type;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) type;
+ MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(methodBinding.declaringClass.fPackage);
+ case ENUM_CONSTANT :
+ case FIELD :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) type;
+ FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(fieldBinding.declaringClass.fPackage);
+ case PARAMETER :
+ variableElementImpl = (VariableElementImpl) type;
+ LocalVariableBinding localVariableBinding = (LocalVariableBinding) variableElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(localVariableBinding.declaringScope.classScope().referenceContext.binding.fPackage);
+ case EXCEPTION_PARAMETER :
+ case INSTANCE_INIT :
+ case OTHER :
+ case STATIC_INIT :
+ case TYPE_PARAMETER :
+ case LOCAL_VARIABLE :
+ return null;
+ }
+ // unreachable
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getTypeElement(java.lang.CharSequence)
+ */
+ @Override
+ public TypeElement getTypeElement(CharSequence name) {
+ LookupEnvironment le = _env.getLookupEnvironment();
+ final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray());
+ ReferenceBinding binding = le.getType(compoundName);
+ // If we didn't find the binding, maybe it's a nested type;
+ // try finding the top-level type and then working downwards.
+ if (null == binding) {
+ ReferenceBinding topLevelBinding = null;
+ int topLevelSegments = compoundName.length;
+ while (--topLevelSegments > 0) {
+ char[][] topLevelName = new char[topLevelSegments][];
+ for (int i = 0; i < topLevelSegments; ++i) {
+ topLevelName[i] = compoundName[i];
+ }
+ topLevelBinding = le.getType(topLevelName);
+ if (null != topLevelBinding) {
+ break;
+ }
+ }
+ if (null == topLevelBinding) {
+ return null;
+ }
+ binding = topLevelBinding;
+ for (int i = topLevelSegments; null != binding && i < compoundName.length; ++i) {
+ binding = binding.getMemberType(compoundName[i]);
+ }
+ }
+ if (null == binding) {
+ return null;
+ }
+ return new TypeElementImpl(_env, binding, null);
+ }
+
+ /* (non-Javadoc)
+ * Element A hides element B if: A and B are both fields, both nested types, or both methods; and
+ * the enclosing element of B is a superclass or superinterface of the enclosing element of A.
+ * See JLS 8.3 (for hiding of fields), 8.4.8.2 (hiding of class methods), and 8.5 (for hiding of member types).
+ * @see javax.lang.model.util.Elements#hides(javax.lang.model.element.Element, javax.lang.model.element.Element)
+ */
+ @Override
+ public boolean hides(Element hider, Element hidden) {
+ if (hidden == null) {
+ // required by API spec
+ throw new NullPointerException();
+ }
+ return ((ElementImpl)hider).hides(hidden);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#isDeprecated(javax.lang.model.element.Element)
+ */
+ @Override
+ public boolean isDeprecated(Element e) {
+ if (!(e instanceof ElementImpl)) {
+ return false;
+ }
+ return (((ElementImpl)e)._binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0;
+ }
+
+ /* (non-Javadoc)
+ * See JLS 8.4.8.1 for discussion of hiding of methods
+ * @see javax.lang.model.util.Elements#overrides(javax.lang.model.element.ExecutableElement, javax.lang.model.element.ExecutableElement, javax.lang.model.element.TypeElement)
+ */
+ @Override
+ public boolean overrides(ExecutableElement overrider, ExecutableElement overridden,
+ TypeElement type) {
+ if (overridden == null || type == null) {
+ throw new NullPointerException();
+ }
+ return ((ExecutableElementImpl)overrider).overrides(overridden, type);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#printElements(java.io.Writer, javax.lang.model.element.Element[])
+ */
+ @Override
+ public void printElements(Writer w, Element... elements) {
+ String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
+ for (Element element : elements) {
+ try {
+ w.write(element.toString());
+ w.write(lineSeparator);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ try {
+ w.flush();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ public boolean isFunctionalInterface(TypeElement type) {
+ if (type != null && type.getKind() == ElementKind.INTERFACE) {
+ ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl) type)._binding;
+ if (binding instanceof SourceTypeBinding) {
+ return binding.isFunctionalInterface(((SourceTypeBinding) binding).scope);
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java
new file mode 100644
index 00000000..9e606cdc
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Element corresponding to the Error type mirror
+ */
+public class ErrorTypeElement extends TypeElementImpl {
+
+ ErrorTypeElement(BaseProcessingEnvImpl env, ReferenceBinding binding) {
+ super(env, binding, null);
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getInterfaces()
+ */
+ @Override
+ public List<? extends TypeMirror> getInterfaces() {
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getNestingKind()
+ */
+ @Override
+ public NestingKind getNestingKind() {
+ return NestingKind.TOP_LEVEL;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getQualifiedName()
+ */
+ @Override
+ public Name getQualifiedName() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ char[] qName;
+ if (binding.isMemberType()) {
+ qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.');
+ CharOperation.replace(qName, '$', '.');
+ } else {
+ qName = CharOperation.concatWith(binding.compoundName, '.');
+ }
+ return new NameImpl(qName);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getSuperclass()
+ */
+ @Override
+ public TypeMirror getSuperclass() {
+ return this._env.getFactory().getNoType(TypeKind.NONE);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getTypeParameters()
+ */
+ @Override
+ public List<? extends TypeParameterElement> getTypeParameters() {
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#asType()
+ */
+ @Override
+ public TypeMirror asType() {
+ return this._env.getFactory().getErrorType((ReferenceBinding) this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getAnnotation(java.lang.Class)
+ */
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getAnnotationMirrors()
+ */
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return Collections.emptyList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ return (A[]) Array.newInstance(annotationType, 0);
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getEnclosedElements()
+ */
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getEnclosingElement()
+ */
+ @Override
+ public Element getEnclosingElement() {
+ return this._env.getFactory().newPackageElement(this._env.getLookupEnvironment().defaultPackage);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getKind()
+ */
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.CLASS;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getModifiers()
+ */
+ @Override
+ public Set<Modifier> getModifiers() {
+ return Collections.emptySet();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getSimpleName()
+ */
+ @Override
+ public Name getSimpleName() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ return new NameImpl(binding.sourceName());
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java
new file mode 100644
index 00000000..2c893fe8
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of the {@link ErrorType} interface.
+ */
+public class ErrorTypeImpl extends DeclaredTypeImpl implements ErrorType {
+
+ /* package */ ErrorTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding) {
+ super(env, binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.DeclaredType#asElement()
+ */
+ @Override
+ public Element asElement() {
+ return this._env.getFactory().newElement((ReferenceBinding) this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.DeclaredType#getEnclosingType()
+ */
+ @Override
+ public TypeMirror getEnclosingType() {
+ return NoTypeImpl.NO_TYPE_NONE;
+ }
+
+ @Override
+ public List<? extends TypeMirror> getTypeArguments() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (binding.isParameterizedType()) {
+ ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)_binding;
+ TypeBinding[] arguments = ptb.arguments;
+ int length = arguments == null ? 0 : arguments.length;
+ if (length == 0) return Collections.emptyList();
+ List<TypeMirror> args = new ArrayList<TypeMirror>(length);
+ for (TypeBinding arg : arguments) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ if (binding.isGenericType()) {
+ TypeVariableBinding[] typeVariables = binding.typeVariables();
+ List<TypeMirror> args = new ArrayList<TypeMirror>(typeVariables.length);
+ for (TypeBinding arg : typeVariables) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ return Collections.emptyList();
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitError(this, p);
+ }
+
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return Factory.EMPTY_ANNOTATION_MIRRORS;
+ }
+
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ return (A[]) Array.newInstance(annotationType, 0);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.ERROR;
+ }
+
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java
new file mode 100644
index 00000000..bbedb9bd
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Jesper Steen Moller - Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationHolder;
+import org.eclipse.jdt.internal.compiler.lookup.AptBinaryLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+public class ExecutableElementImpl extends ElementImpl implements
+ ExecutableElement {
+
+ private Name _name = null;
+
+ /* package */ ExecutableElementImpl(BaseProcessingEnvImpl env, MethodBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitExecutable(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((MethodBinding)_binding).getAnnotations();
+ }
+
+ @Override
+ public AnnotationValue getDefaultValue() {
+ MethodBinding binding = (MethodBinding)_binding;
+ Object defaultValue = binding.getDefaultValue();
+ if (defaultValue != null) return new AnnotationMemberValue(_env, defaultValue, binding);
+ return null;
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (null == binding.declaringClass) {
+ return null;
+ }
+ return _env.getFactory().newElement(binding.declaringClass);
+ }
+
+ @Override
+ public String getFileName() {
+ ReferenceBinding dc = ((MethodBinding)_binding).declaringClass;
+ char[] name = dc.getFileName();
+ if (name == null)
+ return null;
+ return new String(name);
+ }
+
+ @Override
+ public ElementKind getKind() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (binding.isConstructor()) {
+ return ElementKind.CONSTRUCTOR;
+ }
+ else if (CharOperation.equals(binding.selector, TypeConstants.CLINIT)) {
+ return ElementKind.STATIC_INIT;
+ }
+ else if (CharOperation.equals(binding.selector, TypeConstants.INIT)) {
+ return ElementKind.INSTANCE_INIT;
+ }
+ else {
+ return ElementKind.METHOD;
+ }
+ }
+
+ @Override
+ public Set<Modifier> getModifiers() {
+ MethodBinding binding = (MethodBinding)_binding;
+ return Factory.getModifiers(binding.modifiers, getKind());
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (null == binding.declaringClass) {
+ return null;
+ }
+ return _env.getFactory().newPackageElement(binding.declaringClass.fPackage);
+ }
+
+ @Override
+ public List<? extends VariableElement> getParameters() {
+ MethodBinding binding = (MethodBinding)_binding;
+ int length = binding.parameters == null ? 0 : binding.parameters.length;
+ if (0 != length) {
+ AbstractMethodDeclaration methodDeclaration = binding.sourceMethod();
+ List<VariableElement> params = new ArrayList<VariableElement>(length);
+ if (methodDeclaration != null) {
+ for (Argument argument : methodDeclaration.arguments) {
+ VariableElement param = new VariableElementImpl(_env, argument.binding);
+ params.add(param);
+ }
+ } else {
+ // binary method
+ AnnotationBinding[][] parameterAnnotationBindings = null;
+ AnnotationHolder annotationHolder = binding.declaringClass.retrieveAnnotationHolder(binding, false);
+ if (annotationHolder != null) {
+ parameterAnnotationBindings = annotationHolder.getParameterAnnotations();
+ }
+ // we need to filter the synthetic arguments
+ int i = 0;
+ for (TypeBinding typeBinding : binding.parameters) {
+ char name[] = binding.parameterNames.length > i ? binding.parameterNames[i] : null;
+ if (name == null) {
+ StringBuilder builder = new StringBuilder("arg");//$NON-NLS-1$
+ builder.append(i);
+ name = String.valueOf(builder).toCharArray();
+ }
+ VariableElement param = new VariableElementImpl(_env,
+ new AptBinaryLocalVariableBinding(
+ name,
+ typeBinding,
+ 0,
+ parameterAnnotationBindings != null ? parameterAnnotationBindings[i] : null,
+ binding));
+ params.add(param);
+ i++;
+ }
+ }
+ return Collections.unmodifiableList(params);
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public TypeMirror getReturnType() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (binding.returnType == null) {
+ return null;
+ }
+ else return _env.getFactory().newTypeMirror(binding.returnType);
+ }
+
+ @Override
+ public Name getSimpleName() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (_name == null) {
+ _name = new NameImpl(binding.selector);
+ }
+ return _name;
+ }
+
+ @Override
+ public List<? extends TypeMirror> getThrownTypes() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (binding.thrownExceptions.length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeMirror> list = new ArrayList<TypeMirror>(binding.thrownExceptions.length);
+ for (ReferenceBinding exception : binding.thrownExceptions) {
+ list.add(_env.getFactory().newTypeMirror(exception));
+ }
+ return list;
+ }
+
+ @Override
+ public List<? extends TypeParameterElement> getTypeParameters() {
+ MethodBinding binding = (MethodBinding)_binding;
+ TypeVariableBinding[] variables = binding.typeVariables();
+ if (variables.length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeParameterElement> params = new ArrayList<TypeParameterElement>(variables.length);
+ for (TypeVariableBinding variable : variables) {
+ params.add(_env.getFactory().newTypeParameterElement(variable, this));
+ }
+ return Collections.unmodifiableList(params);
+ }
+
+ @Override
+ public boolean hides(Element hidden)
+ {
+ if (!(hidden instanceof ExecutableElementImpl)) {
+ return false;
+ }
+ MethodBinding hiderBinding = (MethodBinding)_binding;
+ MethodBinding hiddenBinding = (MethodBinding)((ExecutableElementImpl)hidden)._binding;
+ if (hiderBinding == hiddenBinding) {
+ return false;
+ }
+ if (hiddenBinding.isPrivate()) {
+ return false;
+ }
+ // See JLS 8.4.8: hiding only applies to static methods
+ if (!hiderBinding.isStatic() || !hiddenBinding.isStatic()) {
+ return false;
+ }
+ // check names
+ if (!CharOperation.equals(hiddenBinding.selector, hiderBinding.selector)) {
+ return false;
+ }
+ // check parameters
+ if (!_env.getLookupEnvironment().methodVerifier().isMethodSubsignature(hiderBinding, hiddenBinding)) {
+ return false;
+ }
+ return null != hiderBinding.declaringClass.findSuperTypeOriginatingFrom(hiddenBinding.declaringClass);
+ }
+
+ @Override
+ public boolean isVarArgs() {
+ return ((MethodBinding) _binding).isVarargs();
+ }
+
+ /**
+ * Return true if this method overrides {@code overridden} in the context of {@code type}. For
+ * instance, consider
+ * <pre>
+ * interface A { void f(); }
+ * class B { void f() {} }
+ * class C extends B implements I { }
+ * </pre>
+ * In the context of B, B.f() does not override A.f(); they are unrelated. But in the context of
+ * C, B.f() does override A.f(). That is, the copy of B.f() that C inherits overrides A.f().
+ * This is equivalent to considering two questions: first, does C inherit B.f(); if so, does
+ * the inherited C.f() override A.f(). If B.f() were private, for instance, then in the context
+ * of C it would still not override A.f().
+ *
+ * @see javax.lang.model.util.Elements#overrides(ExecutableElement, ExecutableElement, TypeElement)
+ * @jls3 8.4.8 Inheritance, Overriding, and Hiding
+ * @jls3 9.4.1 Inheritance and Overriding
+ */
+ public boolean overrides(ExecutableElement overridden, TypeElement type)
+ {
+ MethodBinding overriddenBinding = (MethodBinding)((ExecutableElementImpl) overridden)._binding;
+ ReferenceBinding overriderContext = (ReferenceBinding)((TypeElementImpl)type)._binding;
+ if ((MethodBinding)_binding == overriddenBinding
+ || overriddenBinding.isStatic()
+ || overriddenBinding.isPrivate()
+ || ((MethodBinding)_binding).isStatic()) {
+ return false;
+ }
+ char[] selector = ((MethodBinding)_binding).selector;
+ if (!CharOperation.equals(selector, overriddenBinding.selector))
+ return false;
+
+ // Construct a binding to the equivalent of this (the overrider) as it would be inherited by 'type'.
+ // Can only do this if 'type' is descended from the overrider.
+ // Second clause of the AND is required to match a peculiar javac behavior.
+ if (null == overriderContext.findSuperTypeOriginatingFrom(((MethodBinding)_binding).declaringClass) &&
+ null == ((MethodBinding)_binding).declaringClass.findSuperTypeOriginatingFrom(overriderContext)) {
+ return false;
+ }
+ MethodBinding overriderBinding = new MethodBinding((MethodBinding)_binding, overriderContext);
+ if (overriderBinding.isPrivate()) {
+ // a private method can never override another method. The other method would either be
+ // private itself, in which case it would not be visible; or this would be a restriction
+ // of access, which is a compile-time error.
+ return false;
+ }
+
+ TypeBinding match = overriderBinding.declaringClass.findSuperTypeOriginatingFrom(overriddenBinding.declaringClass);
+ if (!(match instanceof ReferenceBinding)) return false;
+
+ org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] superMethods = ((ReferenceBinding)match).getMethods(selector);
+ LookupEnvironment lookupEnvironment = _env.getLookupEnvironment();
+ if (lookupEnvironment == null) return false;
+ MethodVerifier methodVerifier = lookupEnvironment.methodVerifier();
+ for (int i = 0, length = superMethods.length; i < length; i++) {
+ if (superMethods[i].original() == overriddenBinding) {
+ return methodVerifier.doesMethodOverride(overriderBinding, superMethods[i]);
+ }
+ }
+ return false;
+ }
+
+ public TypeMirror getReceiverType() {
+ return _env.getFactory().getReceiverType((MethodBinding) _binding);
+ }
+
+ public boolean isDefault() {
+ if (_binding != null) {
+ return ((MethodBinding)_binding).isDefaultMethod();
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java
new file mode 100644
index 00000000..aaf45815
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of the ExecutableType
+ *
+ */
+public class ExecutableTypeImpl extends TypeMirrorImpl implements ExecutableType {
+
+ ExecutableTypeImpl(BaseProcessingEnvImpl env, MethodBinding binding) {
+ super(env, binding);
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getParameterTypes()
+ */
+ @Override
+ public List<? extends TypeMirror> getParameterTypes() {
+ MethodBinding binding = (MethodBinding) this._binding;
+ TypeBinding[] parameters = binding.parameters;
+ int length = parameters.length;
+ boolean isEnumConstructor = binding.isConstructor()
+ && binding.declaringClass.isEnum()
+ && binding.declaringClass.isBinaryBinding()
+ && ((binding.modifiers & ExtraCompilerModifiers.AccGenericSignature) == 0);
+ if (isEnumConstructor) {
+ if (length == 2) {
+ return Collections.emptyList();
+ }
+ ArrayList<TypeMirror> list = new ArrayList<TypeMirror>();
+ for (int i = 2; i < length; i++) {
+ list.add(_env.getFactory().newTypeMirror(parameters[i]));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ if (length != 0) {
+ ArrayList<TypeMirror> list = new ArrayList<TypeMirror>();
+ for (TypeBinding typeBinding : parameters) {
+ list.add(_env.getFactory().newTypeMirror(typeBinding));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getReturnType()
+ */
+ @Override
+ public TypeMirror getReturnType() {
+ return _env.getFactory().newTypeMirror(((MethodBinding) this._binding).returnType);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getThrownTypes()
+ */
+ @Override
+ public List<? extends TypeMirror> getThrownTypes() {
+ ArrayList<TypeMirror> list = new ArrayList<TypeMirror>();
+ ReferenceBinding[] thrownExceptions = ((MethodBinding) this._binding).thrownExceptions;
+ if (thrownExceptions.length != 0) {
+ for (ReferenceBinding referenceBinding : thrownExceptions) {
+ list.add(_env.getFactory().newTypeMirror(referenceBinding));
+ }
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getTypeVariables()
+ */
+ @Override
+ public List<? extends TypeVariable> getTypeVariables() {
+ ArrayList<TypeVariable> list = new ArrayList<TypeVariable>();
+ TypeVariableBinding[] typeVariables = ((MethodBinding) this._binding).typeVariables();
+ if (typeVariables.length != 0) {
+ for (TypeVariableBinding typeVariableBinding : typeVariables) {
+ list.add((TypeVariable) _env.getFactory().newTypeMirror(typeVariableBinding));
+ }
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitExecutable(this, p);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.EXECUTABLE;
+ }
+
+ public TypeMirror getReceiverType() {
+ return _env.getFactory().getReceiverType((MethodBinding) _binding);
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
new file mode 100644
index 00000000..d18616b1
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
@@ -0,0 +1,878 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ * IBM Corporation - Java 8 support
+ * het@google.com - Bug 427943 - The method org.eclipse.jdt.internal.compiler.apt.model.Factory.getPrimitiveType does not throw IllegalArgumentException
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.NullType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
+
+/**
+ * Creates javax.lang.model wrappers around JDT internal compiler bindings.
+ */
+public class Factory {
+
+ // using auto-boxing to take advantage of caching, if any.
+ // the dummy value picked here falls within the caching range.
+ public static final Byte DUMMY_BYTE = 0;
+ public static final Character DUMMY_CHAR = '0';
+ public static final Double DUMMY_DOUBLE = 0d;
+ public static final Float DUMMY_FLOAT = 0f;
+ public static final Integer DUMMY_INTEGER = 0;
+ public static final Long DUMMY_LONG = 0l;
+ public static final Short DUMMY_SHORT = 0;
+
+ private final BaseProcessingEnvImpl _env;
+ public static List<? extends AnnotationMirror> EMPTY_ANNOTATION_MIRRORS = Collections.emptyList();
+
+ /**
+ * This object should only be constructed by the BaseProcessingEnvImpl.
+ */
+ public Factory(BaseProcessingEnvImpl env) {
+ _env = env;
+ }
+
+ /**
+ * Convert an array of compiler annotation bindings into a list of AnnotationMirror
+ * @return a non-null, possibly empty, unmodifiable list.
+ */
+ public List<? extends AnnotationMirror> getAnnotationMirrors(AnnotationBinding[] annotations) {
+ if (null == annotations || 0 == annotations.length) {
+ return Collections.emptyList();
+ }
+ List<AnnotationMirror> list = new ArrayList<AnnotationMirror>(annotations.length);
+ for (AnnotationBinding annotation : annotations) {
+ if (annotation == null) continue;
+ list.add(newAnnotationMirror(annotation));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ @SuppressWarnings("unchecked") // for the cast to A
+ public <A extends Annotation> A[] getAnnotationsByType(AnnotationBinding[] annoInstances, Class<A> annotationClass) {
+ A[] result = getAnnotations(annoInstances, annotationClass, false);
+ return result == null ? (A[]) Array.newInstance(annotationClass, 0) : result;
+ }
+
+
+ public <A extends Annotation> A getAnnotation(AnnotationBinding[] annoInstances, Class<A> annotationClass) {
+ A[] result = getAnnotations(annoInstances, annotationClass, true);
+ return result == null ? null : result[0];
+ }
+
+ @SuppressWarnings("unchecked") // for cast of newProxyInstance() to A
+ private <A extends Annotation> A[] getAnnotations(AnnotationBinding[] annoInstances, Class<A> annotationClass, boolean justTheFirst) {
+ if(annoInstances == null || annoInstances.length == 0 || annotationClass == null )
+ return null;
+
+ String annoTypeName = annotationClass.getName();
+ if(annoTypeName == null ) return null;
+
+ List<A> list = new ArrayList<A>(annoInstances.length);
+ for(AnnotationBinding annoInstance : annoInstances) {
+ if (annoInstance == null)
+ continue;
+
+ AnnotationMirrorImpl annoMirror = createAnnotationMirror(annoTypeName, annoInstance);
+ if (annoMirror != null) {
+ list.add((A)Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class[]{ annotationClass }, annoMirror));
+ if (justTheFirst) break;
+ }
+ }
+ A [] result = (A[]) Array.newInstance(annotationClass, list.size());
+ return list.size() > 0 ? (A[]) list.toArray(result) : null;
+ }
+
+ private AnnotationMirrorImpl createAnnotationMirror(String annoTypeName, AnnotationBinding annoInstance) {
+ ReferenceBinding binding = annoInstance.getAnnotationType();
+ if (binding != null && binding.isAnnotationType() ) {
+ char[] qName;
+ if (binding.isMemberType()) {
+ annoTypeName = annoTypeName.replace('$', '.');
+ qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.');
+ CharOperation.replace(qName, '$', '.');
+ } else {
+ qName = CharOperation.concatWith(binding.compoundName, '.');
+ }
+ if(annoTypeName.equals(new String(qName)) ){
+ return (AnnotationMirrorImpl)_env.getFactory().newAnnotationMirror(annoInstance);
+ }
+ }
+ return null;
+ }
+
+ private static void appendModifier(Set<Modifier> result, int modifiers, int modifierConstant, Modifier modifier) {
+ if ((modifiers & modifierConstant) != 0) {
+ result.add(modifier);
+ }
+ }
+
+ private static void decodeModifiers(Set<Modifier> result, int modifiers, int[] checkBits) {
+ if (checkBits == null) return;
+ for (int i = 0, max = checkBits.length; i < max; i++) {
+ switch(checkBits[i]) {
+ case ClassFileConstants.AccPublic :
+ appendModifier(result, modifiers, checkBits[i], Modifier.PUBLIC);
+ break;
+ case ClassFileConstants.AccProtected:
+ appendModifier(result, modifiers, checkBits[i], Modifier.PROTECTED);
+ break;
+ case ClassFileConstants.AccPrivate :
+ appendModifier(result, modifiers, checkBits[i], Modifier.PRIVATE);
+ break;
+ case ClassFileConstants.AccAbstract :
+ appendModifier(result, modifiers, checkBits[i], Modifier.ABSTRACT);
+ break;
+ case ExtraCompilerModifiers.AccDefaultMethod :
+ try {
+ appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("DEFAULT")); //$NON-NLS-1$
+ } catch(IllegalArgumentException iae) {
+ // Don't have JDK 1.8, just ignore and proceed.
+ }
+ break;
+ case ClassFileConstants.AccStatic :
+ appendModifier(result, modifiers, checkBits[i], Modifier.STATIC);
+ break;
+ case ClassFileConstants.AccFinal :
+ appendModifier(result, modifiers, checkBits[i], Modifier.FINAL);
+ break;
+ case ClassFileConstants.AccSynchronized :
+ appendModifier(result, modifiers, checkBits[i], Modifier.SYNCHRONIZED);
+ break;
+ case ClassFileConstants.AccNative :
+ appendModifier(result, modifiers, checkBits[i], Modifier.NATIVE);
+ break;
+ case ClassFileConstants.AccStrictfp :
+ appendModifier(result, modifiers, checkBits[i], Modifier.STRICTFP);
+ break;
+ case ClassFileConstants.AccTransient :
+ appendModifier(result, modifiers, checkBits[i], Modifier.TRANSIENT);
+ break;
+ case ClassFileConstants.AccVolatile :
+ appendModifier(result, modifiers, checkBits[i], Modifier.VOLATILE);
+ break;
+ }
+ }
+ }
+
+ public static Object getMatchingDummyValue(final Class<?> expectedType){
+ if( expectedType.isPrimitive() ){
+ if(expectedType == boolean.class)
+ return Boolean.FALSE;
+ else if( expectedType == byte.class )
+ return DUMMY_BYTE;
+ else if( expectedType == char.class )
+ return DUMMY_CHAR;
+ else if( expectedType == double.class)
+ return DUMMY_DOUBLE;
+ else if( expectedType == float.class )
+ return DUMMY_FLOAT;
+ else if( expectedType == int.class )
+ return DUMMY_INTEGER;
+ else if( expectedType == long.class )
+ return DUMMY_LONG;
+ else if(expectedType == short.class)
+ return DUMMY_SHORT;
+ else // expectedType == void.class. can this happen?
+ return DUMMY_INTEGER; // anything would work
+ }
+ else
+ return null;
+ }
+
+ public TypeMirror getReceiverType(MethodBinding binding) {
+ if (binding != null) {
+ if (binding.receiver != null) {
+ return _env.getFactory().newTypeMirror(binding.receiver);
+ }
+ if (binding.declaringClass != null) {
+ if (!binding.isStatic() && (!binding.isConstructor() || binding.declaringClass.isMemberType())) {
+ return _env.getFactory().newTypeMirror(binding.declaringClass);
+ }
+ }
+ }
+ return NoTypeImpl.NO_TYPE_NONE;
+ }
+
+ public static Set<Modifier> getModifiers(int modifiers, ElementKind kind) {
+ return getModifiers(modifiers, kind, false);
+ }
+ /**
+ * Convert from the JDT's ClassFileConstants flags to the Modifier enum.
+ */
+ public static Set<Modifier> getModifiers(int modifiers, ElementKind kind, boolean isFromBinary)
+ {
+ EnumSet<Modifier> result = EnumSet.noneOf(Modifier.class);
+ switch(kind) {
+ case CONSTRUCTOR :
+ case METHOD :
+ // modifiers for methods
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccAbstract,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccSynchronized,
+ ClassFileConstants.AccNative,
+ ClassFileConstants.AccStrictfp,
+ ExtraCompilerModifiers.AccDefaultMethod
+ });
+ break;
+ case FIELD :
+ case ENUM_CONSTANT :
+ // for fields
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccTransient,
+ ClassFileConstants.AccVolatile
+ });
+ break;
+ case ENUM :
+ if (isFromBinary) {
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccAbstract,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccStrictfp
+ });
+ } else {
+ // enum from source cannot be explicitly abstract
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccStrictfp
+ });
+ }
+ break;
+ case ANNOTATION_TYPE :
+ case INTERFACE :
+ case CLASS :
+ // for type
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccAbstract,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccStrictfp
+ });
+ break;
+ default:
+ break;
+ }
+ return Collections.unmodifiableSet(result);
+ }
+
+ public AnnotationMirror newAnnotationMirror(AnnotationBinding binding)
+ {
+ return new AnnotationMirrorImpl(_env, binding);
+ }
+
+ /**
+ * Create a new element that knows what kind it is even if the binding is unresolved.
+ */
+ public Element newElement(Binding binding, ElementKind kindHint) {
+ if (binding == null)
+ return null;
+ switch (binding.kind()) {
+ case Binding.FIELD:
+ case Binding.LOCAL:
+ case Binding.VARIABLE:
+ return new VariableElementImpl(_env, (VariableBinding) binding);
+ case Binding.TYPE:
+ case Binding.GENERIC_TYPE:
+ ReferenceBinding referenceBinding = (ReferenceBinding)binding;
+ if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) {
+ return new ErrorTypeElement(this._env, referenceBinding);
+ }
+ if (CharOperation.equals(referenceBinding.sourceName, TypeConstants.PACKAGE_INFO_NAME)) {
+ return new PackageElementImpl(_env, referenceBinding.fPackage);
+ }
+ return new TypeElementImpl(_env, referenceBinding, kindHint);
+ case Binding.METHOD:
+ return new ExecutableElementImpl(_env, (MethodBinding)binding);
+ case Binding.RAW_TYPE:
+ case Binding.PARAMETERIZED_TYPE:
+ return new TypeElementImpl(_env, ((ParameterizedTypeBinding)binding).genericType(), kindHint);
+ case Binding.PACKAGE:
+ return new PackageElementImpl(_env, (PackageBinding)binding);
+ case Binding.TYPE_PARAMETER:
+ return new TypeParameterElementImpl(_env, (TypeVariableBinding)binding);
+ // TODO: fill in the rest of these
+ case Binding.IMPORT:
+ case Binding.ARRAY_TYPE:
+ case Binding.BASE_TYPE:
+ case Binding.WILDCARD_TYPE:
+ case Binding.INTERSECTION_TYPE:
+ throw new UnsupportedOperationException("NYI: binding type " + binding.kind()); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ public Element newElement(Binding binding) {
+ return newElement(binding, null);
+ }
+
+ /**
+ * Convenience method - equivalent to {@code (PackageElement)Factory.newElement(binding)}
+ */
+ public PackageElement newPackageElement(PackageBinding binding)
+ {
+ return new PackageElementImpl(_env, binding);
+ }
+
+ public NullType getNullType() {
+ return NoTypeImpl.NULL_TYPE;
+ }
+
+ public NoType getNoType(TypeKind kind)
+ {
+ switch (kind) {
+ case NONE:
+ return NoTypeImpl.NO_TYPE_NONE;
+ case VOID:
+ return NoTypeImpl.NO_TYPE_VOID;
+ case PACKAGE:
+ return NoTypeImpl.NO_TYPE_PACKAGE;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Get a type mirror object representing the specified primitive type kind.
+ * @throw IllegalArgumentException if a non-primitive TypeKind is requested
+ */
+ public PrimitiveTypeImpl getPrimitiveType(TypeKind kind)
+ {
+ switch (kind) {
+ case BOOLEAN:
+ return PrimitiveTypeImpl.BOOLEAN;
+ case BYTE:
+ return PrimitiveTypeImpl.BYTE;
+ case CHAR:
+ return PrimitiveTypeImpl.CHAR;
+ case DOUBLE:
+ return PrimitiveTypeImpl.DOUBLE;
+ case FLOAT:
+ return PrimitiveTypeImpl.FLOAT;
+ case INT:
+ return PrimitiveTypeImpl.INT;
+ case LONG:
+ return PrimitiveTypeImpl.LONG;
+ case SHORT:
+ return PrimitiveTypeImpl.SHORT;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public PrimitiveTypeImpl getPrimitiveType(BaseTypeBinding binding) {
+ AnnotationBinding[] annotations = binding.getTypeAnnotations();
+ if (annotations == null || annotations.length == 0) {
+ return getPrimitiveType(PrimitiveTypeImpl.getKind(binding));
+ }
+ return new PrimitiveTypeImpl(_env, binding);
+ }
+
+ /**
+ * Given a binding of uncertain type, try to create the right sort of TypeMirror for it.
+ */
+ public TypeMirror newTypeMirror(Binding binding) {
+ switch (binding.kind()) {
+ case Binding.FIELD:
+ case Binding.LOCAL:
+ case Binding.VARIABLE:
+ // For variables, return the type of the variable
+ return newTypeMirror(((VariableBinding)binding).type);
+
+ case Binding.PACKAGE:
+ return getNoType(TypeKind.PACKAGE);
+
+ case Binding.IMPORT:
+ throw new UnsupportedOperationException("NYI: import type " + binding.kind()); //$NON-NLS-1$
+
+ case Binding.METHOD:
+ return new ExecutableTypeImpl(_env, (MethodBinding) binding);
+
+ case Binding.TYPE:
+ case Binding.RAW_TYPE:
+ case Binding.GENERIC_TYPE:
+ case Binding.PARAMETERIZED_TYPE:
+ ReferenceBinding referenceBinding = (ReferenceBinding) binding;
+ if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) {
+ return getErrorType(referenceBinding);
+ }
+ return new DeclaredTypeImpl(_env, (ReferenceBinding)binding);
+
+ case Binding.ARRAY_TYPE:
+ return new ArrayTypeImpl(_env, (ArrayBinding)binding);
+
+ case Binding.BASE_TYPE:
+ BaseTypeBinding btb = (BaseTypeBinding)binding;
+ switch (btb.id) {
+ case TypeIds.T_void:
+ return getNoType(TypeKind.VOID);
+ case TypeIds.T_null:
+ return getNullType();
+ default:
+ return getPrimitiveType(btb);
+ }
+
+ case Binding.WILDCARD_TYPE:
+ case Binding.INTERSECTION_TYPE: // TODO compatible, but shouldn't it really be an intersection type?
+ return new WildcardTypeImpl(_env, (WildcardBinding) binding);
+
+ case Binding.TYPE_PARAMETER:
+ return new TypeVariableImpl(_env, (TypeVariableBinding) binding);
+ }
+ return null;
+ }
+
+ /**
+ * @param declaringElement the class, method, etc. that is parameterized by this parameter.
+ */
+ public TypeParameterElement newTypeParameterElement(TypeVariableBinding variable, Element declaringElement)
+ {
+ return new TypeParameterElementImpl(_env, variable, declaringElement);
+ }
+
+ public ErrorType getErrorType(ReferenceBinding binding) {
+ return new ErrorTypeImpl(this._env, binding);
+ }
+
+ /**
+ * This method is derived from code in org.eclipse.jdt.apt.core.
+ *
+ * This method is designed to be invoked by the invocation handler and anywhere that requires
+ * a AnnotationValue (AnnotationMirror member values and default values from annotation member).
+ *
+ * Regardless of the path, there are common primitive type conversion that needs to take place.
+ * The type conversions respect the type widening and narrowing rules from JLS 5.1.2 and 5.1.2.
+ *
+ * The only question remains is what is the type of the return value when the type conversion fails?
+ * When <code>avoidReflectException</code> is set to <code>true</code>
+ * Return <code>false</code> if the expected type is <code>boolean</code>
+ * Return numeric 0 for all numeric primitive types and '0' for <code>char</code>
+ *
+ * Otherwise:
+ * Return the value unchanged.
+ *
+ * In the invocation handler case:
+ * The value returned by {@link java.lang.reflect.InvocationHandler#invoke}
+ * will be converted into the expected type by the {@link java.lang.reflect.Proxy}.
+ * If the value and the expected type does not agree, and the value is not null,
+ * a ClassCastException will be thrown. A NullPointerException will result if the
+ * expected type is a primitive type and the value is null.
+ * This behavior causes annotation processors a lot of pain and the decision is
+ * to not throw such unchecked exception. In the case where a ClassCastException or
+ * NullPointerException will be thrown return some dummy value. Otherwise, return
+ * the original value.
+ * Chosen dummy values:
+ * Return <code>false</code> if the expected type is <code>boolean</code>
+ * Return numeric 0 for all numeric primitive types and '0' for <code>char</code>
+ *
+ * This behavior is triggered by setting <code>avoidReflectException</code> to <code>true</code>
+ *
+ * Note: the new behavior deviates from what's documented in
+ * {@link java.lang.reflect.InvocationHandler#invoke} and also deviates from
+ * Sun's implementation.
+ *
+ * @param value the current value from the annotation instance.
+ * @param expectedType the expected type of the value.
+ *
+ */
+ public static Object performNecessaryPrimitiveTypeConversion(
+ final Class<?> expectedType,
+ final Object value,
+ final boolean avoidReflectException)
+ {
+ assert expectedType.isPrimitive() : "expectedType is not a primitive type: " + expectedType.getName(); //$NON-NLS-1$
+ if( value == null)
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : null;
+ // apply widening conversion based on JLS 5.1.2 and 5.1.3
+ final String typeName = expectedType.getName();
+ final char expectedTypeChar = typeName.charAt(0);
+ final int nameLen = typeName.length();
+ // widening byte -> short, int, long, float or double
+ // narrowing byte -> char
+ if( value instanceof Byte )
+ {
+ final byte b = ((Byte)value).byteValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return value; // exact match.
+ else
+ return avoidReflectException ? Boolean.FALSE : value;
+ case 'c':
+ return new Character((char)b); // narrowing.
+ case 'd':
+ return new Double(b); // widening.
+ case 'f':
+ return new Float(b); // widening.
+ case 'i':
+ return new Integer(b); // widening.
+ case 'l':
+ return new Long(b); // widening.
+ case 's':
+ return new Short(b); // widening.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ // widening short -> int, long, float, or double
+ // narrowing short -> byte or char
+ else if( value instanceof Short )
+ {
+ final short s = ((Short)value).shortValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return new Byte((byte)s); // narrowing.
+ else
+ return avoidReflectException ? Boolean.FALSE : value; // completely wrong.
+ case 'c':
+ return new Character((char)s); // narrowing.
+ case 'd':
+ return new Double(s); // widening.
+ case 'f':
+ return new Float(s); // widening.
+ case 'i':
+ return new Integer(s); // widening.
+ case 'l':
+ return new Long(s); // widening.
+ case 's':
+ return value; // exact match
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ // widening char -> int, long, float, or double
+ // narrowing char -> byte or short
+ else if( value instanceof Character )
+ {
+ final char c = ((Character)value).charValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return new Byte((byte)c); // narrowing.
+ else
+ return avoidReflectException ? Boolean.FALSE : value; // completely wrong.
+ case 'c':
+ return value; // exact match
+ case 'd':
+ return new Double(c); // widening.
+ case 'f':
+ return new Float(c); // widening.
+ case 'i':
+ return new Integer(c); // widening.
+ case 'l':
+ return new Long(c); // widening.
+ case 's':
+ return new Short((short)c); // narrowing.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+
+ // widening int -> long, float, or double
+ // narrowing int -> byte, short, or char
+ else if( value instanceof Integer )
+ {
+ final int i = ((Integer)value).intValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return new Byte((byte)i); // narrowing.
+ else
+ return avoidReflectException ? Boolean.FALSE : value; // completely wrong.
+ case 'c':
+ return new Character((char)i); // narrowing
+ case 'd':
+ return new Double(i); // widening.
+ case 'f':
+ return new Float(i); // widening.
+ case 'i':
+ return value; // exact match
+ case 'l':
+ return new Long(i); // widening.
+ case 's':
+ return new Short((short)i); // narrowing.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ // widening long -> float or double
+ else if( value instanceof Long )
+ {
+ final long l = ((Long)value).longValue();
+ switch( expectedTypeChar )
+ {
+ case 'b': // both byte and boolean
+ case 'c':
+ case 'i':
+ case 's':
+ // completely wrong.
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value;
+ case 'd':
+ return new Double(l); // widening.
+ case 'f':
+ return new Float(l); // widening.
+ case 'l':
+ return value; // exact match.
+
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+
+ // widening float -> double
+ else if( value instanceof Float )
+ {
+ final float f = ((Float)value).floatValue();
+ switch( expectedTypeChar )
+ {
+ case 'b': // both byte and boolean
+ case 'c':
+ case 'i':
+ case 's':
+ case 'l':
+ // completely wrong.
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value;
+ case 'd':
+ return new Double(f); // widening.
+ case 'f':
+ return value; // exact match.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ else if( value instanceof Double ){
+ if(expectedTypeChar == 'd' )
+ return value; // exact match
+ else{
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong.
+ }
+ }
+ else if( value instanceof Boolean ){
+ if( expectedTypeChar == 'b' && nameLen == 7) // "boolean".length() == 7
+ return value;
+ else
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong.
+ }
+ else // can't convert
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value;
+ }
+
+ /**
+ * Set an element of an array to the appropriate dummy value type
+ * @param array
+ * @param i
+ * @param expectedLeafType
+ */
+ public static void setArrayMatchingDummyValue(Object array, int i, Class<?> expectedLeafType)
+ {
+ if (boolean.class.equals(expectedLeafType)) {
+ Array.setBoolean(array, i, false);
+ }
+ else if (byte.class.equals(expectedLeafType)) {
+ Array.setByte(array, i, DUMMY_BYTE);
+ }
+ else if (char.class.equals(expectedLeafType)) {
+ Array.setChar(array, i, DUMMY_CHAR);
+ }
+ else if (double.class.equals(expectedLeafType)) {
+ Array.setDouble(array, i, DUMMY_DOUBLE);
+ }
+ else if (float.class.equals(expectedLeafType)) {
+ Array.setFloat(array, i, DUMMY_FLOAT);
+ }
+ else if (int.class.equals(expectedLeafType)) {
+ Array.setInt(array, i, DUMMY_INTEGER);
+ }
+ else if (long.class.equals(expectedLeafType)) {
+ Array.setLong(array, i, DUMMY_LONG);
+ }
+ else if (short.class.equals(expectedLeafType)) {
+ Array.setShort(array, i, DUMMY_SHORT);
+ }
+ else {
+ Array.set(array, i, null);
+ }
+ }
+
+ /* Wrap repeating annotations into their container, return an array of bindings.
+ Incoming array is not modified.
+ */
+ public static AnnotationBinding [] getPackedAnnotationBindings(AnnotationBinding [] annotations) {
+
+ int length = annotations == null ? 0 : annotations.length;
+ if (length == 0)
+ return annotations;
+
+ AnnotationBinding[] repackagedBindings = annotations; // only replicate if repackaging.
+ for (int i = 0; i < length; i++) {
+ AnnotationBinding annotation = repackagedBindings[i];
+ if (annotation == null) continue;
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+ if (!annotationType.isRepeatableAnnotationType())
+ continue;
+ ReferenceBinding containerType = annotationType.containerAnnotationType();
+ if (containerType == null)
+ continue; // FUBAR.
+ MethodBinding [] values = containerType.getMethods(TypeConstants.VALUE);
+ if (values == null || values.length != 1)
+ continue; // FUBAR.
+ MethodBinding value = values[0];
+ if (value.returnType == null || value.returnType.dimensions() != 1 || TypeBinding.notEquals(value.returnType.leafComponentType(), annotationType))
+ continue; // FUBAR
+
+ // We have a kosher repeatable annotation with a kosher containing type. See if actually repeats.
+ List<AnnotationBinding> containees = null;
+ for (int j = i + 1; j < length; j++) {
+ AnnotationBinding otherAnnotation = repackagedBindings[j];
+ if (otherAnnotation == null) continue;
+ if (otherAnnotation.getAnnotationType() == annotationType) { //$IDENTITY-COMPARISON$
+ if (repackagedBindings == annotations)
+ System.arraycopy(repackagedBindings, 0, repackagedBindings = new AnnotationBinding[length], 0, length);
+ repackagedBindings[j] = null; // so it is not double packed.
+ if (containees == null) {
+ containees = new ArrayList<AnnotationBinding>();
+ containees.add(annotation);
+ }
+ containees.add(otherAnnotation);
+ }
+ }
+ if (containees != null) {
+ ElementValuePair [] elementValuePairs = new ElementValuePair [] { new ElementValuePair(TypeConstants.VALUE, containees.toArray(), value) };
+ repackagedBindings[i] = new AnnotationBinding(containerType, elementValuePairs);
+ }
+ }
+ if (repackagedBindings == annotations)
+ return annotations;
+
+ int finalTally = 0;
+ for (int i = 0; i < length; i++) {
+ if (repackagedBindings[i] != null)
+ finalTally++;
+ }
+ annotations = new AnnotationBinding [finalTally];
+ for (int i = 0, j = 0; i < length; i++) {
+ if (repackagedBindings[i] != null)
+ annotations[j++] = repackagedBindings[i];
+ }
+ return annotations;
+ }
+
+ /* Unwrap container annotations into the repeated annotations, return an array of bindings that includes the container and the containees.
+ */
+ public static AnnotationBinding [] getUnpackedAnnotationBindings(AnnotationBinding [] annotations) {
+
+ int length = annotations == null ? 0 : annotations.length;
+ if (length == 0)
+ return annotations;
+
+ List<AnnotationBinding> unpackedAnnotations = new ArrayList<AnnotationBinding>();
+ for (int i = 0; i < length; i++) {
+ AnnotationBinding annotation = annotations[i];
+ if (annotation == null) continue;
+ unpackedAnnotations.add(annotation);
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+
+ MethodBinding [] values = annotationType.getMethods(TypeConstants.VALUE);
+ if (values == null || values.length != 1)
+ continue;
+ MethodBinding value = values[0];
+
+ if (value.returnType.dimensions() != 1)
+ continue;
+
+ TypeBinding containeeType = value.returnType.leafComponentType();
+ if (containeeType == null || !containeeType.isAnnotationType() || !containeeType.isRepeatableAnnotationType())
+ continue;
+
+ if (containeeType.containerAnnotationType() != annotationType) //$IDENTITY-COMPARISON$
+ continue;
+
+ // We have a kosher container: unwrap the contained annotations.
+ ElementValuePair [] elementValuePairs = annotation.getElementValuePairs();
+ for (ElementValuePair elementValuePair : elementValuePairs) {
+ if (CharOperation.equals(elementValuePair.getName(), TypeConstants.VALUE)) {
+ Object [] containees = (Object []) elementValuePair.getValue();
+ for (Object object : containees) {
+ unpackedAnnotations.add((AnnotationBinding) object);
+ }
+ break;
+ }
+ }
+ }
+ return (AnnotationBinding[]) unpackedAnnotations.toArray(new AnnotationBinding [unpackedAnnotations.size()]);
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java
new file mode 100644
index 00000000..077b094f
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+/**
+ * Additional information available for Elements that are implemented
+ * within the Eclipse APT framework.
+ * @see javax.lang.model.element.Element
+ * @since 3.3
+ */
+public interface IElementInfo {
+ /**
+ * Get the project-relative path to the source file that contains this element.
+ * If the element is a PackageElement, the "source file" is package-info.java.
+ * If the element is not recognized or does not exist in the project for some
+ * reason, returns null.
+ * @return the project-relative path, or null.
+ */
+ public String getFileName();
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java
new file mode 100644
index 00000000..3f9dcc65
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.element.Name;
+
+/**
+ * A String-based implementation of the type used to return strings in javax.lang.model.
+ */
+public class NameImpl implements Name {
+
+ private final String _name;
+
+ /** nullary constructor is prohibited */
+ @SuppressWarnings("unused")
+ private NameImpl()
+ {
+ _name = null;
+ }
+
+ public NameImpl(CharSequence cs)
+ {
+ _name = cs.toString();
+ }
+
+ public NameImpl(char[] chars)
+ {
+ _name = String.valueOf(chars);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Name#contentEquals(java.lang.CharSequence)
+ */
+ @Override
+ public boolean contentEquals(CharSequence cs) {
+ return _name.equals(cs.toString());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.CharSequence#charAt(int)
+ */
+ @Override
+ public char charAt(int index) {
+ return _name.charAt(index);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.CharSequence#length()
+ */
+ @Override
+ public int length() {
+ return _name.length();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.CharSequence#subSequence(int, int)
+ */
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return _name.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return _name;
+ }
+
+ @Override
+ public int hashCode() {
+ return _name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final NameImpl other = (NameImpl) obj;
+ return _name.equals(other._name);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java
new file mode 100644
index 00000000..19d132ce
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.NullType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeVisitor;
+
+/**
+ * An implementation of NoType, which is used to represent certain psuedo-types.
+ * @see NoType
+ */
+public class NoTypeImpl implements NoType, NullType
+{
+ private final TypeKind _kind;
+
+ public static final NoType NO_TYPE_NONE = new NoTypeImpl(TypeKind.NONE);
+ public static final NoType NO_TYPE_VOID = new NoTypeImpl(TypeKind.VOID);
+ public static final NoType NO_TYPE_PACKAGE = new NoTypeImpl(TypeKind.PACKAGE);
+ public static final NullType NULL_TYPE = new NoTypeImpl(TypeKind.NULL);
+
+ private NoTypeImpl(TypeKind kind) {
+ _kind = kind;
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p)
+ {
+ switch(this.getKind())
+ {
+ case NULL :
+ return v.visitNull(this, p);
+ default:
+ return v.visitNoType(this, p);
+ }
+ }
+
+ @Override
+ public TypeKind getKind()
+ {
+ return _kind;
+ }
+
+ public String toString()
+ {
+ switch (_kind) {
+ default:
+ case NONE:
+ return "<none>"; //$NON-NLS-1$
+ case NULL:
+ return "null"; //$NON-NLS-1$
+ case VOID:
+ return "void"; //$NON-NLS-1$
+ case PACKAGE:
+ return "package"; //$NON-NLS-1$
+ }
+ }
+
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return Factory.EMPTY_ANNOTATION_MIRRORS;
+ }
+
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ return (A[]) Array.newInstance(annotationType, 0);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
new file mode 100644
index 00000000..7e0e4c8f
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2007 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+/**
+ * Implementation of PackageElement, which represents a package
+ */
+public class PackageElementImpl extends ElementImpl implements PackageElement {
+
+ PackageElementImpl(BaseProcessingEnvImpl env, PackageBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitPackage(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ PackageBinding packageBinding = (PackageBinding) this._binding;
+ char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME);
+ ReferenceBinding type = this._env.getLookupEnvironment().getType(compoundName);
+ AnnotationBinding[] annotations = null;
+ if (type != null && type.isValidBinding()) {
+ annotations = type.getAnnotations();
+ }
+ return annotations;
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ PackageBinding binding = (PackageBinding)_binding;
+ LookupEnvironment environment = binding.environment;
+ char[][][] typeNames = null;
+ INameEnvironment nameEnvironment = binding.environment.nameEnvironment;
+ if (nameEnvironment instanceof FileSystem) {
+ typeNames = ((FileSystem) nameEnvironment).findTypeNames(binding.compoundName);
+ }
+ HashSet<Element> set = new HashSet<Element>();
+ if (typeNames != null) {
+ for (char[][] typeName : typeNames) {
+ ReferenceBinding type = environment.getType(typeName);
+ if (type != null && type.isValidBinding()) {
+ set.add(_env.getFactory().newElement(type));
+ }
+ }
+ }
+ ArrayList<Element> list = new ArrayList<Element>(set.size());
+ list.addAll(set);
+ return Collections.unmodifiableList(list);
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ // packages have no enclosing element
+ return null;
+ }
+
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.PACKAGE;
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ return this;
+ }
+
+ @Override
+ public Name getSimpleName() {
+ char[][] compoundName = ((PackageBinding)_binding).compoundName;
+ int length = compoundName.length;
+ if (length == 0) {
+ return new NameImpl(CharOperation.NO_CHAR);
+ }
+ return new NameImpl(compoundName[length - 1]);
+ }
+
+ @Override
+ public Name getQualifiedName() {
+ return new NameImpl(CharOperation.concatWith(((PackageBinding)_binding).compoundName, '.'));
+ }
+
+ @Override
+ public boolean isUnnamed() {
+ PackageBinding binding = (PackageBinding)_binding;
+ return binding.compoundName == CharOperation.NO_CHAR_CHAR;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java
new file mode 100644
index 00000000..7ff3f2e0
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 BEA Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/**
+ *
+ * @since 3.3
+ */
+public class PrimitiveTypeImpl extends TypeMirrorImpl implements PrimitiveType {
+
+ public final static PrimitiveTypeImpl BOOLEAN = new PrimitiveTypeImpl(TypeBinding.BOOLEAN);
+ public final static PrimitiveTypeImpl BYTE = new PrimitiveTypeImpl(TypeBinding.BYTE);
+ public final static PrimitiveTypeImpl CHAR = new PrimitiveTypeImpl(TypeBinding.CHAR);
+ public final static PrimitiveTypeImpl DOUBLE = new PrimitiveTypeImpl(TypeBinding.DOUBLE);
+ public final static PrimitiveTypeImpl FLOAT = new PrimitiveTypeImpl(TypeBinding.FLOAT);
+ public final static PrimitiveTypeImpl INT = new PrimitiveTypeImpl(TypeBinding.INT);
+ public final static PrimitiveTypeImpl LONG = new PrimitiveTypeImpl(TypeBinding.LONG);
+ public final static PrimitiveTypeImpl SHORT = new PrimitiveTypeImpl(TypeBinding.SHORT);
+
+ /**
+ * Clients should call {@link Factory#getPrimitiveType(TypeKind)},
+ * rather than creating new objects.
+ */
+ private PrimitiveTypeImpl(BaseTypeBinding binding) {
+ // Primitive types do not need an environment!
+ super(null, binding);
+ }
+
+ PrimitiveTypeImpl(BaseProcessingEnvImpl env, BaseTypeBinding binding) {
+ // From Java 8, base type bindings can hold annotations and hence need the environment.
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p)
+ {
+ return v.visitPrimitive(this, p);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.apt.model.TypeMirrorImpl#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return getKind((BaseTypeBinding)_binding);
+ }
+
+ public static TypeKind getKind(BaseTypeBinding binding) {
+ switch (binding.id) {
+ case TypeIds.T_boolean:
+ return TypeKind.BOOLEAN;
+ case TypeIds.T_byte:
+ return TypeKind.BYTE;
+ case TypeIds.T_char:
+ return TypeKind.CHAR;
+ case TypeIds.T_double:
+ return TypeKind.DOUBLE;
+ case TypeIds.T_float:
+ return TypeKind.FLOAT;
+ case TypeIds.T_int:
+ return TypeKind.INT;
+ case TypeIds.T_long:
+ return TypeKind.LONG;
+ case TypeIds.T_short:
+ return TypeKind.SHORT;
+ default:
+ throw new IllegalArgumentException("BaseTypeBinding of unexpected id " + binding.id); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
new file mode 100644
index 00000000..fae28949
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+public class TypeElementImpl extends ElementImpl implements TypeElement {
+
+ private final ElementKind _kindHint;
+
+ /**
+ * In general, clients should call {@link Factory#newDeclaredType(ReferenceBinding)} or
+ * {@link Factory#newElement(org.eclipse.jdt.internal.compiler.lookup.Binding)} to
+ * create new instances.
+ */
+ TypeElementImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind kindHint) {
+ super(env, binding);
+ _kindHint = kindHint;
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitType(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((ReferenceBinding)_binding).getAnnotations();
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ List<Element> enclosed = new ArrayList<Element>(binding.fieldCount() + binding.methods().length);
+ for (MethodBinding method : binding.methods()) {
+ ExecutableElement executable = new ExecutableElementImpl(_env, method);
+ enclosed.add(executable);
+ }
+ for (FieldBinding field : binding.fields()) {
+ // TODO no field should be excluded according to the JLS
+ if (!field.isSynthetic()) {
+ VariableElement variable = new VariableElementImpl(_env, field);
+ enclosed.add(variable);
+ }
+ }
+ for (ReferenceBinding memberType : binding.memberTypes()) {
+ TypeElement type = new TypeElementImpl(_env, memberType, null);
+ enclosed.add(type);
+ }
+ return Collections.unmodifiableList(enclosed);
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ ReferenceBinding enclosingType = binding.enclosingType();
+ if (null == enclosingType) {
+ // this is a top level type; get its package
+ return _env.getFactory().newPackageElement(binding.fPackage);
+ }
+ else {
+ return _env.getFactory().newElement(binding.enclosingType());
+ }
+ }
+
+ @Override
+ public String getFileName() {
+ char[] name = ((ReferenceBinding)_binding).getFileName();
+ if (name == null)
+ return null;
+ return new String(name);
+ }
+
+ @Override
+ public List<? extends TypeMirror> getInterfaces() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (null == binding.superInterfaces() || binding.superInterfaces().length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeMirror> interfaces = new ArrayList<TypeMirror>(binding.superInterfaces().length);
+ for (ReferenceBinding interfaceBinding : binding.superInterfaces()) {
+ TypeMirror interfaceType = _env.getFactory().newTypeMirror(interfaceBinding);
+ if (interfaceType.getKind() == TypeKind.ERROR) {
+ if (this._env.getSourceVersion().compareTo(SourceVersion.RELEASE_6) > 0) {
+ // for jdk 7 and above, add error types
+ interfaces.add(interfaceType);
+ }
+ } else {
+ interfaces.add(interfaceType);
+ }
+ }
+ return Collections.unmodifiableList(interfaces);
+ }
+
+ @Override
+ public ElementKind getKind() {
+ if (null != _kindHint) {
+ return _kindHint;
+ }
+ ReferenceBinding refBinding = (ReferenceBinding)_binding;
+ // The order of these comparisons is important: e.g., enum is subset of class
+ if (refBinding.isEnum()) {
+ return ElementKind.ENUM;
+ }
+ else if (refBinding.isAnnotationType()) {
+ return ElementKind.ANNOTATION_TYPE;
+ }
+ else if (refBinding.isInterface()) {
+ return ElementKind.INTERFACE;
+ }
+ else if (refBinding.isClass()) {
+ return ElementKind.CLASS;
+ }
+ else {
+ throw new IllegalArgumentException("TypeElement " + new String(refBinding.shortReadableName()) + //$NON-NLS-1$
+ " has unexpected attributes " + refBinding.modifiers); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Set<Modifier> getModifiers()
+ {
+ ReferenceBinding refBinding = (ReferenceBinding)_binding;
+ int modifiers = refBinding.modifiers;
+ if (refBinding.isInterface() && refBinding.isNestedType()) {
+ modifiers |= ClassFileConstants.AccStatic;
+ }
+ return Factory.getModifiers(modifiers, getKind(), refBinding.isBinaryBinding());
+ }
+
+ @Override
+ public NestingKind getNestingKind() {
+ ReferenceBinding refBinding = (ReferenceBinding)_binding;
+ if (refBinding.isAnonymousType()) {
+ return NestingKind.ANONYMOUS;
+ } else if (refBinding.isLocalType()) {
+ return NestingKind.LOCAL;
+ } else if (refBinding.isMemberType()) {
+ return NestingKind.MEMBER;
+ }
+ return NestingKind.TOP_LEVEL;
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ return _env.getFactory().newPackageElement((PackageBinding)binding.fPackage);
+ }
+
+ @Override
+ public Name getQualifiedName() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ char[] qName;
+ if (binding.isMemberType()) {
+ qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.');
+ CharOperation.replace(qName, '$', '.');
+ } else {
+ qName = CharOperation.concatWith(binding.compoundName, '.');
+ }
+ return new NameImpl(qName);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.apt.model.ElementImpl#getSimpleName()
+ * @return last segment of name, e.g. for pa.pb.X.Y return Y.
+ */
+ @Override
+ public Name getSimpleName()
+ {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ return new NameImpl(binding.sourceName());
+ }
+
+ @Override
+ public TypeMirror getSuperclass() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ ReferenceBinding superBinding = binding.superclass();
+ if (null == superBinding || binding.isInterface()) {
+ return _env.getFactory().getNoType(TypeKind.NONE);
+ }
+ // superclass of a type must be a DeclaredType
+ return _env.getFactory().newTypeMirror(superBinding);
+ }
+
+ @Override
+ public List<? extends TypeParameterElement> getTypeParameters() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ TypeVariableBinding[] variables = binding.typeVariables();
+ if (variables.length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeParameterElement> params = new ArrayList<TypeParameterElement>(variables.length);
+ for (TypeVariableBinding variable : variables) {
+ params.add(_env.getFactory().newTypeParameterElement(variable, this));
+ }
+ return Collections.unmodifiableList(params);
+ }
+
+ @Override
+ public boolean hides(Element hidden)
+ {
+ if (!(hidden instanceof TypeElementImpl)) {
+ return false;
+ }
+ ReferenceBinding hiddenBinding = (ReferenceBinding)((TypeElementImpl)hidden)._binding;
+ if (hiddenBinding.isPrivate()) {
+ return false;
+ }
+ ReferenceBinding hiderBinding = (ReferenceBinding)_binding;
+ if (TypeBinding.equalsEquals(hiddenBinding, hiderBinding)) {
+ return false;
+ }
+ if (!hiddenBinding.isMemberType() || !hiderBinding.isMemberType()) {
+ return false;
+ }
+ if (!CharOperation.equals(hiddenBinding.sourceName, hiderBinding.sourceName)) {
+ return false;
+ }
+ return null != hiderBinding.enclosingType().findSuperTypeOriginatingFrom(hiddenBinding.enclosingType());
+ }
+
+ @Override
+ public String toString() {
+ ReferenceBinding binding = (ReferenceBinding) this._binding;
+ char[] concatWith = CharOperation.concatWith(binding.compoundName, '.');
+ if (binding.isNestedType()) {
+ CharOperation.replace(concatWith, '$', '.');
+ return new String(concatWith);
+ }
+ return new String(concatWith);
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java
new file mode 100644
index 00000000..74429571
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 BEA Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+/**
+ * Implementation of a TypeMirror. TypeMirror represents a type, including
+ * types that have no declaration, such as primitives (int, boolean) and
+ * types that are specializations of declarations (List<String>).
+ */
+public class TypeMirrorImpl implements TypeMirror {
+
+ // Caution: _env will be NULL for unannotated primitive types (PrimitiveTypeImpl).
+ protected final BaseProcessingEnvImpl _env;
+ protected final Binding _binding;
+
+ /* package */ TypeMirrorImpl(BaseProcessingEnvImpl env, Binding binding) {
+ _env = env;
+ _binding = binding;
+ }
+
+ /* package */ Binding binding() {
+ return _binding;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visit(this, p);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ switch (_binding.kind()) {
+ // case Binding.TYPE:
+ // case Binding.RAW_TYPE:
+ // case Binding.GENERIC_TYPE:
+ // case Binding.PARAMETERIZED_TYPE:
+ // handled by DeclaredTypeImpl, etc.
+ // case Binding.BASE_TYPE: handled by PrimitiveTypeImpl
+ // case Binding.METHOD: handled by ExecutableTypeImpl
+ // case Binding.PACKAGE: handled by NoTypeImpl
+ // case Binding.WILDCARD_TYPE: handled by WildcardTypeImpl
+ // case Binding.ARRAY_TYPE: handled by ArrayTypeImpl
+ // case Binding.TYPE_PARAMETER: handled by TypeVariableImpl
+ // TODO: fill in the rest of these
+ case Binding.FIELD:
+ case Binding.LOCAL:
+ case Binding.VARIABLE:
+ case Binding.IMPORT:
+ throw new IllegalArgumentException("Invalid binding kind: " + _binding.kind()); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_binding == null) ? 0 : _binding.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof TypeMirrorImpl))
+ return false;
+ final TypeMirrorImpl other = (TypeMirrorImpl) obj;
+ return _binding == other._binding;
+ }
+
+ /* Package any repeating annotations into containers, return others as is.
+ In the compiler bindings repeating annotations are left in as is, hence
+ this step. The return value would match what one would expect to see in
+ a class file.
+ */
+ public final AnnotationBinding [] getPackedAnnotationBindings() {
+ return Factory.getPackedAnnotationBindings(getAnnotationBindings());
+ }
+
+ protected AnnotationBinding[] getAnnotationBindings() {
+ return ((TypeBinding)_binding).getTypeAnnotations();
+ }
+
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return _env == null ? Factory.EMPTY_ANNOTATION_MIRRORS :
+ _env.getFactory().getAnnotationMirrors(getPackedAnnotationBindings());
+ }
+
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return _env == null ? null : _env.getFactory().getAnnotation(getPackedAnnotationBindings(), annotationType);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ if (_env == null)
+ return (A[]) Array.newInstance(annotationType, 0);
+ return _env.getFactory().getAnnotationsByType(Factory.getUnpackedAnnotationBindings(getPackedAnnotationBindings()), annotationType);
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java
new file mode 100644
index 00000000..34f0de59
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342470
+ * IBM Corporation - fix for 342598
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ *
+ */
+public class TypeParameterElementImpl extends ElementImpl implements TypeParameterElement
+{
+ private final Element _declaringElement;
+
+ // Cache the bounds, because they're expensive to compute
+ private List<? extends TypeMirror> _bounds = null;
+
+ /* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding, Element declaringElement) {
+ super(env, binding);
+ _declaringElement = declaringElement;
+ }
+
+ /* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) {
+ super(env, binding);
+ _declaringElement = _env.getFactory().newElement(binding.declaringElement);
+ }
+
+ @Override
+ public List<? extends TypeMirror> getBounds()
+ {
+ if (null == _bounds) {
+ _bounds = calculateBounds();
+ }
+ return _bounds;
+ }
+
+ // This code is drawn from org.eclipse.jdt.core.dom.TypeBinding.getTypeBounds()
+ private List<? extends TypeMirror> calculateBounds() {
+ TypeVariableBinding typeVariableBinding = (TypeVariableBinding)_binding;
+ ReferenceBinding varSuperclass = typeVariableBinding.superclass();
+ TypeBinding firstClassOrArrayBound = typeVariableBinding.firstBound;
+ int boundsLength = 0;
+ boolean isFirstBoundATypeVariable = false;
+ if (firstClassOrArrayBound != null) {
+ if (firstClassOrArrayBound.isTypeVariable()) {
+ isFirstBoundATypeVariable = true;
+ }
+ if (TypeBinding.equalsEquals(firstClassOrArrayBound, varSuperclass)) {
+ boundsLength++;
+ if (firstClassOrArrayBound.isTypeVariable()) {
+ isFirstBoundATypeVariable = true;
+ }
+ } else if (firstClassOrArrayBound.isArrayType()) { // capture of ? extends/super arrayType
+ boundsLength++;
+ } else {
+ firstClassOrArrayBound = null;
+ }
+ }
+ ReferenceBinding[] superinterfaces = typeVariableBinding.superInterfaces();
+ int superinterfacesLength = 0;
+ if (superinterfaces != null) {
+ superinterfacesLength = superinterfaces.length;
+ boundsLength += superinterfacesLength;
+ }
+ List<TypeMirror> typeBounds = new ArrayList<TypeMirror>(boundsLength);
+ if (boundsLength != 0) {
+ if (firstClassOrArrayBound != null) {
+ TypeMirror typeBinding = _env.getFactory().newTypeMirror(firstClassOrArrayBound);
+ if (typeBinding == null) {
+ return Collections.emptyList();
+ }
+ typeBounds.add(typeBinding);
+ }
+ // we need to filter out remaining bounds if the first bound is a type variable
+ if (superinterfaces != null && !isFirstBoundATypeVariable) {
+ for (int i = 0; i < superinterfacesLength; i++) {
+ TypeMirror typeBinding = _env.getFactory().newTypeMirror(superinterfaces[i]);
+ if (typeBinding == null) {
+ return Collections.emptyList();
+ }
+ typeBounds.add(typeBinding);
+ }
+ }
+ } else {
+ // at least we must add java.lang.Object
+ typeBounds.add(_env.getFactory().newTypeMirror(_env.getLookupEnvironment().getType(LookupEnvironment.JAVA_LANG_OBJECT)));
+ }
+ return Collections.unmodifiableList(typeBounds);
+ }
+
+ @Override
+ public Element getGenericElement()
+ {
+ return _declaringElement;
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitTypeParameter(this, p);
+ }
+
+ /*
+ * (non-Javadoc)
+ * Java supports annotations on type parameters from JLS8
+ * @see javax.lang.model.element.Element#getAnnotationMirrors()
+ */
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((TypeVariableBinding)_binding).getTypeAnnotations();
+ }
+
+ private boolean shouldEmulateJavacBug() {
+ if (_env.getLookupEnvironment().globalOptions.emulateJavacBug8031744) {
+ AnnotationBinding [] annotations = getAnnotationBindings();
+ for (int i = 0, length = annotations.length; i < length; i++) {
+ ReferenceBinding firstAnnotationType = annotations[i].getAnnotationType();
+ for (int j = i+1; j < length; j++) {
+ ReferenceBinding secondAnnotationType = annotations[j].getAnnotationType();
+ if (firstAnnotationType == secondAnnotationType) //$IDENTITY-COMPARISON$
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ if (shouldEmulateJavacBug())
+ return Collections.emptyList();
+ return super.getAnnotationMirrors();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked") // for the cast to A
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ if (shouldEmulateJavacBug())
+ return (A[]) Array.newInstance(annotationType, 0);
+ return super.getAnnotationsByType(annotationType);
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ if (shouldEmulateJavacBug())
+ return null;
+ return super.getAnnotation(annotationType);
+ }
+
+ /*
+ * (non-Javadoc)
+ * Always return an empty list; type parameters do not enclose other elements.
+ * @see javax.lang.model.element.Element#getEnclosedElements()
+ */
+ @Override
+ public List<? extends Element> getEnclosedElements()
+ {
+ return Collections.emptyList();
+ }
+
+ /*
+ * (non-Javadoc)
+ * Always return null.
+ * @see javax.lang.model.element.Element#getEnclosingElement()
+ */
+ @Override
+ public Element getEnclosingElement()
+ {
+ return getGenericElement();
+ }
+
+ @Override
+ public ElementKind getKind()
+ {
+ return ElementKind.TYPE_PARAMETER;
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ // TODO what is the package of a type parameter?
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
new file mode 100644
index 00000000..2fd4f4fd
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of TypeVariable
+ */
+public class TypeVariableImpl extends TypeMirrorImpl implements TypeVariable {
+
+ TypeVariableImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) {
+ super(env, binding);
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeVariable#asElement()
+ */
+ @Override
+ public Element asElement() {
+ return _env.getFactory().newElement(this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeVariable#getLowerBound()
+ */
+ @Override
+ public TypeMirror getLowerBound() {
+ // TODO might be more complex than this
+ return this._env.getFactory().getNullType();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeVariable#getUpperBound()
+ */
+ @Override
+ public TypeMirror getUpperBound() {
+ TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this._binding;
+ TypeBinding firstBound = typeVariableBinding.firstBound;
+ ReferenceBinding[] superInterfaces = typeVariableBinding.superInterfaces;
+ if (firstBound == null || superInterfaces.length == 0) {
+ // no explicit bound
+ return _env.getFactory().newTypeMirror(typeVariableBinding.upperBound());
+ }
+ if (firstBound != null && superInterfaces.length == 1 && TypeBinding.equalsEquals(superInterfaces[0], firstBound)) {
+ // only one bound that is an interface
+ return _env.getFactory().newTypeMirror(typeVariableBinding.upperBound());
+ }
+ return this._env.getFactory().newTypeMirror((TypeVariableBinding) this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitTypeVariable(this, p);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.TYPEVAR;
+ }
+
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
new file mode 100644
index 00000000..6ac131e1
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
@@ -0,0 +1,479 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 BEA Systems, Inc. and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.NullType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.Types;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Utilities for working with types (as opposed to elements).
+ * There is one of these for every ProcessingEnvironment.
+ */
+public class TypesImpl implements Types {
+
+ private final BaseProcessingEnvImpl _env;
+
+ /*
+ * The processing env creates and caches a TypesImpl. Other clients should
+ * not create their own; they should ask the env for it.
+ */
+ public TypesImpl(BaseProcessingEnvImpl env) {
+ _env = env;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#asElement(javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public Element asElement(TypeMirror t) {
+ switch(t.getKind()) {
+ case DECLARED :
+ case TYPEVAR :
+ return _env.getFactory().newElement(((TypeMirrorImpl)t).binding());
+ default:
+ break;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#asMemberOf(javax.lang.model.type.DeclaredType, javax.lang.model.element.Element)
+ */
+ @Override
+ public TypeMirror asMemberOf(DeclaredType containing, Element element) {
+// throw new UnsupportedOperationException("NYI: TypesImpl.asMemberOf(" + containing + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ElementImpl elementImpl = (ElementImpl) element;
+ DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
+ ReferenceBinding referenceBinding = (ReferenceBinding) declaredTypeImpl._binding;
+ switch(element.getKind()) {
+ case CONSTRUCTOR :
+ case METHOD :
+ MethodBinding methodBinding = (MethodBinding) elementImpl._binding;
+ if (TypeBinding.notEquals(methodBinding.declaringClass, referenceBinding)) {
+ throw new IllegalArgumentException("element is not valid for the containing declared type"); //$NON-NLS-1$
+ }
+ for (MethodBinding method : referenceBinding.methods()) {
+ if (CharOperation.equals(method.selector, methodBinding.selector)
+ && method.areParameterErasuresEqual(methodBinding)) {
+ return this._env.getFactory().newTypeMirror(method);
+ }
+ }
+ break;
+ case FIELD :
+ case ENUM_CONSTANT:
+ FieldBinding fieldBinding = (FieldBinding) elementImpl._binding;
+ if (TypeBinding.notEquals(fieldBinding.declaringClass, referenceBinding)) {
+ throw new IllegalArgumentException("element is not valid for the containing declared type"); //$NON-NLS-1$
+ }
+ for (FieldBinding field : referenceBinding.fields()) {
+ if (CharOperation.equals(field.name, fieldBinding.name)) {
+ return this._env.getFactory().newTypeMirror(field);
+ }
+ }
+ break;
+ case ENUM :
+ case ANNOTATION_TYPE :
+ case INTERFACE :
+ case CLASS :
+ ReferenceBinding referenceBinding2 = (ReferenceBinding) elementImpl._binding;
+ if (TypeBinding.notEquals(referenceBinding2.enclosingType(), referenceBinding)) {
+ throw new IllegalArgumentException("element is not valid for the containing declared type"); //$NON-NLS-1$
+ }
+ for (ReferenceBinding referenceBinding3 : referenceBinding.memberTypes()) {
+ if (CharOperation.equals(referenceBinding3.compoundName, referenceBinding3.compoundName)) {
+ return this._env.getFactory().newTypeMirror(referenceBinding3);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException("element is not valid for the containing declared type: element kind " + element.getKind()); //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#boxedClass(javax.lang.model.type.PrimitiveType)
+ */
+ @Override
+ public TypeElement boxedClass(PrimitiveType p) {
+ PrimitiveTypeImpl primitiveTypeImpl = (PrimitiveTypeImpl) p;
+ BaseTypeBinding baseTypeBinding = (BaseTypeBinding)primitiveTypeImpl._binding;
+ TypeBinding boxed = _env.getLookupEnvironment().computeBoxingType(baseTypeBinding);
+ return (TypeElement) _env.getFactory().newElement(boxed);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#capture(javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public TypeMirror capture(TypeMirror t) {
+ throw new UnsupportedOperationException("NYI: TypesImpl.capture(...)"); //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#contains(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public boolean contains(TypeMirror t1, TypeMirror t2) {
+ switch(t1.getKind()) {
+ case EXECUTABLE :
+ case PACKAGE :
+ throw new IllegalArgumentException("Executable and package are illegal argument for Types.contains(..)"); //$NON-NLS-1$
+ default:
+ break;
+ }
+ switch(t2.getKind()) {
+ case EXECUTABLE :
+ case PACKAGE :
+ throw new IllegalArgumentException("Executable and package are illegal argument for Types.contains(..)"); //$NON-NLS-1$
+ default:
+ break;
+ }
+ throw new UnsupportedOperationException("NYI: TypesImpl.contains(" + t1 + ", " + t2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#directSupertypes(javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
+ switch(t.getKind()) {
+ case PACKAGE :
+ case EXECUTABLE :
+ throw new IllegalArgumentException("Invalid type mirror for directSupertypes"); //$NON-NLS-1$
+ default:
+ break;
+ }
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
+ Binding binding = typeMirrorImpl._binding;
+ if (binding instanceof ReferenceBinding) {
+ ReferenceBinding referenceBinding = (ReferenceBinding) binding;
+ ArrayList<TypeMirror> list = new ArrayList<TypeMirror>();
+ ReferenceBinding superclass = referenceBinding.superclass();
+ if (superclass != null) {
+ list.add(this._env.getFactory().newTypeMirror(superclass));
+ }
+ for (ReferenceBinding interfaceBinding : referenceBinding.superInterfaces()) {
+ list.add(this._env.getFactory().newTypeMirror(interfaceBinding));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#erasure(javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public TypeMirror erasure(TypeMirror t) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
+ Binding binding = typeMirrorImpl._binding;
+ if (binding instanceof ReferenceBinding) {
+ return _env.getFactory().newTypeMirror(((ReferenceBinding) binding).erasure());
+ }
+ if (binding instanceof ArrayBinding) {
+ TypeBinding typeBinding = (TypeBinding) binding;
+ return _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createArrayType(
+ typeBinding.leafComponentType().erasure(),
+ typeBinding.dimensions()));
+ }
+ return t;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#getArrayType(javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public ArrayType getArrayType(TypeMirror componentType) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) componentType;
+ TypeBinding typeBinding = (TypeBinding) typeMirrorImpl._binding;
+ return (ArrayType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createArrayType(
+ typeBinding.leafComponentType(),
+ typeBinding.dimensions() + 1));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#getDeclaredType(javax.lang.model.element.TypeElement, javax.lang.model.type.TypeMirror[])
+ */
+ @Override
+ public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
+ int typeArgsLength = typeArgs.length;
+ TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem;
+ ReferenceBinding referenceBinding = (ReferenceBinding) typeElementImpl._binding;
+ TypeVariableBinding[] typeVariables = referenceBinding.typeVariables();
+ int typeVariablesLength = typeVariables.length;
+ if (typeArgsLength == 0) {
+ if (referenceBinding.isGenericType()) {
+ // must return a raw type
+ return (DeclaredType) _env.getFactory().newTypeMirror(this._env.getLookupEnvironment().createRawType(referenceBinding, null));
+ }
+ return (DeclaredType)typeElem.asType();
+ } else if (typeArgsLength != typeVariablesLength) {
+ throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$
+ }
+ TypeBinding[] typeArguments = new TypeBinding[typeArgsLength];
+ for (int i = 0; i < typeArgsLength; i++) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i];
+ Binding binding = typeMirrorImpl._binding;
+ if (!(binding instanceof TypeBinding)) {
+ throw new IllegalArgumentException("Invalid type argument: " + typeMirrorImpl); //$NON-NLS-1$
+ }
+ typeArguments[i] = (TypeBinding) binding;
+ }
+ return (DeclaredType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createParameterizedType(referenceBinding, typeArguments, null));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#getDeclaredType(javax.lang.model.type.DeclaredType, javax.lang.model.element.TypeElement, javax.lang.model.type.TypeMirror[])
+ */
+ @Override
+ public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem,
+ TypeMirror... typeArgs) {
+ int typeArgsLength = typeArgs.length;
+ TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem;
+ ReferenceBinding referenceBinding = (ReferenceBinding) typeElementImpl._binding;
+ TypeVariableBinding[] typeVariables = referenceBinding.typeVariables();
+ int typeVariablesLength = typeVariables.length;
+ DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
+ ReferenceBinding enclosingType = (ReferenceBinding) declaredTypeImpl._binding;
+ if (typeArgsLength == 0) {
+ if (referenceBinding.isGenericType()) {
+ // must return a raw type
+ return (DeclaredType) _env.getFactory().newTypeMirror(this._env.getLookupEnvironment().createRawType(referenceBinding, enclosingType));
+ }
+ // TODO (see how to create a member type binding
+ throw new UnsupportedOperationException("NYI: TypesImpl.getDeclaredType(...) for member types"); //$NON-NLS-1$
+ } else if (typeArgsLength != typeVariablesLength) {
+ throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$
+ }
+ TypeBinding[] typeArguments = new TypeBinding[typeArgsLength];
+ for (int i = 0; i < typeArgsLength; i++) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i];
+ Binding binding = typeMirrorImpl._binding;
+ if (!(binding instanceof TypeBinding)) {
+ throw new IllegalArgumentException("Invalid type for a type arguments : " + typeMirrorImpl); //$NON-NLS-1$
+ }
+ typeArguments[i] = (TypeBinding) binding;
+ }
+ return (DeclaredType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createParameterizedType(referenceBinding, typeArguments, enclosingType));
+ }
+
+ @Override
+ public NoType getNoType(TypeKind kind) {
+ return _env.getFactory().getNoType(kind);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#getNullType()
+ */
+ @Override
+ public NullType getNullType() {
+ return _env.getFactory().getNullType();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#getPrimitiveType(javax.lang.model.type.TypeKind)
+ */
+ @Override
+ public PrimitiveType getPrimitiveType(TypeKind kind) {
+ return _env.getFactory().getPrimitiveType(kind);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#getWildcardType(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) {
+ if (extendsBound != null && superBound != null) {
+ throw new IllegalArgumentException("Extends and super bounds cannot be set at the same time"); //$NON-NLS-1$
+ }
+ if (extendsBound != null) {
+ TypeMirrorImpl extendsBoundMirrorType = (TypeMirrorImpl) extendsBound;
+ TypeBinding typeBinding = (TypeBinding) extendsBoundMirrorType._binding;
+ return (WildcardType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createWildcard(
+ null,
+ 0,
+ typeBinding,
+ null,
+ Wildcard.EXTENDS));
+ }
+ if (superBound != null) {
+ TypeMirrorImpl superBoundMirrorType = (TypeMirrorImpl) superBound;
+ TypeBinding typeBinding = (TypeBinding) superBoundMirrorType._binding;
+ return new WildcardTypeImpl(_env, this._env.getLookupEnvironment().createWildcard(
+ null,
+ 0,
+ typeBinding,
+ null,
+ Wildcard.SUPER));
+ }
+ return new WildcardTypeImpl(_env, this._env.getLookupEnvironment().createWildcard(
+ null,
+ 0,
+ null,
+ null,
+ Wildcard.UNBOUND));
+ }
+
+ /**
+ * @return true if a value of type t1 can be assigned to a variable of type t2, i.e., t2 = t1.
+ */
+ @Override
+ public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
+ if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
+ return false;
+ }
+ Binding b1 = ((TypeMirrorImpl)t1).binding();
+ Binding b2 = ((TypeMirrorImpl)t2).binding();
+ if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
+ // package, method, import, etc.
+ throw new IllegalArgumentException();
+ }
+ if (((TypeBinding)b1).isCompatibleWith((TypeBinding)b2)) {
+ return true;
+ }
+
+ TypeBinding convertedType = _env.getLookupEnvironment().computeBoxingType((TypeBinding)b1);
+ return null != convertedType && convertedType.isCompatibleWith((TypeBinding)b2);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#isSameType(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public boolean isSameType(TypeMirror t1, TypeMirror t2) {
+ if (t1.getKind() == TypeKind.WILDCARD || t2.getKind() == TypeKind.WILDCARD) {
+ // Wildcard types are never equal, according to the spec of this method
+ return false;
+ }
+ if (t1 == t2) {
+ return true;
+ }
+ if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
+ return false;
+ }
+ Binding b1 = ((TypeMirrorImpl)t1).binding();
+ Binding b2 = ((TypeMirrorImpl)t2).binding();
+
+ if (b1 == b2) {
+ return true;
+ }
+ if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
+ return false;
+ }
+ TypeBinding type1 = ((TypeBinding) b1);
+ TypeBinding type2 = ((TypeBinding) b2);
+ if (TypeBinding.equalsEquals(type1, type2))
+ return true;
+ return CharOperation.equals(type1.computeUniqueKey(), type2.computeUniqueKey());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#isSubsignature(javax.lang.model.type.ExecutableType, javax.lang.model.type.ExecutableType)
+ */
+ @Override
+ public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
+ MethodBinding methodBinding1 = (MethodBinding) ((ExecutableTypeImpl) m1)._binding;
+ MethodBinding methodBinding2 = (MethodBinding) ((ExecutableTypeImpl) m2)._binding;
+ if (!CharOperation.equals(methodBinding1.selector, methodBinding2.selector))
+ return false;
+ return methodBinding1.areParameterErasuresEqual(methodBinding2) && methodBinding1.areTypeVariableErasuresEqual(methodBinding2);
+ }
+
+ /**
+ * @return true if t1 is a subtype of t2, or if t1 == t2.
+ */
+ @Override
+ public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
+ if (t1 instanceof NoTypeImpl) {
+ if (t2 instanceof NoTypeImpl) {
+ return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind();
+ }
+ return false;
+ } else if (t2 instanceof NoTypeImpl) {
+ return false;
+ }
+ if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
+ return false;
+ }
+ if (t1 == t2) {
+ return true;
+ }
+ Binding b1 = ((TypeMirrorImpl)t1).binding();
+ Binding b2 = ((TypeMirrorImpl)t2).binding();
+ if (b1 == b2) {
+ return true;
+ }
+ if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
+ // package, method, import, etc.
+ return false;
+ }
+ if (b1.kind() == Binding.BASE_TYPE || b2.kind() == Binding.BASE_TYPE) {
+ if (b1.kind() != b2.kind()) {
+ return false;
+ }
+ else {
+ // for primitives, compatibility implies subtype
+ return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2);
+ }
+ }
+ return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2);
+ }
+
+ @Override
+ public PrimitiveType unboxedType(TypeMirror t) {
+ if (!(((TypeMirrorImpl)t)._binding instanceof ReferenceBinding)) {
+ // Not an unboxable type - could be primitive, array, not a type at all, etc.
+ throw new IllegalArgumentException("Given type mirror cannot be unboxed"); //$NON-NLS-1$
+ }
+ ReferenceBinding boxed = (ReferenceBinding)((TypeMirrorImpl)t)._binding;
+ TypeBinding unboxed = _env.getLookupEnvironment().computeBoxingType(boxed);
+ if (unboxed.kind() != Binding.BASE_TYPE) {
+ // No boxing conversion was found
+ throw new IllegalArgumentException();
+ }
+ return (PrimitiveType) _env.getFactory().newTypeMirror((BaseTypeBinding)unboxed);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java
new file mode 100644
index 00000000..74187817
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.VariableElement;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptBinaryLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
+
+/**
+ * Implementation of VariableElement, which represents a a field, enum constant,
+ * method or constructor parameter, local variable, or exception parameter.
+ */
+public class VariableElementImpl extends ElementImpl implements VariableElement {
+
+ /**
+ * @param binding might be a FieldBinding (for a field) or a LocalVariableBinding (for a method param)
+ */
+ VariableElementImpl(BaseProcessingEnvImpl env, VariableBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitVariable(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((VariableBinding)_binding).getAnnotations();
+ }
+
+ @Override
+ public Object getConstantValue() {
+ VariableBinding variableBinding = (VariableBinding) _binding;
+ Constant constant = variableBinding.constant();
+ if (constant == null || constant == Constant.NotAConstant) return null;
+ TypeBinding type = variableBinding.type;
+ switch (type.id) {
+ case TypeIds.T_boolean:
+ return constant.booleanValue();
+ case TypeIds.T_byte:
+ return constant.byteValue();
+ case TypeIds.T_char:
+ return constant.charValue();
+ case TypeIds.T_double:
+ return constant.doubleValue();
+ case TypeIds.T_float:
+ return constant.floatValue();
+ case TypeIds.T_int:
+ return constant.intValue();
+ case TypeIds.T_JavaLangString:
+ return constant.stringValue();
+ case TypeIds.T_long:
+ return constant.longValue();
+ case TypeIds.T_short:
+ return constant.shortValue();
+ }
+ return null;
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ if (_binding instanceof FieldBinding) {
+ return _env.getFactory().newElement(((FieldBinding)_binding).declaringClass);
+ }
+ else if (_binding instanceof AptSourceLocalVariableBinding){
+ return _env.getFactory().newElement(((AptSourceLocalVariableBinding) _binding).methodBinding);
+ } else if (_binding instanceof AptBinaryLocalVariableBinding) {
+ return _env.getFactory().newElement(((AptBinaryLocalVariableBinding) _binding).methodBinding);
+ }
+ return null;
+ }
+
+ @Override
+ public ElementKind getKind() {
+ if (_binding instanceof FieldBinding) {
+ if (((FieldBinding)_binding).declaringClass.isEnum()) {
+ return ElementKind.ENUM_CONSTANT;
+ }
+ else {
+ return ElementKind.FIELD;
+ }
+ }
+ else {
+ return ElementKind.PARAMETER;
+ }
+ }
+
+ @Override
+ public Set<Modifier> getModifiers()
+ {
+ if (_binding instanceof VariableBinding) {
+ return Factory.getModifiers(((VariableBinding)_binding).modifiers, getKind());
+ }
+ return Collections.emptySet();
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ if (_binding instanceof FieldBinding) {
+ PackageBinding pkgBinding = ((FieldBinding)_binding).declaringClass.fPackage;
+ return _env.getFactory().newPackageElement(pkgBinding);
+ }
+ else {
+ // TODO: what is the package of a method parameter?
+ throw new UnsupportedOperationException("NYI: VariableElmentImpl.getPackage() for method parameter"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Name getSimpleName() {
+ return new NameImpl(((VariableBinding)_binding).name);
+ }
+
+ @Override
+ public boolean hides(Element hiddenElement)
+ {
+ if (_binding instanceof FieldBinding) {
+ if (!(((ElementImpl)hiddenElement)._binding instanceof FieldBinding)) {
+ return false;
+ }
+ FieldBinding hidden = (FieldBinding)((ElementImpl)hiddenElement)._binding;
+ if (hidden.isPrivate()) {
+ return false;
+ }
+ FieldBinding hider = (FieldBinding)_binding;
+ if (hidden == hider) {
+ return false;
+ }
+ if (!CharOperation.equals(hider.name, hidden.name)) {
+ return false;
+ }
+ return null != hider.declaringClass.findSuperTypeOriginatingFrom(hidden.declaringClass);
+ }
+ // TODO: should we implement hides() for method parameters?
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return new String(((VariableBinding) _binding).name);
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java
new file mode 100644
index 00000000..c341cc40
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.type.WildcardType;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
+
+/**
+ * Implementation of the WildcardType
+ */
+public class WildcardTypeImpl extends TypeMirrorImpl implements WildcardType {
+
+ WildcardTypeImpl(BaseProcessingEnvImpl env, WildcardBinding binding) {
+ super(env, binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.WildcardType#getExtendsBound()
+ */
+ @Override
+ public TypeMirror getExtendsBound() {
+ WildcardBinding wildcardBinding = (WildcardBinding) this._binding;
+ if (wildcardBinding.boundKind != Wildcard.EXTENDS) return null;
+ TypeBinding bound = wildcardBinding.bound;
+ if (bound == null) return null;
+ return _env.getFactory().newTypeMirror(bound);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.WILDCARD;
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.WildcardType#getSuperBound()
+ */
+ @Override
+ public TypeMirror getSuperBound() {
+ WildcardBinding wildcardBinding = (WildcardBinding) this._binding;
+ if (wildcardBinding.boundKind != Wildcard.SUPER) return null;
+ TypeBinding bound = wildcardBinding.bound;
+ if (bound == null) return null;
+ return _env.getFactory().newTypeMirror(bound);
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitWildcard(this, p);
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Archive.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
new file mode 100644
index 00000000..c8765235
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Used as a zip file cache.
+ */
+public class Archive {
+
+ public static final Archive UNKNOWN_ARCHIVE = new Archive();
+
+ ZipFile zipFile;
+ File file;
+ protected Hashtable<String, ArrayList<String>> packagesCache;
+
+ private Archive() {
+ }
+
+ public Archive(File file) throws ZipException, IOException {
+ this.file = file;
+ this.zipFile = new ZipFile(file);
+ initialize();
+ }
+
+ private void initialize() {
+ // initialize packages
+ this.packagesCache = new Hashtable<String, ArrayList<String>>();
+ nextEntry : for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) {
+ String fileName = ((ZipEntry) e.nextElement()).getName();
+
+ // add the package name & all of its parent packages
+ int last = fileName.lastIndexOf('/');
+ // extract the package name
+ String packageName = fileName.substring(0, last + 1);
+ String typeName = fileName.substring(last + 1);
+ ArrayList<String> types = this.packagesCache.get(packageName);
+ if (types == null) {
+ // might be empty if this is a directory entry
+ if (typeName.length() == 0) {
+ continue nextEntry;
+ }
+ types = new ArrayList<String>();
+ types.add(typeName);
+ this.packagesCache.put(packageName, types);
+ } else {
+ types.add(typeName);
+ }
+ }
+ }
+
+ public ArchiveFileObject getArchiveFileObject(String entryName, Charset charset) {
+ return new ArchiveFileObject(this.file, this.zipFile, entryName, charset);
+ }
+
+ public boolean contains(String entryName) {
+ return this.zipFile.getEntry(entryName) != null;
+ }
+
+ public Set<String> allPackages() {
+ if (this.packagesCache == null) {
+ this.initialize();
+ }
+ return this.packagesCache.keySet();
+ }
+
+ public ArrayList<String> getTypes(String packageName) {
+ // package name is expected to ends with '/'
+ return this.packagesCache.get(packageName);
+ }
+
+ public void flush() {
+ this.packagesCache = null;
+ }
+
+ public void close() {
+ try {
+ if (this.zipFile != null) this.zipFile.close();
+ this.packagesCache = null;
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
new file mode 100644
index 00000000..adae21a2
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+
+/**
+ * Implementation of a Java file object that corresponds to an entry in a zip/jar file
+ */
+public class ArchiveFileObject implements JavaFileObject {
+ private ZipEntry zipEntry;
+ private ZipFile zipFile;
+ private String entryName;
+ private File file;
+ private Charset charset;
+
+ public ArchiveFileObject(File file, ZipFile zipFile, String entryName, Charset charset) {
+ this.zipFile = zipFile;
+ this.zipEntry = zipFile.getEntry(entryName);
+ this.entryName = entryName;
+ this.file = file;
+ this.charset = charset;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getAccessLevel()
+ */
+ public Modifier getAccessLevel() {
+ // cannot express multiple modifier
+ if (getKind() != Kind.CLASS) {
+ return null;
+ }
+ ClassFileReader reader = null;
+ try {
+ reader = ClassFileReader.read(this.zipFile, this.entryName);
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ // ignore
+ }
+ if (reader == null) {
+ return null;
+ }
+ final int accessFlags = reader.accessFlags();
+ if ((accessFlags & ClassFileConstants.AccPublic) != 0) {
+ return Modifier.PUBLIC;
+ }
+ if ((accessFlags & ClassFileConstants.AccAbstract) != 0) {
+ return Modifier.ABSTRACT;
+ }
+ if ((accessFlags & ClassFileConstants.AccFinal) != 0) {
+ return Modifier.FINAL;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getKind()
+ */
+ public Kind getKind() {
+ String name = this.entryName.toLowerCase();
+ if (name.endsWith(Kind.CLASS.extension)) {
+ return Kind.CLASS;
+ } else if (name.endsWith(Kind.SOURCE.extension)) {
+ return Kind.SOURCE;
+ } else if (name.endsWith(Kind.HTML.extension)) {
+ return Kind.HTML;
+ }
+ return Kind.OTHER;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getNestingKind()
+ */
+ public NestingKind getNestingKind() {
+ switch(getKind()) {
+ case SOURCE :
+ return NestingKind.TOP_LEVEL;
+ case CLASS :
+ ClassFileReader reader = null;
+ try {
+ reader = ClassFileReader.read(this.zipFile, this.entryName);
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ // ignore
+ }
+ if (reader == null) {
+ return null;
+ }
+ if (reader.isAnonymous()) {
+ return NestingKind.ANONYMOUS;
+ }
+ if (reader.isLocal()) {
+ return NestingKind.LOCAL;
+ }
+ if (reader.isMember()) {
+ return NestingKind.MEMBER;
+ }
+ return NestingKind.TOP_LEVEL;
+ default:
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#isNameCompatible(java.lang.String, javax.tools.JavaFileObject.Kind)
+ */
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ return this.zipEntry.getName().endsWith(simpleName + kind.extension);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#delete()
+ */
+ public boolean delete() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof ArchiveFileObject)) {
+ return false;
+ }
+ ArchiveFileObject archiveFileObject = (ArchiveFileObject) o;
+ return archiveFileObject.toUri().equals(this.toUri());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getCharContent(boolean)
+ */
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ if (getKind() == Kind.SOURCE) {
+ return Util.getCharContents(this, ignoreEncodingErrors, org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(this.zipEntry, this.zipFile), this.charset.name());
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getLastModified()
+ */
+ public long getLastModified() {
+ return this.zipEntry.getTime(); // looks the closest from the last modification
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getName()
+ */
+ public String getName() {
+ return this.zipEntry.getName();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openInputStream()
+ */
+ public InputStream openInputStream() throws IOException {
+ return this.zipFile.getInputStream(this.zipEntry);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openOutputStream()
+ */
+ public OutputStream openOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openReader(boolean)
+ */
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openWriter()
+ */
+ public Writer openWriter() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#toUri()
+ */
+ public URI toUri() {
+ try {
+ return new URI("jar:" + this.file.toURI().getPath() + "!" + this.zipEntry.getName()); //$NON-NLS-1$//$NON-NLS-2$
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return this.file.getAbsolutePath() + "[" + this.zipEntry.getName() + "]";//$NON-NLS-1$//$NON-NLS-2$
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
new file mode 100644
index 00000000..a54b67ee
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
@@ -0,0 +1,1147 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2014 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.Charset;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.zip.ZipException;
+
+import javax.tools.FileObject;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.JavaFileObject.Kind;
+
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem;
+import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.batch.Main.ResourceBundleFactory;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
+import org.eclipse.jdt.internal.compiler.env.AccessRule;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+
+/**
+ * Implementation of the Standard Java File Manager
+ */
+public class EclipseFileManager implements StandardJavaFileManager {
+ private static final String NO_EXTENSION = "";//$NON-NLS-1$
+ static final int HAS_EXT_DIRS = 1;
+ static final int HAS_BOOTCLASSPATH = 2;
+ static final int HAS_ENDORSED_DIRS = 4;
+ static final int HAS_PROCESSORPATH = 8;
+
+ Map<File, Archive> archivesCache;
+ Charset charset;
+ Locale locale;
+ Map<String, Iterable<? extends File>> locations;
+ int flags;
+ public ResourceBundle bundle;
+
+ public EclipseFileManager(Locale locale, Charset charset) {
+ this.locale = locale == null ? Locale.getDefault() : locale;
+ this.charset = charset == null ? Charset.defaultCharset() : charset;
+ this.locations = new HashMap<String, Iterable<? extends File>>();
+ this.archivesCache = new HashMap<File, Archive>();
+ try {
+ this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath());
+ Iterable<? extends File> defaultClasspath = getDefaultClasspath();
+ this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath);
+ this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath);
+ } catch (IOException e) {
+ // ignore
+ }
+ try {
+ this.bundle = ResourceBundleFactory.getBundle(this.locale);
+ } catch(MissingResourceException e) {
+ System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+
+ private void addFiles(File[][] jars, ArrayList<File> files) {
+ if (jars != null) {
+ for (File[] currentJars : jars) {
+ if (currentJars != null) {
+ for (File currentJar : currentJars) {
+ if (currentJar.exists()) {
+ files.add(currentJar);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ private void addFilesFrom(File javaHome, String propertyName, String defaultPath, ArrayList<File> files) {
+ String extdirsStr = System.getProperty(propertyName);
+ File[] directoriesToCheck = null;
+ if (extdirsStr == null) {
+ if (javaHome != null) {
+ directoriesToCheck = new File[] { new File(javaHome, defaultPath) };
+ }
+ } else {
+ StringTokenizer tokenizer = new StringTokenizer(extdirsStr, File.pathSeparator);
+ ArrayList<String> paths = new ArrayList<String>();
+ while (tokenizer.hasMoreTokens()) {
+ paths.add(tokenizer.nextToken());
+ }
+ if (paths.size() != 0) {
+ directoriesToCheck = new File[paths.size()];
+ for (int i = 0; i < directoriesToCheck.length; i++) {
+ directoriesToCheck[i] = new File(paths.get(i));
+ }
+ }
+ }
+ if (directoriesToCheck != null) {
+ addFiles(Main.getLibrariesFiles(directoriesToCheck), files);
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#close()
+ */
+ public void close() throws IOException {
+ this.locations = null;
+ for (Archive archive : this.archivesCache.values()) {
+ archive.close();
+ }
+ }
+
+ private void collectAllMatchingFiles(File file, String normalizedPackageName, Set<Kind> kinds, boolean recurse, ArrayList<JavaFileObject> collector) {
+ if (!isArchive(file)) {
+ // we must have a directory
+ File currentFile = new File(file, normalizedPackageName);
+ if (!currentFile.exists()) return;
+ String path;
+ try {
+ path = currentFile.getCanonicalPath();
+ } catch (IOException e) {
+ return;
+ }
+ if (File.separatorChar == '/') {
+ if (!path.endsWith(normalizedPackageName)) return;
+ } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return;
+ File[] files = currentFile.listFiles();
+ if (files != null) {
+ // this was a directory
+ for (File f : files) {
+ if (f.isDirectory() && recurse) {
+ collectAllMatchingFiles(file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector);
+ } else {
+ final Kind kind = getKind(f);
+ if (kinds.contains(kind)) {
+ collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset));
+ }
+ }
+ }
+ }
+ } else {
+ Archive archive = this.getArchive(file);
+ String key = normalizedPackageName;
+ if (!normalizedPackageName.endsWith("/")) {//$NON-NLS-1$
+ key += '/';
+ }
+ // we have an archive file
+ if (recurse) {
+ for (String packageName : archive.allPackages()) {
+ if (packageName.startsWith(key)) {
+ ArrayList<String> types = archive.getTypes(packageName);
+ if (types != null) {
+ for (String typeName : types) {
+ final Kind kind = getKind(getExtension(typeName));
+ if (kinds.contains(kind)) {
+ collector.add(archive.getArchiveFileObject(packageName + typeName, this.charset));
+ }
+ }
+ }
+ }
+ }
+ } else {
+ ArrayList<String> types = archive.getTypes(key);
+ if (types != null) {
+ for (String typeName : types) {
+ final Kind kind = getKind(typeName);
+ if (kinds.contains(kind)) {
+ collector.add(archive.getArchiveFileObject(normalizedPackageName + typeName, this.charset));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private Iterable<? extends File> concatFiles(Iterable<? extends File> iterable, Iterable<? extends File> iterable2) {
+ ArrayList<File> list = new ArrayList<File>();
+ if (iterable2 == null) return iterable;
+ for (Iterator<? extends File> iterator = iterable.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ for (Iterator<? extends File> iterator = iterable2.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#flush()
+ */
+ public void flush() throws IOException {
+ for (Archive archive : this.archivesCache.values()) {
+ archive.flush();
+ }
+ }
+
+ private Archive getArchive(File f) {
+ // check the archive (jar/zip) cache
+ Archive archive = this.archivesCache.get(f);
+ if (archive == null) {
+ // create a new archive
+ if (f.exists()) {
+ try {
+ archive = new Archive(f);
+ } catch (ZipException e) {
+ // ignore
+ } catch (IOException e) {
+ // ignore
+ }
+ if (archive != null) {
+ this.archivesCache.put(f, archive);
+ } else {
+ this.archivesCache.put(f, Archive.UNKNOWN_ARCHIVE);
+ }
+ } else {
+ this.archivesCache.put(f, Archive.UNKNOWN_ARCHIVE);
+ }
+ }
+ return archive;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getClassLoader(javax.tools.JavaFileManager.Location)
+ */
+ public ClassLoader getClassLoader(Location location) {
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ // location is unknown
+ return null;
+ }
+ ArrayList<URL> allURLs = new ArrayList<URL>();
+ for (File f : files) {
+ try {
+ allURLs.add(f.toURI().toURL());
+ } catch (MalformedURLException e) {
+ // the url is malformed - this should not happen
+ throw new RuntimeException(e);
+ }
+ }
+ URL[] result = new URL[allURLs.size()];
+ return new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader());
+ }
+
+ private Iterable<? extends File> getPathsFrom(String path) {
+ ArrayList<FileSystem.Classpath> paths = new ArrayList<FileSystem.Classpath>();
+ ArrayList<File> files = new ArrayList<File>();
+ try {
+ this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ for (FileSystem.Classpath classpath : paths) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ Iterable<? extends File> getDefaultBootclasspath() {
+ ArrayList<File> files = new ArrayList<File>();
+ String javaversion = System.getProperty("java.version");//$NON-NLS-1$
+ if(javaversion.length() > 3)
+ javaversion = javaversion.substring(0, 3);
+ long jdkLevel = CompilerOptions.versionToJdkLevel(javaversion);
+ if (jdkLevel < ClassFileConstants.JDK1_6) {
+ // wrong jdk - 1.6 or above is required
+ return null;
+ }
+
+ /*
+ * Handle >= JDK 1.6
+ */
+ String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+ File javaHomeFile = null;
+ if (javaHome != null) {
+ javaHomeFile = new File(javaHome);
+ if (!javaHomeFile.exists())
+ javaHomeFile = null;
+ }
+
+ addFilesFrom(javaHomeFile, "java.endorsed.dirs", "/lib/endorsed", files);//$NON-NLS-1$//$NON-NLS-2$
+ if (javaHomeFile != null) {
+ File[] directoriesToCheck = null;
+ if (System.getProperty("os.name").startsWith("Mac")) {//$NON-NLS-1$//$NON-NLS-2$
+ directoriesToCheck = new File[] { new File(javaHomeFile, "../Classes"), //$NON-NLS-1$
+ };
+ } else {
+ directoriesToCheck = new File[] { new File(javaHomeFile, "lib") //$NON-NLS-1$
+ };
+ }
+ File[][] jars = Main.getLibrariesFiles(directoriesToCheck);
+ addFiles(jars, files);
+ }
+ addFilesFrom(javaHomeFile, "java.ext.dirs", "/lib/ext", files);//$NON-NLS-1$//$NON-NLS-2$
+ return files;
+ }
+
+ Iterable<? extends File> getDefaultClasspath() {
+ // default classpath
+ ArrayList<File> files = new ArrayList<File>();
+ String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$
+ if ((classProp == null) || (classProp.length() == 0)) {
+ return null;
+ } else {
+ StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
+ String token;
+ while (tokenizer.hasMoreTokens()) {
+ token = tokenizer.nextToken();
+ File file = new File(token);
+ if (file.exists()) {
+ files.add(file);
+ }
+ }
+ }
+ return files;
+ }
+
+ private Iterable<? extends File> getEndorsedDirsFrom(String path) {
+ ArrayList<FileSystem.Classpath> paths = new ArrayList<FileSystem.Classpath>();
+ ArrayList<File> files = new ArrayList<File>();
+ try {
+ this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ for (FileSystem.Classpath classpath : paths) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ private Iterable<? extends File> getExtdirsFrom(String path) {
+ ArrayList<FileSystem.Classpath> paths = new ArrayList<FileSystem.Classpath>();
+ ArrayList<File> files = new ArrayList<File>();
+ try {
+ this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ for (FileSystem.Classpath classpath : paths) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ private String getExtension(File file) {
+ String name = file.getName();
+ return getExtension(name);
+ }
+ private String getExtension(String name) {
+ int index = name.lastIndexOf('.');
+ if (index == -1) {
+ return EclipseFileManager.NO_EXTENSION;
+ }
+ return name.substring(index);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String)
+ */
+ public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ String normalizedFileName = normalized(packageName) + '/' + relativeName.replace('\\', '/');
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // handle directory
+ File f = new File(file, normalizedFileName);
+ if (f.exists()) {
+ return new EclipseFileObject(packageName + File.separator + relativeName, f.toURI(), getKind(f), this.charset);
+ } else {
+ continue; // go to next entry in the location
+ }
+ } else if (isArchive(file)) {
+ // handle archive file
+ Archive archive = getArchive(file);
+ if (archive != Archive.UNKNOWN_ARCHIVE) {
+ if (archive.contains(normalizedFileName)) {
+ return archive.getArchiveFileObject(normalizedFileName, this.charset);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String, javax.tools.FileObject)
+ */
+ public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling)
+ throws IOException {
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ final Iterator<? extends File> iterator = files.iterator();
+ if (iterator.hasNext()) {
+ File file = iterator.next();
+ String normalizedFileName = normalized(packageName) + '/' + relativeName.replace('\\', '/');
+ File f = new File(file, normalizedFileName);
+ return new EclipseFileObject(packageName + File.separator + relativeName, f.toURI(), getKind(f), this.charset);
+ } else {
+ throw new IllegalArgumentException("location is empty : " + location);//$NON-NLS-1$
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getJavaFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind)
+ */
+ public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
+ if (kind != Kind.CLASS && kind != Kind.SOURCE) {
+ throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$
+ }
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ String normalizedFileName = normalized(className);
+ normalizedFileName += kind.extension;
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // handle directory
+ File f = new File(file, normalizedFileName);
+ if (f.exists()) {
+ return new EclipseFileObject(className, f.toURI(), kind, this.charset);
+ } else {
+ continue; // go to next entry in the location
+ }
+ } else if (isArchive(file)) {
+ // handle archive file
+ Archive archive = getArchive(file);
+ if (archive != Archive.UNKNOWN_ARCHIVE) {
+ if (archive.contains(normalizedFileName)) {
+ return archive.getArchiveFileObject(normalizedFileName, this.charset);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject)
+ */
+ public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling)
+ throws IOException {
+ if (kind != Kind.CLASS && kind != Kind.SOURCE) {
+ throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$
+ }
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ if (!location.equals(StandardLocation.CLASS_OUTPUT)
+ && !location.equals(StandardLocation.SOURCE_OUTPUT))
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ // we will use either the sibling or user.dir
+ if (sibling != null) {
+ String normalizedFileName = normalized(className);
+ int index = normalizedFileName.lastIndexOf('/');
+ if (index != -1) {
+ normalizedFileName = normalizedFileName.substring(index + 1);
+ }
+ normalizedFileName += kind.extension;
+ URI uri = sibling.toUri();
+ URI uri2 = null;
+ try {
+ String path = uri.getPath();
+ index = path.lastIndexOf('/');
+ if (index != -1) {
+ path = path.substring(0, index + 1);
+ path += normalizedFileName;
+ }
+ uri2 = new URI(uri.getScheme(), uri.getHost(), path, uri.getFragment());
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("invalid sibling");//$NON-NLS-1$
+ }
+ return new EclipseFileObject(className, uri2, kind, this.charset);
+ } else {
+ String normalizedFileName = normalized(className);
+ normalizedFileName += kind.extension;
+ File f = new File(System.getProperty("user.dir"), normalizedFileName);//$NON-NLS-1$
+ return new EclipseFileObject(className, f.toURI(), kind, this.charset);
+ }
+ }
+ final Iterator<? extends File> iterator = files.iterator();
+ if (iterator.hasNext()) {
+ File file = iterator.next();
+ String normalizedFileName = normalized(className);
+ normalizedFileName += kind.extension;
+ File f = new File(file, normalizedFileName);
+ return new EclipseFileObject(className, f.toURI(), kind, this.charset);
+ } else {
+ throw new IllegalArgumentException("location is empty : " + location);//$NON-NLS-1$
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjects(java.io.File[])
+ */
+ public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
+ return getJavaFileObjectsFromFiles(Arrays.asList(files));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjects(java.lang.String[])
+ */
+ public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
+ return getJavaFileObjectsFromStrings(Arrays.asList(names));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjectsFromFiles(java.lang.Iterable)
+ */
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
+ ArrayList<JavaFileObject> javaFileArrayList = new ArrayList<JavaFileObject>();
+ for (File f : files) {
+ if (f.isDirectory()) {
+ throw new IllegalArgumentException("file : " + f.getAbsolutePath() + " is a directory"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ javaFileArrayList.add(new EclipseFileObject(f.getAbsolutePath(), f.toURI(), getKind(f), this.charset));
+ }
+ return javaFileArrayList;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjectsFromStrings(java.lang.Iterable)
+ */
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
+ ArrayList<File> files = new ArrayList<File>();
+ for (String name : names) {
+ files.add(new File(name));
+ }
+ return getJavaFileObjectsFromFiles(files);
+ }
+
+ public Kind getKind(File f) {
+ return getKind(getExtension(f));
+ }
+
+ private Kind getKind(String extension) {
+ if (Kind.CLASS.extension.equals(extension)) {
+ return Kind.CLASS;
+ } else if (Kind.SOURCE.extension.equals(extension)) {
+ return Kind.SOURCE;
+ } else if (Kind.HTML.extension.equals(extension)) {
+ return Kind.HTML;
+ }
+ return Kind.OTHER;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getLocation(javax.tools.JavaFileManager.Location)
+ */
+ public Iterable<? extends File> getLocation(Location location) {
+ if (this.locations == null) return null;
+ return this.locations.get(location.getName());
+ }
+
+ private Iterable<? extends File> getOutputDir(String string) {
+ if ("none".equals(string)) {//$NON-NLS-1$
+ return null;
+ }
+ File file = new File(string);
+ if (file.exists() && !file.isDirectory()) {
+ throw new IllegalArgumentException("file : " + file.getAbsolutePath() + " is not a directory");//$NON-NLS-1$//$NON-NLS-2$
+ }
+ ArrayList<File> list = new ArrayList<File>(1);
+ list.add(file);
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#handleOption(java.lang.String, java.util.Iterator)
+ */
+ public boolean handleOption(String current, Iterator<String> remaining) {
+ try {
+ if ("-bootclasspath".equals(current)) {//$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> bootclasspaths = getPathsFrom(remaining.next());
+ if (bootclasspaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH);
+ if ((this.flags & HAS_ENDORSED_DIRS) == 0
+ && (this.flags & HAS_EXT_DIRS) == 0) {
+ // override default bootclasspath
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths);
+ } else if ((this.flags & HAS_ENDORSED_DIRS) != 0) {
+ // endorseddirs have been processed first
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ concatFiles(iterable, bootclasspaths));
+ } else {
+ // extdirs have been processed first
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ prependFiles(iterable, bootclasspaths));
+ }
+ }
+ remaining.remove();
+ this.flags |= HAS_BOOTCLASSPATH;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-classpath".equals(current) || "-cp".equals(current)) {//$NON-NLS-1$//$NON-NLS-2$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> classpaths = getPathsFrom(remaining.next());
+ if (classpaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.CLASS_PATH);
+ if (iterable != null) {
+ setLocation(StandardLocation.CLASS_PATH,
+ concatFiles(iterable, classpaths));
+ } else {
+ setLocation(StandardLocation.CLASS_PATH, classpaths);
+ }
+ if ((this.flags & HAS_PROCESSORPATH) == 0) {
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths);
+ }
+ }
+ remaining.remove();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-encoding".equals(current)) {//$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ this.charset = Charset.forName(remaining.next());
+ remaining.remove();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-sourcepath".equals(current)) {//$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> sourcepaths = getPathsFrom(remaining.next());
+ if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths);
+ remaining.remove();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-extdirs".equals(current)) {//$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH);
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ concatFiles(iterable, getExtdirsFrom(remaining.next())));
+ remaining.remove();
+ this.flags |= HAS_EXT_DIRS;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-endorseddirs".equals(current)) {//$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH);
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ prependFiles(iterable, getEndorsedDirsFrom(remaining.next())));
+ remaining.remove();
+ this.flags |= HAS_ENDORSED_DIRS;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-d".equals(current)) { //$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> outputDir = getOutputDir(remaining.next());
+ if (outputDir != null) {
+ setLocation(StandardLocation.CLASS_OUTPUT, outputDir);
+ }
+ remaining.remove();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-s".equals(current)) { //$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> outputDir = getOutputDir(remaining.next());
+ if (outputDir != null) {
+ setLocation(StandardLocation.SOURCE_OUTPUT, outputDir);
+ }
+ remaining.remove();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ if ("-processorpath".equals(current)) {//$NON-NLS-1$
+ remaining.remove(); // remove the current option
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> processorpaths = getPathsFrom(remaining.next());
+ if (processorpaths != null) {
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths);
+ }
+ remaining.remove();
+ this.flags |= HAS_PROCESSORPATH;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#hasLocation(javax.tools.JavaFileManager.Location)
+ */
+ public boolean hasLocation(Location location) {
+ return this.locations != null && this.locations.containsKey(location.getName());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#inferBinaryName(javax.tools.JavaFileManager.Location, javax.tools.JavaFileObject)
+ */
+ public String inferBinaryName(Location location, JavaFileObject file) {
+ String name = file.getName();
+ JavaFileObject javaFileObject = null;
+ int index = name.lastIndexOf('.');
+ if (index != -1) {
+ name = name.substring(0, index);
+ }
+ try {
+ javaFileObject = getJavaFileForInput(location, name, file.getKind());
+ } catch (IOException e) {
+ // ignore
+ } catch (IllegalArgumentException iae) {
+ return null; // Either unknown kind or location not present
+ }
+ if (javaFileObject == null) {
+ return null;
+ }
+ return normalized(name);
+ }
+
+ private boolean isArchive(File f) {
+ String extension = getExtension(f);
+ return extension.equalsIgnoreCase(".jar") || extension.equalsIgnoreCase(".zip");//$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#isSameFile(javax.tools.FileObject, javax.tools.FileObject)
+ */
+ public boolean isSameFile(FileObject fileObject1, FileObject fileObject2) {
+ // EclipseFileManager creates only EcliseFileObject
+ if (!(fileObject1 instanceof EclipseFileObject)) throw new IllegalArgumentException("Unsupported file object class : " + fileObject1.getClass());//$NON-NLS-1$
+ if (!(fileObject2 instanceof EclipseFileObject)) throw new IllegalArgumentException("Unsupported file object class : " + fileObject2.getClass());//$NON-NLS-1$
+ return fileObject1.equals(fileObject2);
+ }
+ /* (non-Javadoc)
+ * @see javax.tools.OptionChecker#isSupportedOption(java.lang.String)
+ */
+ public int isSupportedOption(String option) {
+ return Options.processOptionsFileManager(option);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#list(javax.tools.JavaFileManager.Location, java.lang.String, java.util.Set, boolean)
+ */
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse)
+ throws IOException {
+
+ Iterable<? extends File> allFilesInLocations = getLocation(location);
+ if (allFilesInLocations == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+
+ ArrayList<JavaFileObject> collector = new ArrayList<JavaFileObject>();
+ String normalizedPackageName = normalized(packageName);
+ for (File file : allFilesInLocations) {
+ collectAllMatchingFiles(file, normalizedPackageName, kinds, recurse, collector);
+ }
+ return collector;
+ }
+
+ private String normalized(String className) {
+ char[] classNameChars = className.toCharArray();
+ for (int i = 0, max = classNameChars.length; i < max; i++) {
+ switch(classNameChars[i]) {
+ case '\\' :
+ classNameChars[i] = '/';
+ break;
+ case '.' :
+ classNameChars[i] = '/';
+ }
+ }
+ return new String(classNameChars);
+ }
+
+ private Iterable<? extends File> prependFiles(Iterable<? extends File> iterable,
+ Iterable<? extends File> iterable2) {
+ if (iterable2 == null) return iterable;
+ ArrayList<File> list = new ArrayList<File>();
+ for (Iterator<? extends File> iterator = iterable2.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ for (Iterator<? extends File> iterator = iterable.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#setLocation(javax.tools.JavaFileManager.Location, java.lang.Iterable)
+ */
+ public void setLocation(Location location, Iterable<? extends File> path) throws IOException {
+ if (path != null) {
+ if (location.isOutputLocation()) {
+ // output location
+ int count = 0;
+ for (Iterator<? extends File> iterator = path.iterator(); iterator.hasNext(); ) {
+ iterator.next();
+ count++;
+ }
+ if (count != 1) {
+ throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$
+ }
+ }
+ this.locations.put(location.getName(), path);
+ }
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale == null ? Locale.getDefault() : locale;
+ try {
+ this.bundle = ResourceBundleFactory.getBundle(this.locale);
+ } catch(MissingResourceException e) {
+ System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$
+ throw e;
+ }
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void processPathEntries(final int defaultSize, final ArrayList paths,
+ final String currentPath, String customEncoding, boolean isSourceOnly,
+ boolean rejectDestinationPathOnJars) {
+
+ String currentClasspathName = null;
+ String currentDestinationPath = null;
+ ArrayList currentRuleSpecs = new ArrayList(defaultSize);
+ StringTokenizer tokenizer = new StringTokenizer(currentPath,
+ File.pathSeparator + "[]", true); //$NON-NLS-1$
+ ArrayList tokens = new ArrayList();
+ while (tokenizer.hasMoreTokens()) {
+ tokens.add(tokenizer.nextToken());
+ }
+ // state machine
+ final int start = 0;
+ final int readyToClose = 1;
+ // 'path' 'path1[rule];path2'
+ final int readyToCloseEndingWithRules = 2;
+ // 'path[rule]' 'path1;path2[rule]'
+ final int readyToCloseOrOtherEntry = 3;
+ // 'path[rule];' 'path;' 'path1;path2;'
+ final int rulesNeedAnotherRule = 4;
+ // 'path[rule1;'
+ final int rulesStart = 5;
+ // 'path[' 'path1;path2['
+ final int rulesReadyToClose = 6;
+ // 'path[rule' 'path[rule1;rule2'
+ final int destinationPathReadyToClose = 7;
+ // 'path[-d bin'
+ final int readyToCloseEndingWithDestinationPath = 8;
+ // 'path[-d bin]' 'path[rule][-d bin]'
+ final int destinationPathStart = 9;
+ // 'path[rule]['
+ final int bracketOpened = 10;
+ // '.*[.*'
+ final int bracketClosed = 11;
+ // '.*([.*])+'
+
+ final int error = 99;
+ int state = start;
+ String token = null;
+ int cursor = 0, tokensNb = tokens.size(), bracket = -1;
+ while (cursor < tokensNb && state != error) {
+ token = (String) tokens.get(cursor++);
+ if (token.equals(File.pathSeparator)) {
+ switch (state) {
+ case start:
+ case readyToCloseOrOtherEntry:
+ case bracketOpened:
+ break;
+ case readyToClose:
+ case readyToCloseEndingWithRules:
+ case readyToCloseEndingWithDestinationPath:
+ state = readyToCloseOrOtherEntry;
+ addNewEntry(paths, currentClasspathName, currentRuleSpecs,
+ customEncoding, currentDestinationPath, isSourceOnly,
+ rejectDestinationPathOnJars);
+ currentRuleSpecs.clear();
+ break;
+ case rulesReadyToClose:
+ state = rulesNeedAnotherRule;
+ break;
+ case destinationPathReadyToClose:
+ throw new IllegalArgumentException(
+ this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$
+ currentPath));
+ case bracketClosed:
+ cursor = bracket + 1;
+ state = rulesStart;
+ break;
+ default:
+ state = error;
+ }
+ } else if (token.equals("[")) { //$NON-NLS-1$
+ switch (state) {
+ case start:
+ currentClasspathName = ""; //$NON-NLS-1$
+ //$FALL-THROUGH$
+ case readyToClose:
+ bracket = cursor - 1;
+ //$FALL-THROUGH$
+ case bracketClosed:
+ state = bracketOpened;
+ break;
+ case readyToCloseEndingWithRules:
+ state = destinationPathStart;
+ break;
+ case readyToCloseEndingWithDestinationPath:
+ state = rulesStart;
+ break;
+ case bracketOpened:
+ default:
+ state = error;
+ }
+ } else if (token.equals("]")) { //$NON-NLS-1$
+ switch (state) {
+ case rulesReadyToClose:
+ state = readyToCloseEndingWithRules;
+ break;
+ case destinationPathReadyToClose:
+ state = readyToCloseEndingWithDestinationPath;
+ break;
+ case bracketOpened:
+ state = bracketClosed;
+ break;
+ case bracketClosed:
+ default:
+ state = error;
+ }
+ } else {
+ // regular word
+ switch (state) {
+ case start:
+ case readyToCloseOrOtherEntry:
+ state = readyToClose;
+ currentClasspathName = token;
+ break;
+ case rulesStart:
+ if (token.startsWith("-d ")) { //$NON-NLS-1$
+ if (currentDestinationPath != null) {
+ throw new IllegalArgumentException(
+ this.bind("configure.duplicateDestinationPathEntry", //$NON-NLS-1$
+ currentPath));
+ }
+ currentDestinationPath = token.substring(3).trim();
+ state = destinationPathReadyToClose;
+ break;
+ } // else we proceed with a rule
+ //$FALL-THROUGH$
+ case rulesNeedAnotherRule:
+ if (currentDestinationPath != null) {
+ throw new IllegalArgumentException(
+ this.bind("configure.accessRuleAfterDestinationPath", //$NON-NLS-1$
+ currentPath));
+ }
+ state = rulesReadyToClose;
+ currentRuleSpecs.add(token);
+ break;
+ case destinationPathStart:
+ if (!token.startsWith("-d ")) { //$NON-NLS-1$
+ state = error;
+ } else {
+ currentDestinationPath = token.substring(3).trim();
+ state = destinationPathReadyToClose;
+ }
+ break;
+ case bracketClosed:
+ for (int i = bracket; i < cursor ; i++) {
+ currentClasspathName += (String) tokens.get(i);
+ }
+ state = readyToClose;
+ break;
+ case bracketOpened:
+ break;
+ default:
+ state = error;
+ }
+ }
+ if (state == bracketClosed && cursor == tokensNb) {
+ cursor = bracket + 1;
+ state = rulesStart;
+ }
+ }
+ switch(state) {
+ case readyToCloseOrOtherEntry:
+ break;
+ case readyToClose:
+ case readyToCloseEndingWithRules:
+ case readyToCloseEndingWithDestinationPath:
+ addNewEntry(paths, currentClasspathName, currentRuleSpecs,
+ customEncoding, currentDestinationPath, isSourceOnly,
+ rejectDestinationPathOnJars);
+ break;
+ case bracketOpened:
+ case bracketClosed:
+ default :
+ // we go on anyway
+ }
+ }
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ protected void addNewEntry(ArrayList paths, String currentClasspathName,
+ ArrayList currentRuleSpecs, String customEncoding,
+ String destPath, boolean isSourceOnly,
+ boolean rejectDestinationPathOnJars) {
+
+ int rulesSpecsSize = currentRuleSpecs.size();
+ AccessRuleSet accessRuleSet = null;
+ if (rulesSpecsSize != 0) {
+ AccessRule[] accessRules = new AccessRule[currentRuleSpecs.size()];
+ boolean rulesOK = true;
+ Iterator i = currentRuleSpecs.iterator();
+ int j = 0;
+ while (i.hasNext()) {
+ String ruleSpec = (String) i.next();
+ char key = ruleSpec.charAt(0);
+ String pattern = ruleSpec.substring(1);
+ if (pattern.length() > 0) {
+ switch (key) {
+ case '+':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(), 0);
+ break;
+ case '~':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(),
+ IProblem.DiscouragedReference);
+ break;
+ case '-':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(),
+ IProblem.ForbiddenReference);
+ break;
+ case '?':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(),
+ IProblem.ForbiddenReference, true/*keep looking for accessible type*/);
+ break;
+ default:
+ rulesOK = false;
+ }
+ } else {
+ rulesOK = false;
+ }
+ }
+ if (rulesOK) {
+ accessRuleSet = new AccessRuleSet(accessRules, AccessRestriction.COMMAND_LINE, currentClasspathName);
+ } else {
+ return;
+ }
+ }
+ if (Main.NONE.equals(destPath)) {
+ destPath = Main.NONE; // keep == comparison valid
+ }
+ if (rejectDestinationPathOnJars && destPath != null &&
+ (currentClasspathName.endsWith(".jar") || //$NON-NLS-1$
+ currentClasspathName.endsWith(".zip"))) { //$NON-NLS-1$
+ throw new IllegalArgumentException(
+ this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$
+ currentClasspathName));
+ }
+ FileSystem.Classpath currentClasspath = FileSystem.getClasspath(
+ currentClasspathName,
+ customEncoding,
+ isSourceOnly,
+ accessRuleSet,
+ destPath);
+ if (currentClasspath != null) {
+ paths.add(currentClasspath);
+ }
+ }
+ /*
+ * Lookup the message with the given ID in this catalog and bind its
+ * substitution locations with the given string.
+ */
+ private String bind(String id, String binding) {
+ return bind(id, new String[] { binding });
+ }
+
+ /*
+ * Lookup the message with the given ID in this catalog and bind its
+ * substitution locations with the given string values.
+ */
+ private String bind(String id, String[] arguments) {
+ if (id == null)
+ return "No message available"; //$NON-NLS-1$
+ String message = null;
+ try {
+ message = this.bundle.getString(id);
+ } catch (MissingResourceException e) {
+ // If we got an exception looking for the message, fail gracefully by just returning
+ // the id we were looking for. In most cases this is semi-informative so is not too bad.
+ return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$
+ }
+ return MessageFormat.format(message, (Object[]) arguments);
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java
new file mode 100644
index 00000000..e72f450c
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Walter Harley - Patch for ensuring the parent folders are created
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.charset.Charset;
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.SimpleJavaFileObject;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+
+/**
+ * Implementation of a Java file object that corresponds to a file on the file system
+ */
+public class EclipseFileObject extends SimpleJavaFileObject {
+ private File f;
+ private Charset charset;
+ private boolean parentsExist; // parent directories exist
+
+ public EclipseFileObject(String className, URI uri, Kind kind, Charset charset) {
+ super(uri, kind);
+ this.f = new File(this.uri);
+ this.charset = charset;
+ this.parentsExist = false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getAccessLevel()
+ */
+ public Modifier getAccessLevel() {
+ // cannot express multiple modifier
+ if (getKind() != Kind.CLASS) {
+ return null;
+ }
+ ClassFileReader reader = null;
+ try {
+ reader = ClassFileReader.read(this.f);
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ // ignore
+ }
+ if (reader == null) {
+ return null;
+ }
+ final int accessFlags = reader.accessFlags();
+ if ((accessFlags & ClassFileConstants.AccPublic) != 0) {
+ return Modifier.PUBLIC;
+ }
+ if ((accessFlags & ClassFileConstants.AccAbstract) != 0) {
+ return Modifier.ABSTRACT;
+ }
+ if ((accessFlags & ClassFileConstants.AccFinal) != 0) {
+ return Modifier.FINAL;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getNestingKind()
+ */
+ public NestingKind getNestingKind() {
+ switch(kind) {
+ case SOURCE :
+ return NestingKind.TOP_LEVEL;
+ case CLASS :
+ ClassFileReader reader = null;
+ try {
+ reader = ClassFileReader.read(this.f);
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ // ignore
+ }
+ if (reader == null) {
+ return null;
+ }
+ if (reader.isAnonymous()) {
+ return NestingKind.ANONYMOUS;
+ }
+ if (reader.isLocal()) {
+ return NestingKind.LOCAL;
+ }
+ if (reader.isMember()) {
+ return NestingKind.MEMBER;
+ }
+ return NestingKind.TOP_LEVEL;
+ default:
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#delete()
+ */
+ public boolean delete() {
+ return this.f.delete();
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof EclipseFileObject)) {
+ return false;
+ }
+ EclipseFileObject eclipseFileObject = (EclipseFileObject) o;
+ return eclipseFileObject.toUri().equals(this.uri);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getCharContent(boolean)
+ */
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return Util.getCharContents(this, ignoreEncodingErrors, org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(this.f), this.charset.name());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getLastModified()
+ */
+ public long getLastModified() {
+ return this.f.lastModified();
+ }
+
+ public String getName() {
+ return this.f.getPath();
+ }
+
+ public int hashCode() {
+ return f.hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openInputStream()
+ */
+ public InputStream openInputStream() throws IOException {
+ // TODO (olivier) should be used buffered input stream
+ return new FileInputStream(this.f);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openOutputStream()
+ */
+ public OutputStream openOutputStream() throws IOException {
+ ensureParentDirectoriesExist();
+ return new FileOutputStream(this.f);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openReader(boolean)
+ */
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ return new FileReader(this.f);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openWriter()
+ */
+ public Writer openWriter() throws IOException {
+ ensureParentDirectoriesExist();
+ return new FileWriter(this.f);
+ }
+
+ @Override
+ public String toString() {
+ return this.f.getAbsolutePath();
+ }
+
+ private void ensureParentDirectoriesExist() throws IOException {
+ if (!this.parentsExist) {
+ File parent = f.getParentFile();
+ if (parent != null && !parent.exists()) {
+ if (!parent.mkdirs()) {
+ // could have been concurrently created
+ if (!parent.exists() || !parent.isDirectory())
+ throw new IOException("Unable to create parent directories for " + f); //$NON-NLS-1$
+ }
+ }
+ this.parentsExist = true;
+ }
+ }
+
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
new file mode 100644
index 00000000..62e1a125
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
@@ -0,0 +1,364 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 BEA Systems, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * (originally in org.eclipse.jdt.apt.core)
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manage a Map<T1, Set<T2>>, with reverse links so that it is possible to
+ * efficiently find all T1s that have a particular T2 associated with them.
+ * Access to the map is synchronized, so that it is possible to read and
+ * write simultaneously from multiple threads.
+ * <p>
+ * The map permits the null value for keys nor for value elements.
+ * <p>
+ * Design invariants preserved by all operations on this map are as follows:
+ * <ul>
+ * <li> If a key exists, it has at least one value associated with it; that is,
+ * for all k such that null != containsKey(k), getValues(k) returns a non-empty
+ * set.</li>
+ * <li> If a value exists, it has at least one key associated with it; that is,
+ * for all v such that null != containsValue(v), getKeys(v) returns a non-empty
+ * set.</li>
+ */
+public class ManyToMany<T1, T2> {
+
+ private final Map<T1, Set<T2>> _forward = new HashMap<T1, Set<T2>>();
+ private final Map<T2, Set<T1>> _reverse = new HashMap<T2, Set<T1>>();
+ private boolean _dirty = false;
+
+ /**
+ * Empty all maps. If the maps previously contained entries,
+ * this will set the dirty bit.
+ * @return true if the maps contained any entries prior to being cleared
+ */
+ public synchronized boolean clear() {
+ boolean hadContent = !_forward.isEmpty() || !_reverse.isEmpty();
+ _reverse.clear();
+ _forward.clear();
+ _dirty |= hadContent;
+ return hadContent;
+ }
+
+ /**
+ * Sets the dirty bit to false. Internal operations do not use the dirty
+ * bit; clearing it will not affect behavior of the map. It's just there
+ * for the convenience of callers who don't want to keep track of every
+ * put() and remove().
+ */
+ public synchronized void clearDirtyBit() {
+ _dirty = false;
+ }
+
+ /**
+ * Equivalent to keySet().contains(key).
+ * @return true if the map contains the specified key.
+ */
+ public synchronized boolean containsKey(T1 key) {
+ return _forward.containsKey(key);
+ }
+
+ /**
+ * Is there a key that is mapped to the specified value?
+ * Search within the forward map.
+ * @return true if such a key exists
+ */
+ public synchronized boolean containsKeyValuePair(T1 key, T2 value) {
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ return false;
+ }
+ return values.contains(value);
+ }
+
+ /**
+ * Equivalent to values().contains(value).
+ * @return true if the map contains the specified value (regardless
+ * of what key it might be associated with).
+ */
+ public synchronized boolean containsValue(T2 value) {
+ return _reverse.containsKey(value);
+ }
+
+ /**
+ * Search the reverse map for all keys that have been associated with
+ * a particular value.
+ * @return the set of keys that are associated with the specified value,
+ * or an empty set if the value does not exist in the map.
+ */
+ public synchronized Set<T1> getKeys(T2 value) {
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys) {
+ return Collections.emptySet();
+ }
+ return new HashSet<T1>(keys);
+ }
+
+ /**
+ * Search the forward map for all values associated with a particular key.
+ * Returns a copy of the set of values.
+ * @return a copy of the set of values that are associated with the
+ * specified key, or an empty set if the key does not exist in the map.
+ */
+ public synchronized Set<T2> getValues(T1 key) {
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ return Collections.emptySet();
+ }
+ return new HashSet<T2>(values);
+ }
+
+ /**
+ * @return a copy of the set of all keys (that is, all items of type T1).
+ * If the maps are empty, the returned set will be empty, not null. The
+ * returned set can be modified by the caller without affecting the map.
+ * @see #getValueSet()
+ */
+ public synchronized Set<T1> getKeySet() {
+ Set<T1> keys = new HashSet<T1>(_forward.keySet());
+ return keys;
+ }
+
+ /**
+ * @return a copy of the set of all values (that is, all items of type T2).
+ * If the maps are empty, the returned set will be empty, not null. The
+ * returned set can be modified by the caller without affecting the map.
+ * @see #getKeySet()
+ */
+ public synchronized Set<T2> getValueSet() {
+ Set<T2> values = new HashSet<T2>(_reverse.keySet());
+ return values;
+ }
+
+ /**
+ * Return the state of the dirty bit. All operations that change the state
+ * of the maps, including @see #clear(), set the dirty bit if any content actually
+ * changed. The only way to clear the dirty bit is to call @see #clearDirtyBit().
+ * @return true if the map content has changed since it was created or since
+ * the last call to clearDirtyBit().
+ * @see #clearDirtyBit()
+ */
+ public synchronized boolean isDirty() {
+ return _dirty;
+ }
+
+ /**
+ * Check whether <code>key</code> has an association to any values other
+ * than <code>value</code> - that is, whether the same key has been added
+ * with multiple values. Equivalent to asking whether the intersection of
+ * <code>getValues(key)</code> and the set containing <code>value</code> is
+ * non-empty.
+ * @return true iff <code>key</code> is in the map and is associated
+ * with values other than <code>value</code>.
+ * @see #valueHasOtherKeys(Object, Object)
+ */
+ public synchronized boolean keyHasOtherValues(T1 key, T2 value) {
+ Set<T2> values = _forward.get(key);
+ if (values == null)
+ return false;
+ int size = values.size();
+ if (size == 0)
+ return false;
+ else if (size > 1)
+ return true;
+ else // size == 1
+ return !values.contains(value);
+ }
+
+ /**
+ * Associate the specified value with the key. Adds the entry
+ * to both the forward and reverse maps. Adding the same value
+ * twice to a particular key has no effect. Because this is a
+ * many-to-many map, adding a new value for an existing key does
+ * not change the existing association, it adds a new one.
+ * @param key can be null
+ * @param value can be null
+ * @return true if the key/value pair did not exist prior to being added
+ */
+ public synchronized boolean put(T1 key, T2 value) {
+ // Add to forward map
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ values = new HashSet<T2>();
+ _forward.put(key, values);
+ }
+ boolean added = values.add(value);
+ _dirty |= added;
+
+ // Add to reverse map
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys) {
+ keys = new HashSet<T1>();
+ _reverse.put(value, keys);
+ }
+ keys.add(key);
+
+ assert checkIntegrity();
+ return added;
+ }
+
+ /**
+ * Remove a particular key-value association. This is the inverse
+ * of put(key, value). If the key does not exist, or the value
+ * does not exist, or the association does not exist, this call
+ * has no effect.
+ * @return true if the key/value pair existed in the map prior to removal
+ */
+ public synchronized boolean remove(T1 key, T2 value) {
+ Set<T2> values = _forward.get(key);
+ if (values == null) {
+ assert checkIntegrity();
+ return false;
+ }
+ boolean removed = values.remove(value);
+ if (values.isEmpty()) {
+ _forward.remove(key);
+ }
+ if (removed) {
+ _dirty = true;
+ // it existed, so we need to remove from reverse map as well
+ Set<T1> keys = _reverse.get(value);
+ keys.remove(key);
+ if (keys.isEmpty()) {
+ _reverse.remove(value);
+ }
+ }
+ assert checkIntegrity();
+ return removed;
+ }
+
+ /**
+ * Remove the key and its associated key/value entries.
+ * Calling removeKey(k) is equivalent to calling remove(k,v)
+ * for every v in getValues(k).
+ * @return true if the key existed in the map prior to removal
+ */
+ public synchronized boolean removeKey(T1 key) {
+ // Remove all back-references to key.
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ // key does not exist in map.
+ assert checkIntegrity();
+ return false;
+ }
+ for (T2 value : values) {
+ Set<T1> keys = _reverse.get(value);
+ if (null != keys) {
+ keys.remove(key);
+ if (keys.isEmpty()) {
+ _reverse.remove(value);
+ }
+ }
+ }
+ // Now remove the forward references from key.
+ _forward.remove(key);
+ _dirty = true;
+ assert checkIntegrity();
+ return true;
+ }
+
+ /**
+ * Remove the value and its associated key/value entries.
+ * Calling removeValue(v) is equivalent to calling remove(k,v)
+ * for every k in getKeys(v).
+ * @return true if the value existed in the map prior to removal.
+ */
+ public synchronized boolean removeValue(T2 value) {
+ // Remove any forward references to value
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys) {
+ // value does not exist in map.
+ assert checkIntegrity();
+ return false;
+ }
+ for (T1 key : keys) {
+ Set<T2> values = _forward.get(key);
+ if (null != values) {
+ values.remove(value);
+ if (values.isEmpty()) {
+ _forward.remove(key);
+ }
+ }
+ }
+ // Now remove the reverse references from value.
+ _reverse.remove(value);
+ _dirty = true;
+ assert checkIntegrity();
+ return true;
+ }
+
+ /**
+ * Check whether <code>value</code> has an association from any keys other
+ * than <code>key</code> - that is, whether the same value has been added
+ * with multiple keys. Equivalent to asking whether the intersection of
+ * <code>getKeys(value)</code> and the set containing <code>key</code> is
+ * non-empty.
+ * @return true iff <code>value</code> is in the map and is associated
+ * with keys other than <code>key</code>.
+ * @see #keyHasOtherValues(Object, Object)
+ */
+ public synchronized boolean valueHasOtherKeys(T2 value, T1 key) {
+ Set<T1> keys = _reverse.get(key);
+ if (keys == null)
+ return false;
+ int size = keys.size();
+ if (size == 0)
+ return false;
+ else if (size > 1)
+ return true;
+ else // size == 1
+ return !keys.contains(key);
+ }
+
+ /**
+ * Check the integrity of the internal data structures. This is intended to
+ * be called within an assert, so that if asserts are disabled the integrity
+ * checks will not cause a performance impact.
+ * @return true if everything is okay.
+ * @throws IllegalStateException if there is a problem.
+ */
+ private boolean checkIntegrity() {
+ // For every T1->T2 mapping in the forward map, there should be a corresponding
+ // T2->T1 mapping in the reverse map.
+ for (Map.Entry<T1, Set<T2>> entry : _forward.entrySet()) {
+ Set<T2> values = entry.getValue();
+ if (values.isEmpty()) {
+ throw new IllegalStateException("Integrity compromised: forward map contains an empty set"); //$NON-NLS-1$
+ }
+ for (T2 value : values) {
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys || !keys.contains(entry.getKey())) {
+ throw new IllegalStateException("Integrity compromised: forward map contains an entry missing from reverse map: " + value); //$NON-NLS-1$
+ }
+ }
+ }
+ // And likewise in the other direction.
+ for (Map.Entry<T2, Set<T1>> entry : _reverse.entrySet()) {
+ Set<T1> keys = entry.getValue();
+ if (keys.isEmpty()) {
+ throw new IllegalStateException("Integrity compromised: reverse map contains an empty set"); //$NON-NLS-1$
+ }
+ for (T1 key : keys) {
+ Set<T2> values = _forward.get(key);
+ if (null == values || !values.contains(entry.getKey())) {
+ throw new IllegalStateException("Integrity compromised: reverse map contains an entry missing from forward map: " + key); //$NON-NLS-1$
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Options.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Options.java
new file mode 100644
index 00000000..f9795cf1
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Options.java
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Class used to handle options in the EclipseFileManager and the EclipseCompiler
+ */
+public final class Options {
+ private static final Set<String> ZERO_ARGUMENT_OPTIONS;
+ private static final Set<String> ONE_ARGUMENT_OPTIONS;
+ private static final Set<String> FILE_MANAGER_OPTIONS;
+ static {
+ ZERO_ARGUMENT_OPTIONS = new HashSet<String>();
+ ZERO_ARGUMENT_OPTIONS.add("-progress");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-proceedOnError");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-time");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-v");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-version");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-showversion");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-deprecation");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-help");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-?");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-help:warn");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-?:warn");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-noExit");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-verbose");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-referenceInfo");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-inlineJSR");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-g");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-g:none");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-nowarn");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-warn:none");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-preserveAllLocals");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-enableJavadoc");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-Xemacs");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-X");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-O");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-1.3");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-1.4");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-1.5");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-5");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-5.0");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-1.6");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-6");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-6.0");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-proc:only");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-proc:none");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-XprintProcessorInfo");//$NON-NLS-1$
+ ZERO_ARGUMENT_OPTIONS.add("-XprintRounds");//$NON-NLS-1$
+
+ FILE_MANAGER_OPTIONS = new HashSet<String>();
+ FILE_MANAGER_OPTIONS.add("-bootclasspath");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-encoding");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-d");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-classpath");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-cp");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-sourcepath");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-extdirs");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-endorseddirs");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-s");//$NON-NLS-1$
+ FILE_MANAGER_OPTIONS.add("-processorpath");//$NON-NLS-1$
+
+ ONE_ARGUMENT_OPTIONS = new HashSet<String>();
+ ONE_ARGUMENT_OPTIONS.addAll(FILE_MANAGER_OPTIONS);
+ ONE_ARGUMENT_OPTIONS.add("-log");//$NON-NLS-1$
+ ONE_ARGUMENT_OPTIONS.add("-repeat");//$NON-NLS-1$
+ ONE_ARGUMENT_OPTIONS.add("-maxProblems");//$NON-NLS-1$
+ ONE_ARGUMENT_OPTIONS.add("-source");//$NON-NLS-1$
+ ONE_ARGUMENT_OPTIONS.add("-target");//$NON-NLS-1$
+ ONE_ARGUMENT_OPTIONS.add("-processor");//$NON-NLS-1$
+ ONE_ARGUMENT_OPTIONS.add("-classNames");//$NON-NLS-1$
+ }
+ public static int processOptionsFileManager(String option) {
+ if (option == null) return -1;
+ if (FILE_MANAGER_OPTIONS.contains(option)) {
+ return 1;
+ }
+ return -1;
+ }
+
+ public static int processOptions(String option) {
+ if (option == null) return -1;
+ if (ZERO_ARGUMENT_OPTIONS.contains(option)) {
+ return 0;
+ }
+ if (ONE_ARGUMENT_OPTIONS.contains(option)) {
+ return 1;
+ }
+ if (option.startsWith("-g")) { //$NON-NLS-1$
+ int length = option.length();
+ if (length > 3) {
+ StringTokenizer tokenizer =
+ new StringTokenizer(option.substring(3, option.length()), ",");//$NON-NLS-1$
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if ("vars".equals(token) || "lines".equals(token) || "source".equals(token)) {//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ continue;
+ }
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+ }
+ if (option.startsWith("-warn")) {//$NON-NLS-1$
+ int length = option.length();
+ if (length <= 6) {
+ return -1;
+ }
+ int warnTokenStart;
+ switch (option.charAt(6)) {
+ case '+' :
+ warnTokenStart = 7;
+ break;
+ case '-' :
+ warnTokenStart = 7;
+ break;
+ default:
+ warnTokenStart = 6;
+ }
+
+ StringTokenizer tokenizer =
+ new StringTokenizer(option.substring(warnTokenStart, option.length()), ","); //$NON-NLS-1$
+ int tokenCounter = 0;
+
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ tokenCounter++;
+ if ("constructorName".equals(token)//$NON-NLS-1$
+ || token.equals("pkgDefaultMethod")//$NON-NLS-1$
+ || token.equals("packageDefaultMethod")//$NON-NLS-1$
+ || token.equals("maskedCatchBlock")//$NON-NLS-1$
+ || token.equals("maskedCatchBlocks")//$NON-NLS-1$
+ || token.equals("deprecation")//$NON-NLS-1$
+ || token.equals("allDeprecation")//$NON-NLS-1$
+ || token.equals("unusedLocal")//$NON-NLS-1$
+ || token.equals("unusedLocals")//$NON-NLS-1$
+ || token.equals("unusedArgument")//$NON-NLS-1$
+ || token.equals("unusedArguments")//$NON-NLS-1$
+ || token.equals("unusedImport")//$NON-NLS-1$
+ || token.equals("unusedImports")//$NON-NLS-1$
+ || token.equals("unusedPrivate")//$NON-NLS-1$
+ || token.equals("unusedLabel")//$NON-NLS-1$
+ || token.equals("localHiding")//$NON-NLS-1$
+ || token.equals("fieldHiding")//$NON-NLS-1$
+ || token.equals("specialParamHiding")//$NON-NLS-1$
+ || token.equals("conditionAssign")//$NON-NLS-1$
+ || token.equals("syntheticAccess")//$NON-NLS-1$
+ || token.equals("synthetic-access")//$NON-NLS-1$
+ || token.equals("nls")//$NON-NLS-1$
+ || token.equals("staticReceiver")//$NON-NLS-1$
+ || token.equals("indirectStatic")//$NON-NLS-1$
+ || token.equals("noEffectAssign")//$NON-NLS-1$
+ || token.equals("intfNonInherited")//$NON-NLS-1$
+ || token.equals("interfaceNonInherited")//$NON-NLS-1$
+ || token.equals("charConcat")//$NON-NLS-1$
+ || token.equals("noImplicitStringConversion")//$NON-NLS-1$
+ || token.equals("semicolon")//$NON-NLS-1$
+ || token.equals("serial")//$NON-NLS-1$
+ || token.equals("emptyBlock")//$NON-NLS-1$
+ || token.equals("uselessTypeCheck")//$NON-NLS-1$
+ || token.equals("unchecked")//$NON-NLS-1$
+ || token.equals("unsafe")//$NON-NLS-1$
+ || token.equals("raw")//$NON-NLS-1$
+ || token.equals("finalBound")//$NON-NLS-1$
+ || token.equals("suppress")//$NON-NLS-1$
+ || token.equals("warningToken")//$NON-NLS-1$
+ || token.equals("unnecessaryElse")//$NON-NLS-1$
+ || token.equals("javadoc")//$NON-NLS-1$
+ || token.equals("allJavadoc")//$NON-NLS-1$
+ || token.equals("assertIdentifier")//$NON-NLS-1$
+ || token.equals("enumIdentifier")//$NON-NLS-1$
+ || token.equals("finally")//$NON-NLS-1$
+ || token.equals("unusedThrown")//$NON-NLS-1$
+ || token.equals("unqualifiedField")//$NON-NLS-1$
+ || token.equals("unqualified-field-access")//$NON-NLS-1$
+ || token.equals("typeHiding")//$NON-NLS-1$
+ || token.equals("varargsCast")//$NON-NLS-1$
+ || token.equals("null")//$NON-NLS-1$
+ || token.equals("boxing")//$NON-NLS-1$
+ || token.equals("over-ann")//$NON-NLS-1$
+ || token.equals("dep-ann")//$NON-NLS-1$
+ || token.equals("intfAnnotation")//$NON-NLS-1$
+ || token.equals("enumSwitch")//$NON-NLS-1$
+ || token.equals("incomplete-switch")//$NON-NLS-1$
+ || token.equals("hiding")//$NON-NLS-1$
+ || token.equals("static-access")//$NON-NLS-1$
+ || token.equals("unused")//$NON-NLS-1$
+ || token.equals("paramAssign")//$NON-NLS-1$
+ || token.equals("discouraged")//$NON-NLS-1$
+ || token.equals("forbidden")//$NON-NLS-1$
+ || token.equals("fallthrough")) {//$NON-NLS-1$
+ continue;
+ } else if (token.equals("tasks")) {//$NON-NLS-1$
+ String taskTags = "";//$NON-NLS-1$
+ int start = token.indexOf('(');
+ int end = token.indexOf(')');
+ if (start >= 0 && end >= 0 && start < end){
+ taskTags = token.substring(start+1, end).trim();
+ taskTags = taskTags.replace('|',',');
+ }
+ if (taskTags.length() == 0){
+ return -1;
+ }
+ continue;
+ } else {
+ return -1;
+ }
+ }
+ if (tokenCounter == 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ if (option.startsWith("-J")//$NON-NLS-1$
+ || option.startsWith("-X")//$NON-NLS-1$
+ || option.startsWith("-A")) {//$NON-NLS-1$
+ return 0;
+ }
+ return -1;
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Util.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Util.java
new file mode 100644
index 00000000..2559ceec
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/Util.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+
+import javax.tools.FileObject;
+
+/**
+ * Util class that defines helper methods to read class contents with handling of wrong encoding
+ *
+ */
+public final class Util {
+ public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ public static class EncodingError {
+ int position;
+ int length;
+ public EncodingError(int position, int length) {
+ this.position = position;
+ this.length = length;
+ }
+
+ public String getSource(char[] unitSource) {
+ //extra from the source the innacurate token
+ //and "highlight" it using some underneath ^^^^^
+ //put some context around too.
+
+ //this code assumes that the font used in the console is fixed size
+
+ //sanity .....
+ int startPosition = this.position;
+ int endPosition = this.position + this.length - 1;
+
+ if ((startPosition > endPosition)
+ || ((startPosition < 0) && (endPosition < 0))
+ || unitSource.length == 0)
+ return "No source available"; //$NON-NLS-1$
+
+ StringBuffer errorBuffer = new StringBuffer();
+ errorBuffer.append('\t');
+
+ char c;
+ final char SPACE = ' ';
+ final char MARK = '^';
+ final char TAB = '\t';
+ //the next code tries to underline the token.....
+ //it assumes (for a good display) that token source does not
+ //contain any \r \n. This is false on statements !
+ //(the code still works but the display is not optimal !)
+
+ // expand to line limits
+ int length = unitSource.length, begin, end;
+ for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) {
+ if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break;
+ }
+ for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) {
+ if ((c = unitSource[end + 1]) == '\r' || c == '\n') break;
+ }
+
+ // trim left and right spaces/tabs
+ while ((c = unitSource[begin]) == ' ' || c == '\t') begin++;
+ //while ((c = unitSource[end]) == ' ' || c == '\t') end--; TODO (philippe) should also trim right, but all tests are to be updated
+
+ // copy source
+ errorBuffer.append(unitSource, begin, end-begin+1);
+ errorBuffer.append(Util.LINE_SEPARATOR).append("\t"); //$NON-NLS-1$
+
+ // compute underline
+ for (int i = begin; i <startPosition; i++) {
+ errorBuffer.append((unitSource[i] == TAB) ? TAB : SPACE);
+ }
+ for (int i = startPosition; i <= (endPosition >= length ? length - 1 : endPosition); i++) {
+ errorBuffer.append(MARK);
+ }
+ return errorBuffer.toString();
+ }
+ }
+ public static class EncodingErrorCollector {
+ ArrayList<EncodingError> encodingErrors = new ArrayList<EncodingError>();
+ FileObject fileObject;
+ String encoding;
+
+ public EncodingErrorCollector(FileObject fileObject, String encoding) {
+ this.fileObject = fileObject;
+ this.encoding = encoding;
+ }
+ public void collect(int position, int length) {
+ this.encodingErrors.add(new EncodingError(position, length));
+ }
+ public void reportAllEncodingErrors(String string) {
+ // this is where the encoding errors should be reported
+ char[] unitSource = string.toCharArray();
+ for (EncodingError error : this.encodingErrors) {
+ System.err.println(this.fileObject.getName() + " Unmappable character for encoding " + this.encoding);//$NON-NLS-1$
+ System.err.println(error.getSource(unitSource));
+ }
+ }
+ }
+
+ public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding) throws IOException {
+ Charset charset = null;
+ try {
+ charset = Charset.forName(encoding);
+ } catch (IllegalCharsetNameException e) {
+ System.err.println("Illegal charset name : " + encoding); //$NON-NLS-1$
+ return null;
+ } catch(UnsupportedCharsetException e) {
+ System.err.println("Unsupported charset : " + encoding); //$NON-NLS-1$
+ return null;
+ }
+ CharsetDecoder charsetDecoder = charset.newDecoder();
+ charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
+ byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, length);
+ ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length);
+ byteBuffer.put(contents);
+ byteBuffer.flip();
+ return charsetDecoder.decode(byteBuffer).array();
+ }
+
+ public static CharSequence getCharContents(FileObject fileObject, boolean ignoreEncodingErrors, byte[] contents, String encoding) throws IOException {
+ if (contents == null) return null;
+ Charset charset = null;
+ try {
+ charset = Charset.forName(encoding);
+ } catch (IllegalCharsetNameException e) {
+ System.err.println("Illegal charset name : " + encoding); //$NON-NLS-1$
+ return null;
+ } catch(UnsupportedCharsetException e) {
+ System.err.println("Unsupported charset : " + encoding); //$NON-NLS-1$
+ return null;
+ }
+ CharsetDecoder charsetDecoder = charset.newDecoder();
+ ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length);
+ byteBuffer.put(contents);
+ byteBuffer.flip();
+ if (ignoreEncodingErrors) {
+ charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
+ return charsetDecoder.decode(byteBuffer);
+ } else {
+ charsetDecoder.onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT);
+ CharBuffer out = CharBuffer.allocate(contents.length);
+ CoderResult result = null;
+ String replacement = charsetDecoder.replacement();
+ int replacementLength = replacement.length();
+ EncodingErrorCollector collector = null;
+ while (true) {
+ result = charsetDecoder.decode(byteBuffer, out, true);
+ if (result.isMalformed() || result.isUnmappable()) {
+ /* treat the error
+ * The wrong input character is at out.position
+ */
+ if (collector == null) {
+ collector = new EncodingErrorCollector(fileObject, encoding);
+ }
+ reportEncodingError(collector, out.position(), result.length());
+ if ((out.position() + replacementLength) >= out.capacity()) {
+ // resize
+ CharBuffer temp = CharBuffer.allocate(out.capacity() * 2);
+ out.flip();
+ temp.put(out);
+ out = temp;
+ }
+ out.append(replacement);
+ byteBuffer.position(byteBuffer.position() + result.length());
+ continue;
+ }
+ if (result.isOverflow()) {
+ CharBuffer temp = CharBuffer.allocate(out.capacity() * 2);
+ out.flip();
+ temp.put(out);
+ out = temp;
+ } else {
+ break;
+ }
+ }
+ out.flip();
+ if (collector != null) {
+ collector.reportAllEncodingErrors(out.toString());
+ }
+ return out;
+ }
+ }
+
+ private static void reportEncodingError(EncodingErrorCollector collector, int position, int length) {
+ collector.collect(position, -length);
+ }
+}
+
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptBinaryLocalVariableBinding.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptBinaryLocalVariableBinding.java
new file mode 100644
index 00000000..53315f58
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptBinaryLocalVariableBinding.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class AptBinaryLocalVariableBinding extends LocalVariableBinding {
+ AnnotationBinding[] annotationBindings;
+ // enclosing element
+ public MethodBinding methodBinding;
+
+ public AptBinaryLocalVariableBinding(char[] name, TypeBinding type, int modifiers, AnnotationBinding[] annotationBindings, MethodBinding methodBinding) {
+ super(name, type, modifiers, true);
+ this.annotationBindings = annotationBindings == null ? Binding.NO_ANNOTATIONS : annotationBindings;
+ this.methodBinding = methodBinding;
+ }
+
+ public AnnotationBinding[] getAnnotations() {
+ return this.annotationBindings;
+ }
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptSourceLocalVariableBinding.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptSourceLocalVariableBinding.java
new file mode 100644
index 00000000..81441c82
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/lookup/AptSourceLocalVariableBinding.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class AptSourceLocalVariableBinding extends LocalVariableBinding {
+
+ // enclosing element
+ public MethodBinding methodBinding;
+ private LocalVariableBinding local;
+
+ public AptSourceLocalVariableBinding(LocalVariableBinding localVariableBinding, MethodBinding methodBinding) {
+ super(localVariableBinding.name, localVariableBinding.type, localVariableBinding.modifiers, true);
+ this.constant = localVariableBinding.constant;
+ this.declaration = localVariableBinding.declaration;
+ this.declaringScope = localVariableBinding.declaringScope;
+ this.id = localVariableBinding.id;
+ this.resolvedPosition = localVariableBinding.resolvedPosition;
+ this.tagBits = localVariableBinding.tagBits;
+ this.useFlag = localVariableBinding.useFlag;
+ this.initializationCount = localVariableBinding.initializationCount;
+ this.initializationPCs = localVariableBinding.initializationPCs;
+ this.methodBinding = methodBinding;
+ this.local = localVariableBinding;
+ }
+
+ @Override
+ public AnnotationBinding[] getAnnotations() {
+ return this.local.getAnnotations();
+ }
+}
diff --git a/org.eclipse.jdt.core/aspectj/org/aspectj/ajdt/internal/compiler/CompilerAdapter.aj b/org.eclipse.jdt.core/aspectj/org/aspectj/ajdt/internal/compiler/CompilerAdapter.aj
index 4aea2b15..3dd82056 100644
--- a/org.eclipse.jdt.core/aspectj/org/aspectj/ajdt/internal/compiler/CompilerAdapter.aj
+++ b/org.eclipse.jdt.core/aspectj/org/aspectj/ajdt/internal/compiler/CompilerAdapter.aj
@@ -1,12 +1,12 @@
/* *******************************************************************
* Copyright (c) 2005 Contributors.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://eclipse.org/legal/epl-v10.html
- *
- * Contributors:
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
* Adrian Colyer Initial implementation
* ******************************************************************/
package org.aspectj.ajdt.internal.compiler;
@@ -16,60 +16,65 @@ import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+import java.util.Stack;
+
/**
* This aspect implements the necessary hooks around the JDT compiler to allow AspectJ to do its
* job
*/
public privileged aspect CompilerAdapter {
-
+
/**
* A default adapter factory for circumstances when this code is used outside of AspectJ
* Seems overkill?? Will that ever happen???
*/
- private static ICompilerAdapterFactory adapterFactory =
+ private static ICompilerAdapterFactory adapterFactory =
new ICompilerAdapterFactory() {
public ICompilerAdapter getAdapter(Compiler forCompiler) {
return new DefaultCompilerAdapter(forCompiler);
}
};
-
+
/**
* Called by AspectJ to inform the JDT of the AspectJ compiler adapter factor to use.
*/
public static void setCompilerAdapterFactory(ICompilerAdapterFactory factory) {
adapterFactory = factory;
}
-
- /**
- * adapter to drive on compilation events.
- */
- private ICompilerAdapter compilerAdapter;
-
- pointcut dietParsing(Compiler compiler):
+
+ /**
+ * If annotation processing is enabled method Compiler.compile(..) could be called recursively.
+ * So here we introduce stack of adapters instead of single adapter to drive on compilation events.
+ */
+ private final Stack<ICompilerAdapter> compilerAdapterStack = new Stack<ICompilerAdapter>();
+
+ pointcut dietParsing(Compiler compiler):
execution(void Compiler.beginToCompile(ICompilationUnit[])) && this(compiler);
-
+
pointcut compiling(Compiler compiler, ICompilationUnit[] sourceUnits) :
execution(* Compiler.compile(..)) && args(sourceUnits) && this(compiler);
-
+
pointcut processing(CompilationUnitDeclaration unit, int index) :
execution(* Compiler.process(..)) && args(unit,index);
-
+
pointcut resolving(CompilationUnitDeclaration unit) :
call(* CompilationUnitDeclaration.resolve(..)) && target(unit) && within(Compiler);
-
+
pointcut analysing(CompilationUnitDeclaration unit) :
call(* CompilationUnitDeclaration.analyseCode(..)) && target(unit) && within(Compiler);
-
+
pointcut generating(CompilationUnitDeclaration unit) :
call(* CompilationUnitDeclaration.generateCode(..)) && target(unit) && within(Compiler);
-
+
before(Compiler compiler, ICompilationUnit[] sourceUnits) : compiling(compiler, sourceUnits) {
- compilerAdapter = adapterFactory.getAdapter(compiler);
+ final ICompilerAdapter compilerAdapter = adapterFactory.getAdapter(compiler);
+ compilerAdapterStack.push(compilerAdapter);
compilerAdapter.beforeCompiling(sourceUnits);
}
-
+
after(Compiler compiler) returning : compiling(compiler, ICompilationUnit[]) {
try {
+ final ICompilerAdapter compilerAdapter = compilerAdapterStack.pop();
compilerAdapter.afterCompiling(compiler.unitsToProcess);
} catch (AbortCompilation e) {
compiler.handleInternalException(e, null);
@@ -80,45 +85,45 @@ public privileged aspect CompilerAdapter {
compiler.handleInternalException(e, null, null);
throw e; // rethrow
} finally {
- compiler.reset();
- this.compilerAdapter = null;
+ if (compilerAdapterStack.isEmpty())
+ compiler.reset();
}
}
-
+
before(CompilationUnitDeclaration unit, int index) : processing(unit,index) {
- compilerAdapter.beforeProcessing(unit);
+ compilerAdapterStack.peek().beforeProcessing(unit);
}
-
+
after(Compiler compiler) returning(): dietParsing(compiler){
- compilerAdapter.afterDietParsing(compiler.unitsToProcess);
+ compilerAdapterStack.peek().afterDietParsing(compiler.unitsToProcess);
}
-
+
// We want this to run even in the erroneous case to ensure 'compiled:' gets out...
after(CompilationUnitDeclaration unit, int index) : processing(unit, index) {
- compilerAdapter.afterProcessing(unit,index);
+ compilerAdapterStack.peek().afterProcessing(unit,index);
}
-
+
before(CompilationUnitDeclaration unit) : resolving(unit) {
- compilerAdapter.beforeResolving(unit);
+ compilerAdapterStack.peek().beforeResolving(unit);
}
-
+
after(CompilationUnitDeclaration unit) returning : resolving(unit) {
- compilerAdapter.afterResolving(unit);
+ compilerAdapterStack.peek().afterResolving(unit);
}
-
+
before(CompilationUnitDeclaration unit) : analysing(unit) {
- compilerAdapter.beforeAnalysing(unit);
+ compilerAdapterStack.peek().beforeAnalysing(unit);
}
-
+
after(CompilationUnitDeclaration unit) returning : analysing(unit) {
- compilerAdapter.afterAnalysing(unit);
+ compilerAdapterStack.peek().afterAnalysing(unit);
}
-
+
before(CompilationUnitDeclaration unit) : generating(unit) {
- compilerAdapter.beforeGenerating(unit);
+ compilerAdapterStack.peek().beforeGenerating(unit);
}
-
+
after(CompilationUnitDeclaration unit) returning : generating(unit) {
- compilerAdapter.afterGenerating(unit);
+ compilerAdapterStack.peek().afterGenerating(unit);
}
}
diff --git a/org.eclipse.jdt.core/build.xml b/org.eclipse.jdt.core/build.xml
index f3ec69ab..dec31309 100644
--- a/org.eclipse.jdt.core/build.xml
+++ b/org.eclipse.jdt.core/build.xml
@@ -1,5 +1,5 @@
<project name="ShadowJdtCore" basedir="." default="make.jdtcore.jar">
-
+
<property name="eclipse.home" value="/Users/aclement/eclipses/e432/eclipse"/>
<property name="plugins.dir" value="${eclipse.home}/plugins"/>
<property name="plugins.src.dir" value="${plugins.dir}/org.eclipse.platform.source_${eclipse.version}/src"/>
@@ -24,16 +24,16 @@
<zipfileset src="${plugins.dir}/org.eclipse.core.filesystem_1.4.0.v20130514-1240.jar"/>
<zipfileset src="${plugins.dir}/org.eclipse.core.contenttype_3.4.200.v20130326-1255.jar"/>
<zipfileset src="${plugins.dir}/org.eclipse.core.runtime.compatibility.registry_3.5.200.v20130514-1256/runtime_registry_compatibility.jar"/>
-
+
<!-- These are dependencies the original version 785 compiler had but we do not need because of how we use it -->
- <!--
+ <!--
<zipfileset src="${plugins.dir}/org.eclipse.team.core_3.3.1.r33x_20070807.jar"/>
<zipfileset src="${plugins.dir}/org.apache.ant_1.7.0.v200706080842/lib/ant.jar"/>
-->
</jar>
<delete file="lib/jdtDepends-src.zip" failonerror="false"/>
<!-- Build the source for the included libraries -->
-
+
<!-- incomplete... -->
<!--
<jar destfile="lib/jdtDepends-src.zip" update="true">
@@ -48,11 +48,11 @@
<delete file="${aj}/jdtcore-for-aspectj.jar"/>
<jar destfile="${aj}/jdtcore-for-aspectj.jar">
<fileset dir="bin"/>
- </jar>
+ </jar>
<jar destfile="${aj}/jdtcore-for-aspectj.jar" update="true">
<!-- with the AST code now activated, we need text and jface... -->
<zipfileset src="lib/jdtDepends.jar" excludes="org/apache/**,org/w3c/**,org/xml/**,org/xml/**,org/eclipse/jface/**,org/eclipse/osgi/**,META-INF/**"/>
- </jar>
+ </jar>
<delete file="${aj}/jdtcore-for-aspectj-src.zip"/>
<jar destfile="${aj}/jdtcore-for-aspectj-src.zip">
<fileset dir="batch"/>
@@ -66,15 +66,16 @@
<fileset dir="model"/>
<fileset dir="search"/>
<fileset dir="aspectj"/>
- </jar>
+ <fileset dir="apt"/>
+ </jar>
<!--
<jar destfile="../org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip" update="true">
<zipfileset src="lib/jdtDepends-src.zip" excludes="org/apache/**,org/w3c/**,org/xml/**,org/eclipse/jface/**,org/eclipse/text/**,org/eclipse/osgi/**"/>
</jar>
-->
</target>
-
- <target name="make.ajdtcore.jar"
+
+ <target name="make.ajdtcore.jar"
description="build the ajdtcore.jar and jdtcore.jar used by the org.eclipse.ajdt.core plugin">
<delete file="lib/ajdtcore.jar"/>
<jar destfile="lib/ajdtcore.jar">
@@ -89,9 +90,9 @@
<include name = "org/aspectj/weaver/**" />
</zipfileset>
<fileset dir="bin"/>
- </jar>
+ </jar>
</target>
-
+
<target name="transformProjectToORGASPECTJ"
description="Transforms the contents of all source folders to use of an 'org.aspectj' prefix">
<antcall target="transformOneFolderToAJ"><param name="srcfolder" value="antadapter"/></antcall>
@@ -104,8 +105,9 @@
<antcall target="transformOneFolderToAJ"><param name="srcfolder" value="model"/></antcall>
<antcall target="transformOneFolderToAJ"><param name="srcfolder" value="search"/></antcall>
<antcall target="transformOneFolderToAJ"><param name="srcfolder" value="aspectj"/></antcall>
+ <antcall target="transformOneFolderToAJ"><param name="srcfolder" value="apt"/></antcall>
</target>
-
+
<target name="transformProjectFromORGASPECTJ"
description="Transforms the contents of all source folders to remove 'org.aspectj' prefix on package names">
<antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="antadapter"/></antcall>
@@ -116,15 +118,17 @@
<antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="eval"/></antcall>
<antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="formatter"/></antcall>
<antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="model"/></antcall>
- <antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="search"/></antcall>
- <antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="aspectj"/></antcall>
+ <antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="search"/></antcall>
+ <antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="aspectj"/></antcall>
+ <antcall target="transformOneFolderFromAJ"><param name="srcfolder" value="apt"/></antcall>
</target>
-
+
<target name="transformOneFolderToAJ" description="For source folder named in 'srcfolder' param, renames refs to org.aspectj.org.eclipse.jdt">
<delete dir="src-temp" />
-
+ <mkdir dir="src-temp"/>
+
<echo message="Copying '${srcfolder}' to 'src-temp' and modifying file names to include aspectj"/>
-
+
<!-- if the files don't match org.eclipse they won't be looked copied -->
<copy toDir="src-temp">
<fileset dir="${srcfolder}"/>
@@ -133,7 +137,7 @@
<mapper type="regexp" from="^(.*)org\\eclipse\\jdt(.*)$" to="\1org\\aspectj\\org\\eclipse\\jdt\2"/>
-->
</copy>
-
+
<!-- Copy across other stuff as is.. -->
<copy toDir="src-temp">
<fileset dir="${srcfolder}"/>
@@ -142,12 +146,12 @@
<mapper type="regexp" from="^(.*)org\\aspectj\\ajdt(.*)$" to="\1org\\aspectj\\ajdt\2"/>
-->
</copy>
-
+
<echo message="Modifying file contents to change refs from 'org.eclipse.jdt' to 'org.aspectj.org.eclipse.jdt'"/>
-
+
<!-- This next bit of code replaces all the string references. There are two files where
we have to be careful about. Both AssistOptions and CompilerOptions include strings for options that we
- must not change as AJDT will be working with them without the prefix. We skip these two files on the
+ must not change as AJDT will be working with them without the prefix. We skip these two files on the
'big replace' and then do the pair of them with a less pervasive replace that will just do import and
package statements. -->
<replaceregexp byline="true" flags="g">
@@ -157,46 +161,46 @@
<include name="**/*"/>
<exclude name="**/AssistOptions.java"/>
<exclude name="**/CompilerOptions.java"/>
- </fileset>
+ </fileset>
</replaceregexp>
-
+
<replaceregexp byline="true" flags="g">
<regexp pattern=" org.eclipse.jdt"/>
<substitution expression=" org.aspectj.org.eclipse.jdt"/>
<fileset dir="src-temp">
<include name="**/AssistOptions.java"/>
<include name="**/CompilerOptions.java"/>
- </fileset>
+ </fileset>
</replaceregexp>
<delete dir="${srcfolder}"/>
-
+
<echo message="Copying from 'src-temp' back to '${srcfolder}'"/>
-
+
<copy toDir="${srcfolder}">
<fileset dir="src-temp"/>
</copy>
-
+
<delete dir="src-temp"/>
</target>
-
+
<target name="transformOneFolderFromAJ" description="For source folder named in 'srcfolder' param, renames refs to org.eclipse.jdt">
<delete dir="src-temp" />
-
+
<echo message="Copying '${srcfolder}' to 'src-temp' and modifying file names to remove aspectj"/>
-
+
<copy toDir="src-temp">
<fileset dir="${srcfolder}"/>
<mapper type="regexp" from="^(.*)org\\aspectj\\org\\eclipse\\jdt(.*)$" to="\1org\\eclipse\\jdt\2"/>
</copy>
-
+
<!-- Copy across other stuff as is.. -->
<copy toDir="src-temp">
<fileset dir="${srcfolder}"/>
<mapper type="regexp" from="^(.*)org\\aspectj\\ajdt(.*)$" to="\1org\\aspectj\\ajdt\2"/>
</copy>
-
-
+
+
<echo message="Modifying file contents to change refs from 'org.aspectj.org.eclipse' to 'org.eclipse.jdt'"/>
<replaceregexp byline="true" flags="g">
@@ -204,7 +208,7 @@
<substitution expression="org.eclipse.jdt"/>
<fileset dir="src-temp">
<include name="**/*"/>
- </fileset>
+ </fileset>
</replaceregexp>
<delete dir="${srcfolder}"/>
@@ -215,5 +219,5 @@
</copy>
<delete dir="src-temp"/>
</target>
-
+
</project> \ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
index 4b006cbf..b75a10d2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
@@ -417,6 +417,10 @@ public class Compiler implements ITypeRequestor, ProblemSeverities {
* -> recompile any required types for which we have an incomplete principle structure
*/
public void compile(ICompilationUnit[] sourceUnits) {
+ compile(sourceUnits, false);
+ }
+
+ public void compile(ICompilationUnit[] sourceUnits, boolean ignoreAnnotationProcessing) {
this.stats.startTime = System.currentTimeMillis();
CompilationUnitDeclaration unit = null;
ProcessTaskManager processingTask = null;
@@ -431,7 +435,9 @@ public class Compiler implements ITypeRequestor, ProblemSeverities {
try {
beginToCompile(sourceUnits);
- processAnnotations();
+ if (!ignoreAnnotationProcessing) {
+ processAnnotations();
+ }
if (!this.options.generateClassFiles) {
// -proc:only was set on the command line
return;
@@ -448,7 +454,11 @@ public class Compiler implements ITypeRequestor, ProblemSeverities {
System.arraycopy(originalUnits, 0, combinedUnits, 0, originalLength);
System.arraycopy(e.newAnnotationProcessorUnits, 0, combinedUnits, originalLength, newProcessedLength);
this.annotationProcessorStartIndex = originalLength;
- compile(combinedUnits);
+
+ // Javadoc on javax.annotation.processing.RoundEnvironment#processingOver() claims that
+ // types generated by last round of annotation processing should not be subject to a subsequent rounds
+ // of annotation processing. So this flag have to be added to handle last round of annotation processing gracefully.
+ compile(combinedUnits, e.afterLastAnnotationProcessingRound);
return;
}
}
@@ -879,6 +889,7 @@ public class Compiler implements ITypeRequestor, ProblemSeverities {
internalBeginToCompile(newUnits, newUnitSize);
} catch (SourceTypeCollisionException e) {
e.newAnnotationProcessorUnits = newProcessedUnits;
+ e.afterLastAnnotationProcessingRound = true;
throw e;
} finally {
this.lookupEnvironment.isProcessingAnnotations = false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java
index 615ea936..bbb30b38 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java
@@ -16,4 +16,10 @@ public class SourceTypeCollisionException extends RuntimeException {
private static final long serialVersionUID = 4798247636899127380L;
public ICompilationUnit[] newAnnotationProcessorUnits;
+ /**
+ * Javadoc on {@link javax.annotation.processing.RoundEnvironment#processingOver()} claims that
+ * types generated by last round of annotation processing should not be subject to a subsequent rounds
+ * of annotation processing. So this flag have to be added to handle last round of annotation processing gracefully.
+ */
+ public boolean afterLastAnnotationProcessingRound = false;
}

Back to the top