KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > apt > core > internal > env > BaseProcessorEnv


1 /*******************************************************************************
2  * Copyright (c) 2005 BEA Systems Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * tyeung@bea.com - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.apt.core.internal.env;
12
13 import java.io.File JavaDoc;
14 import java.util.*;
15
16 import org.eclipse.core.resources.IFile;
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.runtime.IPath;
19 import org.eclipse.core.runtime.Path;
20 import org.eclipse.jdt.apt.core.env.Phase;
21 import org.eclipse.jdt.apt.core.internal.AptPlugin;
22 import org.eclipse.jdt.apt.core.internal.AptProject;
23 import org.eclipse.jdt.apt.core.internal.declaration.EclipseDeclarationImpl;
24 import org.eclipse.jdt.apt.core.internal.declaration.PackageDeclarationImpl;
25 import org.eclipse.jdt.apt.core.internal.declaration.PackageDeclarationImplNoBinding;
26 import org.eclipse.jdt.apt.core.internal.declaration.TypeDeclarationImpl;
27 import org.eclipse.jdt.apt.core.internal.type.PrimitiveTypeImpl;
28 import org.eclipse.jdt.apt.core.internal.type.VoidTypeImpl;
29 import org.eclipse.jdt.apt.core.internal.util.DeclarationsUtil;
30 import org.eclipse.jdt.apt.core.internal.util.Factory;
31 import org.eclipse.jdt.apt.core.internal.util.PackageUtil;
32 import org.eclipse.jdt.apt.core.internal.util.TypesUtil;
33 import org.eclipse.jdt.apt.core.internal.util.Visitors.AnnotatedNodeVisitor;
34 import org.eclipse.jdt.apt.core.util.AptConfig;
35 import org.eclipse.jdt.core.BindingKey;
36 import org.eclipse.jdt.core.IClassFile;
37 import org.eclipse.jdt.core.ICompilationUnit;
38 import org.eclipse.jdt.core.IJavaElement;
39 import org.eclipse.jdt.core.IJavaProject;
40 import org.eclipse.jdt.core.IMember;
41 import org.eclipse.jdt.core.IPackageFragment;
42 import org.eclipse.jdt.core.IPackageFragmentRoot;
43 import org.eclipse.jdt.core.IType;
44 import org.eclipse.jdt.core.JavaModelException;
45 import org.eclipse.jdt.core.dom.AST;
46 import org.eclipse.jdt.core.dom.ASTNode;
47 import org.eclipse.jdt.core.dom.ASTParser;
48 import org.eclipse.jdt.core.dom.ASTRequestor;
49 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
50 import org.eclipse.jdt.core.dom.Annotation;
51 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
52 import org.eclipse.jdt.core.dom.CompilationUnit;
53 import org.eclipse.jdt.core.dom.IBinding;
54 import org.eclipse.jdt.core.dom.IMethodBinding;
55 import org.eclipse.jdt.core.dom.ITypeBinding;
56 import org.eclipse.jdt.core.dom.IVariableBinding;
57 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
58
59 import com.sun.mirror.apt.AnnotationProcessorEnvironment;
60 import com.sun.mirror.apt.AnnotationProcessorListener;
61 import com.sun.mirror.apt.Filer;
62 import com.sun.mirror.apt.Messager;
63 import com.sun.mirror.declaration.AnnotationTypeDeclaration;
64 import com.sun.mirror.declaration.Declaration;
65 import com.sun.mirror.declaration.PackageDeclaration;
66 import com.sun.mirror.declaration.TypeDeclaration;
67 import com.sun.mirror.util.Declarations;
68 import com.sun.mirror.util.Types;
69
70 /**
71  * Base annotation processor environment that supports type system navigation.
72  * No support for problem registration as well as type generation.
73  *
74  * @author tyeung
75  */

76 public class BaseProcessorEnv implements AnnotationProcessorEnvironment
77 {
78     static{
79         final AST ast = AST.newAST(AST.JLS3);
80         EMPTY_AST_UNIT = ast.newCompilationUnit();
81     }
82     public static final CompilationUnit EMPTY_AST_UNIT;
83     public static final ICompilationUnit[] NO_UNIT = new ICompilationUnit[0];
84     public static final CompilationUnit[] NO_AST_UNITs = new CompilationUnit[0];
85     public static final String JavaDoc[] NO_KEYS = new String JavaDoc[0];
86
87     private static final int BOOLEAN_INDEX = 0;
88     private static final int BYTE_INDEX = 1;
89     private static final int CHAR_INDEX = 2;
90     private static final int DOUBLE_INDEX = 3;
91     private static final int FLOAT_INDEX = 4;
92     private static final int INT_INDEX = 5;
93     private static final int LONG_INDEX = 6;
94     private static final int SHORT_INDEX = 7;
95     
96     private static final String JavaDoc DOT_JAVA = ".java"; //$NON-NLS-1$
97

98     protected CompilationUnit _astRoot;
99     protected final Phase _phase;
100     protected IFile _file;
101     protected final IJavaProject _javaProject;
102     protected final AptProject _aptProject;
103     
104     /**
105      * Unmodifiable map of processor options, including -A options.
106      * Set in ctor and then not changed.
107      */

108     protected final Map<String JavaDoc, String JavaDoc> _options;
109
110     /**
111      * Mapping model compilation unit to dom compilation unit.
112      * The assumption here is that once the client examine some binding from some file,
113      * it will continue to examine other bindings from came from that same file.
114      */

115     protected final Map<ICompilationUnit, CompilationUnit> _modelCompUnit2astCompUnit;
116     /**
117      * Mapping (source) top-level type binding to the compilation unit that defines it.
118      */

119     protected final Map<ITypeBinding, ICompilationUnit> _typeBinding2ModelCompUnit;
120     // void type and the primitive types will be null if the '_file'
121
// is outside of the workspace.
122
private VoidTypeImpl _voidType;
123     private PrimitiveTypeImpl[] _primitives;
124     
125     // This type cache exists for the duration of a single round.
126
// We store positive as well as negative hits. Negative hits are
127
// stored with a value of null
128
protected final Map<String JavaDoc,TypeDeclaration> _typeCache = new HashMap<String JavaDoc,TypeDeclaration>();
129     
130     protected IPackageFragmentRoot[] _packageRootsCache;
131     
132     public BaseProcessorEnv(CompilationUnit astCompilationUnit,
133                             IFile file,
134                             IJavaProject javaProj,
135                             Phase phase )
136     {
137         _astRoot = astCompilationUnit;
138         _file = file;
139         _javaProject = javaProj;
140         _phase = phase;
141         _options = initOptions(javaProj);
142         _modelCompUnit2astCompUnit = new HashMap<ICompilationUnit, CompilationUnit>();
143         _typeBinding2ModelCompUnit = new HashMap<ITypeBinding, ICompilationUnit>();
144         _aptProject = AptPlugin.getAptProject(javaProj);
145     }
146   
147     /**
148      * Set the _options map based on the current project/workspace settings.
149      * There is a bug in Sun's apt implementation: it parses the command line
150      * incorrectly, such that -Akey=value gets added to the options map as
151      * key "-Akey=value" and value "". In order to support processors written
152      * to run on Sun's apt as well as processors written without this bug
153      * in mind, we populate the map with two copies of every option, one the
154      * expected way ("key" / "value") and the other the Sun way
155      * ("-Akey=value" / ""). We make exceptions for the non-dash-A options
156      * that we set automatically, such as -classpath, -target, and so forth;
157      * since these wouldn't have come from a -A option we don't construct a
158      * -Akey=value variant.
159      *
160      * Called from constructor. A new Env is constructed for each build pass,
161      * so this will always be up to date with the latest settings.
162      */

163     private Map<String JavaDoc, String JavaDoc> initOptions(IJavaProject jproj) {
164         Map<String JavaDoc, String JavaDoc> procOptions = AptConfig.getProcessorOptions(jproj);
165         // options is large enough to include the translated -A options
166
Map<String JavaDoc, String JavaDoc> options = new HashMap<String JavaDoc, String JavaDoc>(procOptions.size() * 2);
167         
168         // Add configured options
169
for (Map.Entry<String JavaDoc, String JavaDoc> entry : procOptions.entrySet()) {
170             String JavaDoc value = entry.getValue();
171             String JavaDoc key = entry.getKey();
172             options.put(key, value);
173             if (!AptConfig.isAutomaticProcessorOption(key)) {
174                 String JavaDoc sunStyle;
175                 if (value != null) {
176                     sunStyle = "-A" + entry.getKey() + "=" + value; //$NON-NLS-1$ //$NON-NLS-2$
177
}
178                 else {
179                     sunStyle = "-A" + entry.getKey(); //$NON-NLS-1$
180
}
181                 options.put(sunStyle, ""); //$NON-NLS-1$
182
}
183         }
184         return Collections.unmodifiableMap(options);
185     }
186
187     public Types getTypeUtils()
188     {
189         return new TypesUtil(this);
190     }
191     
192     public Declarations getDeclarationUtils()
193     {
194         return new DeclarationsUtil();
195     }
196     
197     public void addListener(AnnotationProcessorListener listener) {
198         throw new UnsupportedOperationException JavaDoc("Not supported!"); //$NON-NLS-1$
199
}
200     
201     public void removeListener(AnnotationProcessorListener listener) {
202         throw new UnsupportedOperationException JavaDoc("Not supported!"); //$NON-NLS-1$
203
}
204     
205     /**
206      * @return the list of all named type declarations in the compilation units associated with
207      * this environment - usually just one compilation unit, except in batch mode
208      * where it will be all compilation units in the build.
209      * This implementation is different from the API specification in that it does not return
210      * all included source types in the universe.
211      */

212     public Collection<TypeDeclaration> getTypeDeclarations()
213     {
214         final List<ITypeBinding> bindings = getTypeBindings();
215         if( bindings.isEmpty() )
216             return Collections.emptyList();
217         final List<TypeDeclaration> mirrorDecls = new ArrayList<TypeDeclaration>(bindings.size());
218
219         for( ITypeBinding binding : bindings ){
220             final TypeDeclaration mirrorDecl = Factory.createReferenceType(binding, this);
221             if( mirrorDecl != null )
222                 mirrorDecls.add(mirrorDecl);
223         }
224
225         return mirrorDecls;
226     }
227     
228     @SuppressWarnings JavaDoc("unchecked")
229     protected List<AbstractTypeDeclaration> searchLocallyForTypeDeclarations()
230     {
231         return _astRoot.types();
232     }
233     
234     private List<ITypeBinding> getTypeBindings()
235     {
236         final List<AbstractTypeDeclaration> declTypes = searchLocallyForTypeDeclarations();
237         if( declTypes == null || declTypes.isEmpty() )
238             return Collections.emptyList();
239         final List<ITypeBinding> typeBindings = new ArrayList<ITypeBinding>(declTypes.size());
240
241         for( AbstractTypeDeclaration decl : declTypes ){
242             getTypeBindings(decl.resolveBinding(), typeBindings);
243         }
244         return typeBindings;
245     }
246     
247     /**
248      * Add <code>type</code> and all its declared nested type(s) to <code>types</code>
249      * @param type the container type
250      * @param typeBindings upon return, contains all the nested types within <code>type</code>
251      * and the type itself.
252      */

253     protected void getTypeBindings(final ITypeBinding type, final List<ITypeBinding> typeBindings)
254     {
255         if( type == null ) return;
256         typeBindings.add(type);
257         for( ITypeBinding nestedType : type.getDeclaredTypes() ) {
258             //typeBindings.add(nestedType);
259
getTypeBindings(nestedType, typeBindings);
260         }
261     }
262     
263     public Collection<TypeDeclaration> getSpecifiedTypeDeclarations()
264     {
265         return getTypeDeclarations();
266     }
267     
268     public Collection<Declaration> getDeclarationsAnnotatedWith(AnnotationTypeDeclaration a)
269     {
270          final ITypeBinding annotationType = TypesUtil.getTypeBinding(a);
271          if( annotationType == null || !annotationType.isAnnotation()) return Collections.emptyList();
272          return getDeclarationsAnnotatedWith(annotationType);
273     }
274     
275     /**
276      * Go through the current compilation unit and look for ast nodes that has annotations.
277      * @return the map between ast node and
278      */

279     protected Map<ASTNode, List<Annotation>> getASTNodesWithAnnotations()
280     {
281         final Map<ASTNode, List<Annotation>> astNode2Anno = new HashMap<ASTNode, List<Annotation>>();
282         final AnnotatedNodeVisitor visitor = new AnnotatedNodeVisitor(astNode2Anno);
283         _astRoot.accept(visitor);
284         return astNode2Anno;
285     }
286
287     private List<Declaration> getDeclarationsAnnotatedWith(final ITypeBinding annotationType)
288     {
289         final Map<ASTNode, List<Annotation>> astNode2Anno = getASTNodesWithAnnotations();
290         if( astNode2Anno.isEmpty() )
291             return Collections.emptyList();
292         final List<Declaration> decls = new ArrayList<Declaration>();
293         for(Map.Entry<ASTNode, List<Annotation>> entry : astNode2Anno.entrySet() ){
294             final ASTNode node = entry.getKey();
295             for( Annotation anno : entry.getValue() ){
296                 final IBinding resolvedTypeBinding = anno.resolveTypeBinding();
297                 if( annotationType.isEqualTo(resolvedTypeBinding) )
298                     getDeclarations(node, decls);
299             }
300         }
301         return decls;
302
303     }
304     
305     protected IFile getFileForNode(final ASTNode node)
306     {
307         if( node.getRoot() == _astRoot )
308             return _file;
309         
310         throw new IllegalStateException JavaDoc(); // should never get here.
311
}
312     
313     /**
314      * @param node the ast node in question
315      * @param decls the list to be populated.
316      * adding the declaration(s) corresponding to the ast node to this list.
317      */

318     @SuppressWarnings JavaDoc("unchecked")
319     protected void getDeclarations(ASTNode node, List<Declaration>decls)
320     {
321         if( node == null ) return;
322         IBinding binding = null;
323         switch( node.getNodeType() )
324         {
325         case ASTNode.FIELD_DECLARATION:
326             final List<VariableDeclarationFragment> fragments =
327                 ((org.eclipse.jdt.core.dom.FieldDeclaration)node).fragments();
328             for( VariableDeclarationFragment frag : fragments ){
329                 final IBinding fieldBinding = frag.resolveBinding();
330                 final EclipseDeclarationImpl decl;
331                 if( fieldBinding != null )
332                     decl = Factory.createDeclaration(fieldBinding, this);
333                 else{
334                     decl = Factory.createDeclaration(frag, getFileForNode(frag), this);
335                 }
336                 if( decl != null )
337                     decls.add(decl);
338             }
339             return;
340
341         case ASTNode.ENUM_CONSTANT_DECLARATION:
342             binding = ((org.eclipse.jdt.core.dom.EnumConstantDeclaration)node).resolveVariable();
343             break;
344         case ASTNode.METHOD_DECLARATION:
345             binding = ((org.eclipse.jdt.core.dom.MethodDeclaration)node).resolveBinding();
346             break;
347         case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION:
348             binding = ((AnnotationTypeMemberDeclaration)node).resolveBinding();
349             break;
350         case ASTNode.TYPE_DECLARATION:
351         case ASTNode.ANNOTATION_TYPE_DECLARATION:
352         case ASTNode.ENUM_DECLARATION:
353             binding = ((AbstractTypeDeclaration)node).resolveBinding();
354             break;
355         case ASTNode.SINGLE_VARIABLE_DECLARATION:
356             // Need to create the declaration with the ast node, not the binding
357
break;
358         case ASTNode.PACKAGE_DECLARATION:
359             binding = ((org.eclipse.jdt.core.dom.PackageDeclaration)node).resolveBinding();
360             break;
361         default:
362             throw new UnsupportedOperationException JavaDoc("unknown node type: " + node.getNodeType()); //$NON-NLS-1$
363
}
364
365         final EclipseDeclarationImpl decl;
366         if( binding != null )
367             decl = Factory.createDeclaration(binding, this);
368         else{
369             decl = Factory.createDeclaration(node, getFileForNode(node), this);
370         }
371         if( decl != null )
372             decls.add( decl );
373         
374         return;
375     }
376
377     
378     
379     /**
380      * @param binding must be correspond to a type, method or field declaration.
381      * @return the ast node the corresponds to the declaration of the given binding.
382      * Return null if none is found.
383      */

384     public ASTNode getASTNodeForBinding(final IBinding binding)
385     {
386         final CompilationUnit astUnit = getCompilationUnitForBinding(binding);
387         if( astUnit == null )
388             return null;
389         return astUnit.findDeclaringNode(binding.getKey());
390     }
391     
392     public Map<String JavaDoc, String JavaDoc> getOptions(){ return _options; }
393     
394     // does not generate dependencies
395
public TypeDeclaration getTypeDeclaration(String JavaDoc name)
396     {
397         if( name == null || name.length() == 0 ) return null;
398
399         // get rid of the generics parts.
400
final int index = name.indexOf('<');
401         if( index != -1 )
402             name = name.substring(0, index);
403         
404         ITypeBinding typeBinding = null;
405         try {
406             typeBinding = getTypeDefinitionBindingFromName(name);
407         }
408         catch (ArrayIndexOutOfBoundsException JavaDoc e) {
409             // https://bugs.eclipse.org/bugs/show_bug.cgi?id=133947
410
// if the name is invalid, JDT can throw an ArrayIndexOutOfBoundsException
411
// We'll ignore this and return null to the user
412
AptPlugin.log(e, "Unable to get type definition binding for: " + name); //$NON-NLS-1$
413
}
414         
415         return Factory.createReferenceType(typeBinding, this);
416     }
417     
418     /**
419      * @param fullyQualifiedName the fully qualified name of a type.
420      * The name cannot contain type argument or array signature.
421      * The name *must* also be correct wrt $ for inner-class separators.
422      * e.g. java.util.Map$Entry, NOT java.util.Map.Entry
423      * @return the type binding corresponding to the parameter.
424      */

425     protected ITypeBinding getTypeDefinitionBindingFromCorrectName(
426             final String JavaDoc fullyQualifiedName ){
427         final int dollarIndex = fullyQualifiedName.indexOf('$');
428         final String JavaDoc toplevelTypeName;
429         if( dollarIndex < 0 )
430             toplevelTypeName = fullyQualifiedName;
431         else
432             toplevelTypeName = fullyQualifiedName.substring(0, dollarIndex);
433         
434         // locate the compilation unit for the type of interest.
435
// we need this information so that when we request the binding for 'fullyQualifiedName'
436
// we can get the dom pipeline to return back to us the ast compilation unit
437
// which we will need to correctly compute the number of methods, fields and constructors.
438
// see CR259011 -theodora
439
ICompilationUnit unit = getICompilationUnitForTopLevelType(toplevelTypeName);
440         final String JavaDoc key = BindingKey.createTypeBindingKey(fullyQualifiedName);
441         return getTypeBindingFromKey(key, unit);
442     }
443   
444     private ITypeBinding getTypeDefinitionBindingFromName(String JavaDoc fullyQualifiedName) {
445         // We don't know for sure that the name we have represents a top-level type,
446
// so we need to loop backwards until we find one, in case we have something
447
// like "java.util.Map.Entry", converting it to "java.util.Map$Entry". --jgarms
448
ITypeBinding binding = getTypeDefinitionBindingFromCorrectName(fullyQualifiedName);
449         while (binding == null) {
450             int dotIndex = fullyQualifiedName.lastIndexOf('.');
451             if (dotIndex == -1) {
452                 break;
453             }
454             fullyQualifiedName = fullyQualifiedName.substring(0, dotIndex) +
455                 "$" + //$NON-NLS-1$
456
fullyQualifiedName.substring(dotIndex + 1);
457             binding = getTypeDefinitionBindingFromCorrectName(fullyQualifiedName);
458         }
459         return binding;
460     }
461     
462     /**
463      * @param key
464      * @param unit the unit that contains the definition of type whose type key is <code>key</code>
465      * if <code>key</code> is a wild card, primitive, array type or parameterized type, this should be null.
466      * @return return the type binding for the given key or null if none is found.
467      */

468     protected ITypeBinding getTypeBindingFromKey(final String JavaDoc key, final ICompilationUnit unit){
469         
470         class BindingRequestor extends ASTRequestor
471         {
472             private ITypeBinding _result = null;
473             public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
474                 if( source == unit ){
475                     _modelCompUnit2astCompUnit.put(source, ast);
476                 }
477             }
478             public void acceptBinding(String JavaDoc bindingKey, IBinding binding)
479             {
480                 if( binding != null && binding.getKind() == IBinding.TYPE )
481                     _result = (ITypeBinding)binding;
482             }
483         }
484
485         final BindingRequestor requestor = new BindingRequestor();
486         final ASTParser parser = ASTParser.newParser(AST.JLS3);
487         parser.setResolveBindings(true);
488         parser.setProject(_javaProject);
489         ICompilationUnit[] units = unit == null ? NO_UNIT : new ICompilationUnit[]{unit};
490         parser.createASTs(units, new String JavaDoc[]{key}, requestor, null);
491         final ITypeBinding result = requestor._result;
492         if(result != null && unit != null){
493             final CompilationUnit astUnit = _modelCompUnit2astCompUnit.get(unit);
494             // make sure everything is lining up properly.
495
if( astUnit.findDeclaringNode(result) != null ){
496                 ITypeBinding declaringClass = getDeclaringClass(result);
497                 _typeBinding2ModelCompUnit.put(declaringClass, unit);
498             }
499         }
500         return result;
501     }
502     
503     /**
504      * @param key the key to a type binding, could be reference type, array or primitive.
505      * @return the binding corresponding to the given key or null if none is found.
506      */

507     public ITypeBinding getTypeBindingFromKey(final String JavaDoc key)
508     {
509         return getTypeBindingFromKey(key, null);
510         
511     }
512     
513     public TypeDeclaration getTypeDeclaration(final IType type) {
514         if (type == null) return null;
515         String JavaDoc name = type.getFullyQualifiedName();
516         return getTypeDeclaration(name);
517     }
518     
519     public PackageDeclaration getPackage(String JavaDoc name)
520     {
521         if (name == null)
522             throw new IllegalArgumentException JavaDoc("name cannot be null"); //$NON-NLS-1$
523
IPackageFragment[] pkgFrags = PackageUtil.getPackageFragments(name, this);
524
525         // No packages found, null expected
526
if (pkgFrags.length == 0)
527             return null;
528
529         // If there are no source or class files, we'll need to return
530
// a special implementation of the package decl that expects
531
// no declarations inside it
532
boolean containsNoJavaResources = true;
533         for (IPackageFragment pkg : pkgFrags) {
534             try {
535                 if (pkg.containsJavaResources()) {
536                     containsNoJavaResources = false;
537                     break;
538                 }
539             }
540             catch (JavaModelException e) {}
541         }
542         if (containsNoJavaResources)
543             return new PackageDeclarationImplNoBinding(pkgFrags);
544
545         // We should be able to create a class or
546
// source file from one of the packages.
547
ICompilationUnit compUnit = null;
548         IClassFile classFile = null;
549
550         OUTER:
551         for (IPackageFragment pkg : pkgFrags) {
552             try {
553                 ICompilationUnit[] compUnits = pkg.getCompilationUnits();
554                 if (compUnits.length > 0) {
555                     compUnit = compUnits[0];
556                     break;
557                 }
558                 IClassFile[] classFiles = pkg.getClassFiles();
559                 if (classFiles.length > 0) {
560                     // Need to grab the first one that's not an inner class,
561
// as eclipse has trouble parsing inner class files
562
for (IClassFile tempClassFile : classFiles) {
563                         if (tempClassFile.getElementName().indexOf("$") < 0) { //$NON-NLS-1$
564
classFile = tempClassFile;
565                             break OUTER;
566                         }
567                     }
568                 }
569             }
570             catch (JavaModelException e) {}
571         }
572
573         IType type = null;
574         if (compUnit != null) {
575             try {
576                 IType[] types = compUnit.getAllTypes();
577                 if (types.length > 0) {
578                     type = types[0];
579                 }
580             }
581             catch (JavaModelException e) {}
582         }
583         else if (classFile != null) {
584             type = classFile.getType();
585         }
586
587         // Given a type, we can construct a package declaration impl from it,
588
// but we must hide the fact that it came from a real declaration,
589
// as the client requested it without that context
590
if (type != null) {
591             TypeDeclarationImpl typeDecl = (TypeDeclarationImpl)getTypeDeclaration(type);
592             ITypeBinding binding = typeDecl.getDeclarationBinding();
593             return new PackageDeclarationImpl(binding.getPackage(), typeDecl, this, true, pkgFrags);
594         }
595
596         // No classes or source files found
597
return new PackageDeclarationImplNoBinding(pkgFrags);
598     }
599     
600     protected CompilationUnit searchLocallyForBinding(final IBinding binding)
601     {
602         if (_astRoot == null) {
603             throw new IllegalStateException JavaDoc("_astRoot is null. Check that types or environments are not being cached between builds or reconciles by user code"); //$NON-NLS-1$
604
}
605         
606         final ASTNode node = _astRoot.findDeclaringNode(binding);
607         if( node != null )
608             return _astRoot;
609         return null;
610     }
611     
612     /**
613      * Retrieve the <code>ICompilationUnit</code> whose top-level type has
614      * <code>topTypeQName</code> as its fully qualified name.
615      * @param topTypeQName
616      * @return the <code>ICompilationUnit</code> matching <code>topTypeQName</code> or
617      * <code>null</code> if one doesn't exist.
618      */

619     private ICompilationUnit getICompilationUnitForTopLevelType(final String JavaDoc topTypeQName ){
620         final String JavaDoc pathname = topTypeQName.replace('.', File.separatorChar) + DOT_JAVA;
621         final IPath path = Path.fromOSString(pathname);
622         try{
623             final IJavaElement element = _javaProject.findElement(path);
624             if( element instanceof ICompilationUnit )
625                 return (ICompilationUnit)element;
626             else // dropping class files.
627
return null;
628         }
629         catch(JavaModelException e){
630             return null;
631         }
632     }
633     
634     /**
635      * @param binding must be correspond to a type, method or field declaration.
636      * @return the compilation unit that contains the declaration of the given binding.
637      */

638     public CompilationUnit getCompilationUnitForBinding(final IBinding binding)
639     {
640         assert binding.getKind() == IBinding.TYPE ||
641                binding.getKind() == IBinding.METHOD ||
642                binding.getKind() == IBinding.VARIABLE ;
643         CompilationUnit domUnit = searchLocallyForBinding(binding);
644         if( domUnit != null )
645             return domUnit;
646         else{
647             final IMember member = (IMember)binding.getJavaElement();
648             final ICompilationUnit unit;
649             if( member != null ){
650                 unit = member.getCompilationUnit();
651             }
652             else{
653                 final ITypeBinding typeBinding = getDeclaringClass(binding);
654                 // binary type don't have compilation unit.
655
if( !typeBinding.isFromSource() )
656                     return null;
657                 if( _typeBinding2ModelCompUnit.get(typeBinding) != null )
658                     unit = _typeBinding2ModelCompUnit.get(typeBinding);
659                 else{
660                     final String JavaDoc qname = typeBinding.getQualifiedName();
661                     unit = getICompilationUnitForTopLevelType(qname);
662                 }
663             }
664             if( unit == null ) return null;
665
666             final CompilationUnit astUnit = _modelCompUnit2astCompUnit.get(unit);
667             if( astUnit != null ) return astUnit;
668             else{
669                 // Note: very expensive operation. we are re-compiling a file with binding information.
670
final ASTParser parser = ASTParser.newParser(AST.JLS3);
671                 parser.setResolveBindings(true);
672                 parser.setSource(unit);
673                 parser.setFocalPosition(0);
674                 CompilationUnit resultUnit = (CompilationUnit)parser.createAST(null);
675                 _modelCompUnit2astCompUnit.put(unit, resultUnit);
676                 return resultUnit;
677             }
678         }
679     }
680     
681     public Filer getFiler(){
682         throw new UnsupportedOperationException JavaDoc("Not supported: the EnvironmentFactory API is for type system navigation only"); //$NON-NLS-1$
683
}
684
685     public Messager getMessager(){
686         throw new UnsupportedOperationException JavaDoc("Not supported: the EnvironmentFactory API is for type system navigation only"); //$NON-NLS-1$
687
}
688     
689     /**
690      * @param binding a type, method or field binding.
691      * @return the top-level type binding that declares <code>binding</code>
692      * or itself if it is already one.
693      */

694     protected static ITypeBinding getDeclaringClass(final IBinding binding)
695     {
696         assert binding != null : "binding cannot be null"; //$NON-NLS-1$
697
ITypeBinding aTypeBinding = null;
698         switch( binding.getKind() )
699         {
700         case IBinding.TYPE:
701             aTypeBinding = (ITypeBinding)binding;
702             break;
703         case IBinding.METHOD:
704             aTypeBinding = ((IMethodBinding)binding).getDeclaringClass();
705             break;
706         case IBinding.VARIABLE:
707             aTypeBinding = ((IVariableBinding)binding).getDeclaringClass();
708             break;
709         default:
710             throw new IllegalStateException JavaDoc("unrecognized binding type " + binding.getKind()); //$NON-NLS-1$
711
}
712         if(aTypeBinding == null ) return null;
713         while( !aTypeBinding.isTopLevel() ){
714             aTypeBinding = aTypeBinding.getDeclaringClass();
715         }
716         return aTypeBinding;
717     }
718     
719     /**
720      * The environment caches the package fragment roots, as
721      * they are expensive to compute
722      */

723     public IPackageFragmentRoot[] getAllPackageFragmentRoots() throws JavaModelException {
724         if (_packageRootsCache == null) {
725             _packageRootsCache = getJavaProject().getAllPackageFragmentRoots();
726         }
727         return _packageRootsCache;
728     }
729     
730     protected IFile searchLocallyForIFile(final IBinding binding)
731     {
732         if (_astRoot == null) {
733             return null;
734         }
735         
736         ASTNode node = _astRoot.findDeclaringNode(binding);
737         if( node != null )
738             return _file;
739         return null;
740     }
741     
742     /**
743      * @param binding must be correspond to a type, method or field declaration
744      * @return the file that contains the declaration of given binding.
745      */

746     public IFile getDeclaringFileForBinding(final IBinding binding)
747     {
748         assert binding.getKind() == IBinding.TYPE ||
749                binding.getKind() == IBinding.METHOD ||
750                binding.getKind() == IBinding.VARIABLE ;
751         // check to see whether it is in the current file.
752
IFile file = searchLocallyForIFile(binding);
753         if( file != null )
754             return file;
755     
756         final IMember member = (IMember)binding.getJavaElement();
757         if( member != null ){
758             final ICompilationUnit unit = member.getCompilationUnit();
759             return (IFile)unit.getResource();
760         }
761         else{
762             final ITypeBinding type = getDeclaringClass(binding);
763             assert type.isTopLevel() : "type must be top-level type"; //$NON-NLS-1$
764
ICompilationUnit unit = _typeBinding2ModelCompUnit.get(type);
765             if( unit != null )
766                 return (IFile)unit.getResource();
767             final String JavaDoc qname = type.getQualifiedName();
768             unit = getICompilationUnitForTopLevelType(qname);
769             if( unit == null )
770                 return null;
771             return (IFile)unit.getResource();
772         }
773     }
774     
775     static class BaseRequestor extends ASTRequestor
776     {
777         ICompilationUnit[] parseUnits;
778         CompilationUnit[] asts;
779         BaseRequestor(ICompilationUnit[] parseUnits)
780         {
781             asts = new CompilationUnit[parseUnits.length];
782             // Init all units to empty to prevent any NPEs
783
Arrays.fill(asts, EMPTY_AST_UNIT);
784             this.parseUnits = parseUnits;
785         }
786         
787         public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
788             for( int i=0, len = asts.length; i<len; i++ ){
789                 if( source == parseUnits[i] ){
790                     asts[i] = ast;
791                     break;
792                 }
793             }
794         }
795         
796     }
797     
798     /**
799      * Parse and fully resolve all files.
800      * @param javaProject
801      * @param parseUnits the files to be parsed and resolved.
802      */

803     static void createASTs(
804             final IJavaProject javaProject,
805             final ICompilationUnit[] parseUnits,
806             ASTRequestor requestor)
807     {
808         // Construct exactly 1 binding key. When acceptBinding is called we know that
809
// All ASTs have been returned. This also means that a pipeline is opened when
810
// there are no asts. This is needed by the batch processors.
811
String JavaDoc bogusKey = BindingKey.createTypeBindingKey("java.lang.Object"); //$NON-NLS-1$
812
String JavaDoc[] keys = new String JavaDoc[] {bogusKey};
813
814         ASTParser p = ASTParser.newParser( AST.JLS3 );
815         p.setResolveBindings( true );
816         p.setProject( javaProject );
817         p.setKind( ASTParser.K_COMPILATION_UNIT );
818         p.createASTs( parseUnits, keys, requestor, null);
819     }
820     
821     /**
822      * This should create an AST without imports or method-body statements
823      */

824     public static CompilationUnit createAST(
825             IJavaProject javaProject,
826             final ICompilationUnit compilationUnit)
827     {
828         if(compilationUnit == null)
829             return null;
830         
831         class CompilationUnitRequestor extends ASTRequestor
832         {
833             CompilationUnit domUnit = EMPTY_AST_UNIT;
834             public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
835                 if( source == compilationUnit )
836                     domUnit = ast;
837             }
838         }
839         
840         CompilationUnitRequestor requestor = new CompilationUnitRequestor();
841         ASTParser p = ASTParser.newParser( AST.JLS3 );
842         p.setResolveBindings( true );
843         p.setProject( javaProject );
844         p.setKind( ASTParser.K_COMPILATION_UNIT );
845         p.createASTs( new ICompilationUnit[]{compilationUnit}, NO_KEYS, requestor, null);
846         if( AptPlugin.DEBUG ){
847             AptPlugin.trace("created DOM AST for " + compilationUnit.getElementName() ); //$NON-NLS-1$
848
}
849         return requestor.domUnit;
850     }
851     
852     /**
853      * @return the ast current being processed
854      */

855     protected AST getCurrentDietAST(){
856         return _astRoot.getAST();
857     }
858     
859     private void initPrimitives()
860     {
861         if(_primitives != null ) return;
862         AST ast = getCurrentDietAST();
863          
864         _primitives = new PrimitiveTypeImpl[8];
865         // boolean
866
ITypeBinding binding = ast.resolveWellKnownType(ITypeConstants.BOOLEAN);
867         if( binding == null )
868             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BOOLEAN); //$NON-NLS-1$
869
_primitives[BOOLEAN_INDEX] = new PrimitiveTypeImpl(binding);
870         // byte
871
binding = ast.resolveWellKnownType(ITypeConstants.BYTE);
872         if( binding == null )
873             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
874
_primitives[BYTE_INDEX] = new PrimitiveTypeImpl(binding);
875         // char
876
binding = ast.resolveWellKnownType(ITypeConstants.CHAR);
877         if( binding == null )
878             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
879
_primitives[CHAR_INDEX] = new PrimitiveTypeImpl(binding);
880         // double
881
binding = ast.resolveWellKnownType(ITypeConstants.DOUBLE);
882         if( binding == null )
883             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
884
_primitives[DOUBLE_INDEX] = new PrimitiveTypeImpl(binding);
885         // float
886
binding = ast.resolveWellKnownType(ITypeConstants.FLOAT);
887         if( binding == null )
888             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
889
_primitives[FLOAT_INDEX] = new PrimitiveTypeImpl(binding);
890         // int
891
binding = ast.resolveWellKnownType(ITypeConstants.INT);
892         if( binding == null )
893             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
894
_primitives[INT_INDEX] = new PrimitiveTypeImpl(binding);
895         // long
896
binding = ast.resolveWellKnownType(ITypeConstants.LONG);
897         if( binding == null )
898             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
899
_primitives[LONG_INDEX] = new PrimitiveTypeImpl(binding);
900         // short
901
binding = ast.resolveWellKnownType(ITypeConstants.SHORT);
902         if( binding == null )
903             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
904
_primitives[SHORT_INDEX] = new PrimitiveTypeImpl(binding);
905         // void
906
binding = ast.resolveWellKnownType(ITypeConstants.VOID);
907         if( binding == null )
908             throw new IllegalStateException JavaDoc("fail to locate " + ITypeConstants.BYTE); //$NON-NLS-1$
909
_voidType = new VoidTypeImpl(binding);
910     }
911     
912     public PrimitiveTypeImpl getBooleanType(){
913         initPrimitives();
914         return _primitives[BOOLEAN_INDEX];
915     }
916     public PrimitiveTypeImpl getByteType(){
917         initPrimitives();
918         return _primitives[BYTE_INDEX];
919     }
920     public PrimitiveTypeImpl getCharType(){
921         initPrimitives();
922         return _primitives[CHAR_INDEX];
923     }
924     public PrimitiveTypeImpl getDoubleType(){
925         initPrimitives();
926         return _primitives[DOUBLE_INDEX];
927     }
928     public PrimitiveTypeImpl getFloatType(){
929         initPrimitives();
930         return _primitives[FLOAT_INDEX];
931     }
932     public PrimitiveTypeImpl getIntType(){
933         initPrimitives();
934         return _primitives[INT_INDEX];
935     }
936     public PrimitiveTypeImpl getLongType(){
937         initPrimitives();
938         return _primitives[LONG_INDEX];
939     }
940     public PrimitiveTypeImpl getShortType(){
941         initPrimitives();
942         return _primitives[SHORT_INDEX];
943     }
944     public VoidTypeImpl getVoidType(){
945         initPrimitives();
946         return _voidType;
947     }
948     
949     public CompilationUnit getAstCompilationUnit(){ return _astRoot; }
950     public IFile getFile() { return _file; }
951     public Phase getPhase(){ return _phase; }
952     public IProject getProject(){ return _javaProject.getProject(); }
953     public IJavaProject getJavaProject(){ return _javaProject; }
954     public AptProject getAptProject(){ return _aptProject; }
955 }
956
Popular Tags