blob: 0dcc4b48fa2c8b549ca56ab042cc43fb083d9e23 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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:
* tyeung@bea.com - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.apt.core.internal.env;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.apt.core.env.EclipseAnnotationProcessorEnvironment;
import org.eclipse.jdt.apt.core.env.Phase;
import org.eclipse.jdt.apt.core.internal.declaration.EclipseMirrorObject;
import org.eclipse.jdt.apt.core.internal.declaration.TypeDeclarationImpl;
import org.eclipse.jdt.apt.core.internal.env.MessagerImpl.Severity;
import org.eclipse.jdt.apt.core.internal.util.Factory;
import org.eclipse.jdt.apt.core.internal.util.Visitors.AnnotationVisitor;
import org.eclipse.jdt.apt.core.util.EclipseMessager;
import org.eclipse.jdt.core.BindingKey;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.compiler.BuildContext;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.ReconcileContext;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import com.sun.mirror.apt.AnnotationProcessorListener;
import com.sun.mirror.apt.Filer;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
/** Base environment to be used during reconcile or build */
public abstract class AbstractCompilationEnv
extends BaseProcessorEnv
implements EclipseAnnotationProcessorEnvironment{
private Set<AnnotationProcessorListener> _listeners = null;
protected List<APTProblem> _problems = new ArrayList<APTProblem>();
private boolean _isClosed = false;
EnvCallback _callback;
/**
* Currently open dom pipeline, used to request type bindings.
*/
protected ASTRequestor _requestor;
public static interface EnvCallback {
public void run(AbstractCompilationEnv env);
}
public static void newReconcileEnv(ReconcileContext reconcileContext, EnvCallback callback)
{
assert reconcileContext != null : "reconcile context is null"; //$NON-NLS-1$
ReconcileEnv env = ReconcileEnv.newEnv(reconcileContext);
env._callback = callback;
env.openPipeline();
}
public static void newBuildEnv(
BuildContext[] filesWithAnnotations,
final BuildContext[] additionalFiles,
IJavaProject javaProj,
EnvCallback callback)
{
assert filesWithAnnotations != null : "missing files"; //$NON-NLS-1$
// note, we are not reading any files.
BuildEnv env = new BuildEnv(filesWithAnnotations, additionalFiles, javaProj);
env._callback = callback;
env.createASTs(filesWithAnnotations);
}
AbstractCompilationEnv(
CompilationUnit compilationUnit,
IFile file,
IJavaProject javaProj,
Phase phase)
{
super(compilationUnit, file, javaProj, phase);
}
@Override
protected ITypeBinding getTypeDefinitionBindingFromCorrectName(String fullyQualifiedName) {
checkValid();
final String key = BindingKey.createTypeBindingKey(fullyQualifiedName);
return (ITypeBinding)_requestor.createBindings(new String[] {key})[0];
}
public void addListener(AnnotationProcessorListener listener)
{
checkValid();
if(_listeners == null )
_listeners = new HashSet<AnnotationProcessorListener>();
_listeners.add(listener);
}
public void removeListener(AnnotationProcessorListener listener)
{
checkValid();
if( _listeners == null ) return;
_listeners.remove(listener);
}
public Set<AnnotationProcessorListener> getProcessorListeners()
{
if( _listeners == null )
return Collections.emptySet();
return Collections.unmodifiableSet(_listeners);
}
public Map<String, String> getOptions()
{
final HashMap<String, String> options = new HashMap<String, String>(_options);
options.put("phase", getPhase().toString()); //$NON-NLS-1$
return options;
}
abstract public CompilationUnit getASTFrom(final IFile file);
public CompilationUnit getAST(){
return _astRoot;
}
public EclipseMessager getMessager()
{
checkValid();
return new MessagerImpl(this);
}
abstract void addMessage(
IFile resource,
int start,
int end,
Severity severity,
String msg,
int line,
String[] arguments);
public List<? extends CategorizedProblem> getProblems(){
checkValid();
if( !_problems.isEmpty() )
EnvUtil.updateProblemLength(_problems, getAstCompilationUnit());
return _problems;
}
APTProblem createProblem(
IFile resource,
int start,
int end,
Severity severity,
String msg,
int line,
String[] arguments)
{
// end-1 since IProblem ending offsets are inclusive but DOM layer
// ending offsets are exclusive.
final APTProblem newProblem =
new APTProblem(msg, severity, resource, start, end-1, line, arguments);
return newProblem;
}
public abstract Filer getFiler();
/**
* @return all annotation types in the current compilation unit.
*/
public Map<String, AnnotationTypeDeclaration> getAnnotationTypes()
{
checkValid();
final List<Annotation> instances = new ArrayList<Annotation>();
final Map<String, AnnotationTypeDeclaration> decls =
new HashMap<String, AnnotationTypeDeclaration>();
final AnnotationVisitor visitor = new AnnotationVisitor(instances);
_astRoot.accept(visitor);
for (int instanceIndex=0, size = instances.size(); instanceIndex < size; instanceIndex++) {
final Annotation instance = instances.get(instanceIndex);
final ITypeBinding annoType = instance.resolveTypeBinding();
if (annoType == null)
continue;
final TypeDeclarationImpl decl =
Factory.createReferenceType(annoType, this);
if (decl.kind() == EclipseMirrorObject.MirrorKind.TYPE_ANNOTATION){
final AnnotationTypeDeclaration annoDecl = (AnnotationTypeDeclaration)decl;
decls.put(annoDecl.getQualifiedName(), annoDecl);
}
}
return decls;
}
/* package */ void checkValid()
{
if( _isClosed )
throw new IllegalStateException("Environment has expired"); //$NON-NLS-1$
}
public void close(){
if (isClosed())
return;
if(_listeners != null)
_listeners.clear();
_problems = null;
_typeCache.clear();
_packageRootsCache = null;
_isClosed = true;
_callback = null;
_requestor = null;
}
boolean isClosed(){ return _isClosed; }
}