KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > core > dom > CompilationUnitResolver


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
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  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.core.dom;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.OperationCanceledException;
20 import org.eclipse.jdt.core.ICompilationUnit;
21 import org.eclipse.jdt.core.IJavaElement;
22 import org.eclipse.jdt.core.IJavaProject;
23 import org.eclipse.jdt.core.JavaModelException;
24 import org.eclipse.jdt.core.WorkingCopyOwner;
25 import org.eclipse.jdt.core.compiler.CategorizedProblem;
26 import org.eclipse.jdt.core.compiler.CharOperation;
27 import org.eclipse.jdt.internal.compiler.CompilationResult;
28 import org.eclipse.jdt.internal.compiler.Compiler;
29 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
30 import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
31 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
32 import org.eclipse.jdt.internal.compiler.IProblemFactory;
33 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
34 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
35 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
36 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
37 import org.eclipse.jdt.internal.compiler.env.ISourceType;
38 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
39 import org.eclipse.jdt.internal.compiler.lookup.Binding;
40 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
41 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
42 import org.eclipse.jdt.internal.compiler.parser.Parser;
43 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
44 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
45 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
46 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
47 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
48 import org.eclipse.jdt.internal.compiler.util.Messages;
49 import org.eclipse.jdt.internal.core.BinaryMember;
50 import org.eclipse.jdt.internal.core.CancelableNameEnvironment;
51 import org.eclipse.jdt.internal.core.CancelableProblemFactory;
52 import org.eclipse.jdt.internal.core.JavaProject;
53 import org.eclipse.jdt.internal.core.NameLookup;
54 import org.eclipse.jdt.internal.core.SourceRefElement;
55 import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
56 import org.eclipse.jdt.internal.core.util.BindingKeyResolver;
57 import org.eclipse.jdt.internal.core.util.CommentRecorderParser;
58 import org.eclipse.jdt.internal.core.util.DOMFinder;
59
60 class CompilationUnitResolver extends Compiler JavaDoc {
61
62     /* A list of int */
63     static class IntArrayList {
64         public int[] list = new int[5];
65         public int length = 0;
66         public void add(int i) {
67             if (this.list.length == this.length) {
68                 System.arraycopy(this.list, 0, this.list = new int[this.length*2], 0, this.length);
69             }
70                 this.list[this.length++] = i;
71             }
72         }
73
74     /*
75      * The sources that were requested.
76      * Map from file name (char[]) to ICompilationUnit.
77      */

78     HashtableOfObject requestedSources;
79
80     /*
81      * The binding keys that were requested.
82      * Map from file name (char[]) to BindingKey (or ArrayList if multiple keys in the same file).
83      */

84     HashtableOfObject requestedKeys;
85
86     DefaultBindingResolver.BindingTables bindingTables;
87
88     boolean hasCompilationAborted;
89
90     private IProgressMonitor monitor;
91
92     /**
93      * Answer a new CompilationUnitVisitor using the given name environment and compiler options.
94      * The environment and options will be in effect for the lifetime of the compiler.
95      * When the compiler is run, compilation results are sent to the given requestor.
96      *
97      * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment
98      * Environment used by the compiler in order to resolve type and package
99      * names. The name environment implements the actual connection of the compiler
100      * to the outside world (for example, in batch mode the name environment is performing
101      * pure file accesses, reuse previous build state or connection to repositories).
102      * Note: the name environment is responsible for implementing the actual classpath
103      * rules.
104      *
105      * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy
106      * Configurable part for problem handling, allowing the compiler client to
107      * specify the rules for handling problems (stop on first error or accumulate
108      * them all) and at the same time perform some actions such as opening a dialog
109      * in UI when compiling interactively.
110      * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies
111      *
112      * @param compilerOptions The compiler options to use for the resolution.
113      *
114      * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
115      * Component which will receive and persist all compilation results and is intended
116      * to consume them as they are produced. Typically, in a batch compiler, it is
117      * responsible for writing out the actual .class files to the file system.
118      * @see org.eclipse.jdt.internal.compiler.CompilationResult
119      *
120      * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
121      * Factory used inside the compiler to create problem descriptors. It allows the
122      * compiler client to supply its own representation of compilation problems in
123      * order to avoid object conversions. Note that the factory is not supposed
124      * to accumulate the created problems, the compiler will gather them all and hand
125      * them back as part of the compilation unit result.
126      */

127     public CompilationUnitResolver(
128         INameEnvironment environment,
129         IErrorHandlingPolicy policy,
130         CompilerOptions compilerOptions,
131         ICompilerRequestor requestor,
132         IProblemFactory problemFactory,
133         IProgressMonitor monitor) {
134
135         super(environment, policy, compilerOptions, requestor, problemFactory);
136         this.hasCompilationAborted = false;
137         this.monitor =monitor;
138     }
139
140     /*
141      * Add additional source types
142      */

143     public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
144         // Need to reparse the entire source of the compilation unit so as to get source positions
145
// (case of processing a source that was not known by beginToCompile (e.g. when asking to createBinding))
146
SourceTypeElementInfo sourceType = (SourceTypeElementInfo) sourceTypes[0];
147         accept((org.eclipse.jdt.internal.compiler.env.ICompilationUnit) sourceType.getHandle().getCompilationUnit(), accessRestriction);
148     }
149
150     /**
151      * Add the initial set of compilation units into the loop
152      * -> build compilation unit declarations, their bindings and record their results.
153      */

154     protected void beginToCompile(org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits, String JavaDoc[] bindingKeys) {
155         int sourceLength = sourceUnits.length;
156         int keyLength = bindingKeys.length;
157         int maxUnits = sourceLength + keyLength;
158         this.totalUnits = 0;
159         this.unitsToProcess = new CompilationUnitDeclaration[maxUnits];
160         int index = 0;
161
162         // walks the source units
163
this.requestedSources = new HashtableOfObject();
164         for (int i = 0; i < sourceLength; i++) {
165             org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = sourceUnits[i];
166             CompilationUnitDeclaration parsedUnit;
167             CompilationResult unitResult =
168                 new CompilationResult(sourceUnit, index++, maxUnits, this.options.maxProblemsPerUnit);
169             try {
170                 if (options.verbose) {
171                     this.out.println(
172                         Messages.bind(Messages.compilation_request,
173                         new String JavaDoc[] {
174                             String.valueOf(index++ + 1),
175                             String.valueOf(maxUnits),
176                             new String JavaDoc(sourceUnit.getFileName())
177                         }));
178                 }
179                 // diet parsing for large collection of units
180
if (this.totalUnits < this.parseThreshold) {
181                     parsedUnit = this.parser.parse(sourceUnit, unitResult);
182                 } else {
183                     parsedUnit = this.parser.dietParse(sourceUnit, unitResult);
184                 }
185                 // initial type binding creation
186
this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
187                 addCompilationUnit(sourceUnit, parsedUnit);
188                 this.requestedSources.put(unitResult.getFileName(), sourceUnit);
189                 worked(1);
190             } finally {
191                 sourceUnits[i] = null; // no longer hold onto the unit
192
}
193         }
194
195         // walk the binding keys
196
this.requestedKeys = new HashtableOfObject();
197         for (int i = 0; i < keyLength; i++) {
198             BindingKeyResolver resolver = new BindingKeyResolver(bindingKeys[i], this, this.lookupEnvironment);
199             resolver.parse(true/*pause after fully qualified name*/);
200             // If it doesn't have a type name, then it is either an array type, package or base type, which will definitely not have a compilation unit.
201
// Skipping it will speed up performance because the call will open jars. (theodora)
202
CompilationUnitDeclaration parsedUnit = resolver.hasTypeName() ? resolver.getCompilationUnitDeclaration() : null;
203             if (parsedUnit != null) {
204                 char[] fileName = parsedUnit.compilationResult.getFileName();
205                 Object JavaDoc existing = this.requestedKeys.get(fileName);
206                 if (existing == null)
207                     this.requestedKeys.put(fileName, resolver);
208                 else if (existing instanceof ArrayList JavaDoc)
209                     ((ArrayList JavaDoc) existing).add(resolver);
210                 else {
211                     ArrayList JavaDoc list = new ArrayList JavaDoc();
212                     list.add(existing);
213                     list.add(resolver);
214                     this.requestedKeys.put(fileName, list);
215                 }
216
217             } else {
218                 char[] key = resolver.hasTypeName()
219                     ? resolver.getKey().toCharArray() // binary binding
220
: CharOperation.concatWith(resolver.compoundName(), '.'); // package binding or base type binding
221
this.requestedKeys.put(key, resolver);
222             }
223             worked(1);
224         }
225
226         // binding resolution
227
lookupEnvironment.completeTypeBindings();
228     }
229
230     IBinding createBinding(String JavaDoc key) {
231         if (this.bindingTables == null)
232             throw new RuntimeException JavaDoc("Cannot be called outside ASTParser#createASTs(...)"); //$NON-NLS-1$
233
BindingKeyResolver keyResolver = new BindingKeyResolver(key, this, this.lookupEnvironment);
234         Binding compilerBinding = keyResolver.getCompilerBinding();
235         if (compilerBinding == null) return null;
236         DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null/*no owner*/, this.bindingTables, false);
237         return resolver.getBinding(compilerBinding);
238     }
239
240     public static CompilationUnit convert(CompilationUnitDeclaration compilationUnitDeclaration, char[] source, int apiLevel, Map JavaDoc options, boolean needToResolveBindings, WorkingCopyOwner owner, DefaultBindingResolver.BindingTables bindingTables, int flags, IProgressMonitor monitor) {
241         BindingResolver resolver = null;
242         AST ast = AST.newAST(apiLevel);
243         ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
244         CompilationUnit compilationUnit = null;
245         ASTConverter converter = new ASTConverter(options, needToResolveBindings, monitor);
246         if (needToResolveBindings) {
247             resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, owner, bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
248             ast.setFlag(flags | AST.RESOLVED_BINDINGS);
249         } else {
250             resolver = new BindingResolver();
251             ast.setFlag(flags);
252         }
253         ast.setBindingResolver(resolver);
254         converter.setAST(ast);
255         compilationUnit = converter.convert(compilationUnitDeclaration, source);
256         compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions());
257         ast.setDefaultNodeFlag(0);
258         ast.setOriginalModificationCount(ast.modificationCount());
259         return compilationUnit;
260     }
261
262     protected static CompilerOptions getCompilerOptions(Map JavaDoc options, boolean statementsRecovery) {
263         CompilerOptions compilerOptions = new CompilerOptions(options);
264         compilerOptions.performMethodsFullRecovery = statementsRecovery;
265         compilerOptions.performStatementsRecovery = statementsRecovery;
266         compilerOptions.parseLiteralExpressionsAsConstants = false;
267         compilerOptions.storeAnnotations = true /*store annotations in the bindings*/;
268         return compilerOptions;
269     }
270     /*
271      * Low-level API performing the actual compilation
272      */

273     protected static IErrorHandlingPolicy getHandlingPolicy() {
274
275         // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
276
return new IErrorHandlingPolicy() {
277             public boolean stopOnFirstError() {
278                 return false;
279             }
280             public boolean proceedOnErrors() {
281                 return false; // stop if there are some errors
282
}
283         };
284     }
285
286     /*
287      * Answer the component to which will be handed back compilation results from the compiler
288      */

289     protected static ICompilerRequestor getRequestor() {
290         return new ICompilerRequestor() {
291             public void acceptResult(CompilationResult compilationResult) {
292                 // do nothing
293
}
294         };
295     }
296
297     /* (non-Javadoc)
298      * @see org.eclipse.jdt.internal.compiler.Compiler#initializeParser()
299      */

300     public void initializeParser() {
301         this.parser = new CommentRecorderParser(this.problemReporter, false);
302     }
303     public void process(CompilationUnitDeclaration unit, int i) {
304         // don't resolve a second time the same unit (this would create the same binding twice)
305
char[] fileName = unit.compilationResult.getFileName();
306         if (!this.requestedKeys.containsKey(fileName) && !this.requestedSources.containsKey(fileName))
307             super.process(unit, i);
308     }
309     /*
310      * Compiler crash recovery in case of unexpected runtime exceptions
311      */

312     protected void handleInternalException(
313             Throwable JavaDoc internalException,
314             CompilationUnitDeclaration unit,
315             CompilationResult result) {
316         super.handleInternalException(internalException, unit, result);
317         if (unit != null) {
318             removeUnresolvedBindings(unit);
319         }
320     }
321
322     /*
323      * Compiler recovery in case of internal AbortCompilation event
324      */

325     protected void handleInternalException(
326             AbortCompilation abortException,
327             CompilationUnitDeclaration unit) {
328         super.handleInternalException(abortException, unit);
329         if (unit != null) {
330             removeUnresolvedBindings(unit);
331         }
332         this.hasCompilationAborted = true;
333     }
334
335     public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map JavaDoc options, int flags, IProgressMonitor monitor) {
336         try {
337             CompilerOptions compilerOptions = new CompilerOptions(options);
338             Parser parser = new CommentRecorderParser(
339                 new ProblemReporter(
340                         DefaultErrorHandlingPolicies.proceedWithAllProblems(),
341                         compilerOptions,
342                         new DefaultProblemFactory()),
343                 false);
344             int length = compilationUnits.length;
345             if (monitor != null) monitor.beginTask("", length); //$NON-NLS-1$
346
for (int i = 0; i < length; i++) {
347                 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) compilationUnits[i];
348                 CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
349                 CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
350
351                 if (compilationUnitDeclaration.ignoreMethodBodies) {
352                     compilationUnitDeclaration.ignoreFurtherInvestigation = true;
353                     // if initial diet parse did not work, no need to dig into method bodies.
354
continue;
355                 }
356
357                 //fill the methods bodies in order for the code to be generated
358
//real parse of the method....
359
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
360                 if (types != null) {
361                     for (int j = types.length; --j >= 0;)
362                         types[j].parseMethod(parser, compilationUnitDeclaration);
363                 }
364
365                 // convert AST
366
CompilationUnit node = convert(compilationUnitDeclaration, parser.scanner.getSource(), apiLevel, options, false/*don't resolve binding*/, null/*no owner needed*/, null/*no binding table needed*/, flags /* flags */, monitor);
367                 node.setTypeRoot(compilationUnits[i]);
368
369                 // accept AST
370
astRequestor.acceptAST(compilationUnits[i], node);
371
372                 if (monitor != null) monitor.worked(1);
373             }
374         } finally {
375             if (monitor != null) monitor.done();
376         }
377     }
378
379     public static CompilationUnitDeclaration parse(
380             org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
381             NodeSearcher nodeSearcher,
382             Map JavaDoc settings,
383             int flags) {
384         if (sourceUnit == null) {
385             throw new IllegalStateException JavaDoc();
386         }
387         CompilerOptions compilerOptions = new CompilerOptions(settings);
388         boolean statementsRecovery = (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0;
389         compilerOptions.performMethodsFullRecovery = statementsRecovery;
390         compilerOptions.performStatementsRecovery = statementsRecovery;
391         Parser parser = new CommentRecorderParser(
392             new ProblemReporter(
393                     DefaultErrorHandlingPolicies.proceedWithAllProblems(),
394                     compilerOptions,
395                     new DefaultProblemFactory()),
396             false);
397         CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
398         CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
399
400         if (compilationUnitDeclaration.ignoreMethodBodies) {
401             compilationUnitDeclaration.ignoreFurtherInvestigation = true;
402             // if initial diet parse did not work, no need to dig into method bodies.
403
return null;
404         }
405
406         if (nodeSearcher != null) {
407             char[] source = parser.scanner.getSource();
408             int searchPosition = nodeSearcher.position;
409             if (searchPosition < 0 || searchPosition > source.length) {
410                 // the position is out of range. There is no need to search for a node.
411
return compilationUnitDeclaration;
412             }
413
414             compilationUnitDeclaration.traverse(nodeSearcher, compilationUnitDeclaration.scope);
415
416             org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
417             if (node == null) {
418                 return compilationUnitDeclaration;
419             }
420
421             org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
422
423             if (node instanceof AbstractMethodDeclaration) {
424                 ((AbstractMethodDeclaration)node).parseStatements(parser, compilationUnitDeclaration);
425             } else if (enclosingTypeDeclaration != null) {
426                 if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) {
427                     ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(parser, enclosingTypeDeclaration, compilationUnitDeclaration);
428                 } else {
429                     ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethod(parser, compilationUnitDeclaration);
430                 }
431             }
432         } else {
433             //fill the methods bodies in order for the code to be generated
434
//real parse of the method....
435
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
436             if (types != null) {
437                 for (int i = types.length; --i >= 0;)
438                     types[i].parseMethod(parser, compilationUnitDeclaration);
439             }
440         }
441         return compilationUnitDeclaration;
442     }
443
444     public static void resolve(
445         ICompilationUnit[] compilationUnits,
446         String JavaDoc[] bindingKeys,
447         ASTRequestor requestor,
448         int apiLevel,
449         Map JavaDoc options,
450         IJavaProject javaProject,
451         WorkingCopyOwner owner,
452         int flags,
453         IProgressMonitor monitor) {
454
455         CancelableNameEnvironment environment = null;
456         CancelableProblemFactory problemFactory = null;
457         try {
458             if (monitor != null) {
459                 int amountOfWork = (compilationUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve
460
monitor.beginTask("", amountOfWork); //$NON-NLS-1$
461
}
462             environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, monitor);
463             problemFactory = new CancelableProblemFactory(monitor);
464             CompilationUnitResolver resolver =
465                 new CompilationUnitResolver(
466                     environment,
467                     getHandlingPolicy(),
468                     getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0),
469                     getRequestor(),
470                     problemFactory,
471                     monitor);
472
473             resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner, flags);
474             if (NameLookup.VERBOSE) {
475                 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
476
System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
477
}
478         } catch (JavaModelException e) {
479             // project doesn't exist -> simple parse without resolving
480
parse(compilationUnits, requestor, apiLevel, options, flags, monitor);
481         } finally {
482             if (monitor != null) monitor.done();
483             if (environment != null) {
484                 environment.monitor = null; // don't hold a reference to this external object
485
}
486             if (problemFactory != null) {
487                 problemFactory.monitor = null; // don't hold a reference to this external object
488
}
489         }
490     }
491     public static CompilationUnitDeclaration resolve(
492             org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
493             IJavaProject javaProject,
494             NodeSearcher nodeSearcher,
495             Map JavaDoc options,
496             WorkingCopyOwner owner,
497             int flags,
498             IProgressMonitor monitor) throws JavaModelException {
499
500         CompilationUnitDeclaration unit = null;
501         CancelableNameEnvironment environment = null;
502         CancelableProblemFactory problemFactory = null;
503         CompilationUnitResolver resolver = null;
504         try {
505             environment = new CancelableNameEnvironment(((JavaProject)javaProject), owner, monitor);
506             problemFactory = new CancelableProblemFactory(monitor);
507             resolver =
508                 new CompilationUnitResolver(
509                     environment,
510                     getHandlingPolicy(),
511                     getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0),
512                     getRequestor(),
513                     problemFactory,
514                     monitor);
515
516             unit =
517                 resolver.resolve(
518                     null, // no existing compilation unit declaration
519
sourceUnit,
520                     nodeSearcher,
521                     true, // method verification
522
true, // analyze code
523
true); // generate code
524
if (resolver.hasCompilationAborted) {
525                 // the bindings could not be resolved due to missing types in name environment
526
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541
527
CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags);
528                 final int problemCount = unit.compilationResult.problemCount;
529                 if (problemCount != 0) {
530                     unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount];
531                     System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount);
532                     unitDeclaration.compilationResult.problemCount = problemCount;
533                 }
534                 return unitDeclaration;
535             }
536             if (NameLookup.VERBOSE) {
537                 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
538
System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
539
}
540             return unit;
541         } finally {
542             if (environment != null) {
543                 environment.monitor = null; // don't hold a reference to this external object
544
}
545             if (problemFactory != null) {
546                 problemFactory.monitor = null; // don't hold a reference to this external object
547
}
548             // first unit cleanup is done by caller, but cleanup all enqueued requested units (not processed)
549
// if (resolver != null) {
550
// for (int i = 1; i < resolver.totalUnits; i++) { // could be more requested units
551
// CompilationUnitDeclaration parsedUnit = resolver.unitsToProcess[i];
552
// if (parsedUnit.scope != null)
553
// parsedUnit.scope.faultInTypes(); // force resolution of signatures, so clients can query DOM AST
554
// parsedUnit.cleanUp();
555
// }
556
// }
557
}
558     }
559     public static IBinding[] resolve(
560         final IJavaElement[] elements,
561         int apiLevel,
562         Map JavaDoc compilerOptions,
563         IJavaProject javaProject,
564         WorkingCopyOwner owner,
565         int flags,
566         IProgressMonitor monitor) {
567
568         final int length = elements.length;
569         final HashMap JavaDoc sourceElementPositions = new HashMap JavaDoc(); // a map from ICompilationUnit to int[] (positions in elements)
570
int cuNumber = 0;
571         final HashtableOfObjectToInt binaryElementPositions = new HashtableOfObjectToInt(); // a map from String (binding key) to int (position in elements)
572
for (int i = 0; i < length; i++) {
573             IJavaElement element = elements[i];
574             if (!(element instanceof SourceRefElement))
575                 throw new IllegalStateException JavaDoc(element + " is not part of a compilation unit or class file"); //$NON-NLS-1$
576
Object JavaDoc cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
577             if (cu != null) {
578                 // source member
579
IntArrayList intList = (IntArrayList) sourceElementPositions.get(cu);
580                 if (intList == null) {
581                     sourceElementPositions.put(cu, intList = new IntArrayList());
582                     cuNumber++;
583                 }
584                 intList.add(i);
585             } else {
586                 // binary member
587
try {
588                     String JavaDoc key = ((BinaryMember) element).getKey(true/*open to get resolved info*/);
589                     binaryElementPositions.put(key, i);
590                 } catch (JavaModelException e) {
591                     throw new IllegalArgumentException JavaDoc(element + " does not exist"); //$NON-NLS-1$
592
}
593             }
594         }
595         ICompilationUnit[] cus = new ICompilationUnit[cuNumber];
596         sourceElementPositions.keySet().toArray(cus);
597
598         int bindingKeyNumber = binaryElementPositions.size();
599         String JavaDoc[] bindingKeys = new String JavaDoc[bindingKeyNumber];
600         binaryElementPositions.keysToArray(bindingKeys);
601
602         class Requestor extends ASTRequestor {
603             IBinding[] bindings = new IBinding[length];
604             public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
605                 // TODO (jerome) optimize to visit the AST only once
606
IntArrayList intList = (IntArrayList) sourceElementPositions.get(source);
607                 for (int i = 0; i < intList.length; i++) {
608                     final int index = intList.list[i];
609                     SourceRefElement element = (SourceRefElement) elements[index];
610                     DOMFinder finder = new DOMFinder(ast, element, true/*resolve binding*/);
611                     try {
612                         finder.search();
613                     } catch (JavaModelException e) {
614                         throw new IllegalArgumentException JavaDoc(element + " does not exist"); //$NON-NLS-1$
615
}
616                     this.bindings[index] = finder.foundBinding;
617                 }
618             }
619             public void acceptBinding(String JavaDoc bindingKey, IBinding binding) {
620                 int index = binaryElementPositions.get(bindingKey);
621                 this.bindings[index] = binding;
622             }
623         }
624         Requestor requestor = new Requestor();
625         resolve(cus, bindingKeys, requestor, apiLevel, compilerOptions, javaProject, owner, flags, monitor);
626         return requestor.bindings;
627     }
628     /*
629      * When unit result is about to be accepted, removed back pointers
630      * to unresolved bindings
631      */

632     public void removeUnresolvedBindings(CompilationUnitDeclaration compilationUnitDeclaration) {
633         final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
634         if (types != null) {
635             for (int i = 0, max = types.length; i < max; i++) {
636                 removeUnresolvedBindings(types[i]);
637             }
638         }
639     }
640     private void removeUnresolvedBindings(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration type) {
641         final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] memberTypes = type.memberTypes;
642         if (memberTypes != null) {
643             for (int i = 0, max = memberTypes.length; i < max; i++){
644                 removeUnresolvedBindings(memberTypes[i]);
645             }
646         }
647         if (type.binding != null && (type.binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
648             type.binding = null;
649         }
650
651         final org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = type.fields;
652         if (fields != null) {
653             for (int i = 0, max = fields.length; i < max; i++){
654                 if (fields[i].binding != null && (fields[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
655                     fields[i].binding = null;
656                 }
657             }
658         }
659
660         final AbstractMethodDeclaration[] methods = type.methods;
661         if (methods != null) {
662             for (int i = 0, max = methods.length; i < max; i++){
663                 if (methods[i].binding != null && (methods[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
664                     methods[i].binding = null;
665                 }
666             }
667         }
668     }
669
670     private void resolve(ICompilationUnit[] compilationUnits, String JavaDoc[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map JavaDoc compilerOptions, WorkingCopyOwner owner, int flags) {
671
672         // temporararily connect ourselves to the ASTResolver - must disconnect when done
673
astRequestor.compilationUnitResolver = this;
674         this.bindingTables = new DefaultBindingResolver.BindingTables();
675         CompilationUnitDeclaration unit = null;
676         int i = 0;
677         try {
678             int length = compilationUnits.length;
679             org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length];
680             System.arraycopy(compilationUnits, 0, sourceUnits, 0, length);
681             beginToCompile(sourceUnits, bindingKeys);
682             // process all units (some more could be injected in the loop by the lookup environment)
683
for (; i < this.totalUnits; i++) {
684                 if (this.requestedSources.size() == 0 && this.requestedKeys.size() == 0) {
685                     // no need to keep resolving if no more ASTs and no more binding keys are needed
686
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935
687
// cleanup remaining units
688
for (; i < this.totalUnits; i++) {
689                         this.unitsToProcess[i].cleanUp();
690                         this.unitsToProcess[i] = null;
691                     }
692                     break;
693                 }
694                 unit = this.unitsToProcess[i];
695                 try {
696                     super.process(unit, i); // this.process(...) is optimized to not process already known units
697

698                     // requested AST
699
char[] fileName = unit.compilationResult.getFileName();
700                     ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName);
701                     if (source != null) {
702                         // convert AST
703
CompilationResult compilationResult = unit.compilationResult;
704                         org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit;
705                         char[] contents = sourceUnit.getContents();
706                         AST ast = AST.newAST(apiLevel);
707                         ast.setFlag(flags | AST.RESOLVED_BINDINGS);
708                         ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
709                         ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor);
710                         BindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
711                         ast.setBindingResolver(resolver);
712                         converter.setAST(ast);
713                         CompilationUnit compilationUnit = converter.convert(unit, contents);
714                         compilationUnit.setTypeRoot(source);
715                         compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions());
716                         ast.setDefaultNodeFlag(0);
717                         ast.setOriginalModificationCount(ast.modificationCount());
718
719                         // pass it to requestor
720
astRequestor.acceptAST(source, compilationUnit);
721
722                         worked(1);
723                     }
724
725                     // requested binding
726
Object JavaDoc key = this.requestedKeys.get(fileName);
727                     if (key instanceof BindingKeyResolver) {
728                         reportBinding(key, astRequestor, owner, unit);
729                         worked(1);
730                     } else if (key instanceof ArrayList JavaDoc) {
731                         Iterator JavaDoc iterator = ((ArrayList JavaDoc) key).iterator();
732                         while (iterator.hasNext()) {
733                             reportBinding(iterator.next(), astRequestor, owner, unit);
734                             worked(1);
735                         }
736                     }
737
738                     // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested
739
this.requestedSources.removeKey(fileName);
740                     this.requestedKeys.removeKey(fileName);
741                 } finally {
742                     // cleanup compilation unit result
743
unit.cleanUp();
744                 }
745                 this.unitsToProcess[i] = null; // release reference to processed unit declaration
746
this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
747             }
748
749             // remaining binding keys
750
DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
751             Object JavaDoc[] keys = this.requestedKeys.valueTable;
752             for (int j = 0, keysLength = keys.length; j < keysLength; j++) {
753                 BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j];
754                 if (keyResolver == null) continue;
755                 Binding compilerBinding = keyResolver.getCompilerBinding();
756                 IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding);
757                 // pass it to requestor
758
astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding);
759                 worked(1);
760             }
761         } catch (OperationCanceledException e) {
762             throw e;
763         } catch (AbortCompilation e) {
764             this.handleInternalException(e, unit);
765         } catch (Error JavaDoc e) {
766             this.handleInternalException(e, unit, null);
767             throw e; // rethrow
768
} catch (RuntimeException JavaDoc e) {
769             this.handleInternalException(e, unit, null);
770             throw e; // rethrow
771
} finally {
772             // disconnect ourselves from ast requestor
773
astRequestor.compilationUnitResolver = null;
774         }
775     }
776
777     private void reportBinding(Object JavaDoc key, ASTRequestor astRequestor, WorkingCopyOwner owner, CompilationUnitDeclaration unit) {
778         BindingKeyResolver keyResolver = (BindingKeyResolver) key;
779         Binding compilerBinding = keyResolver.getCompilerBinding();
780         if (compilerBinding != null) {
781             DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, false);
782             IBinding binding = resolver.getBinding(compilerBinding);
783             if (binding != null)
784                 astRequestor.acceptBinding(keyResolver.getKey(), binding);
785         }
786     }
787
788     private CompilationUnitDeclaration resolve(
789             CompilationUnitDeclaration unit,
790             org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
791             NodeSearcher nodeSearcher,
792             boolean verifyMethods,
793             boolean analyzeCode,
794             boolean generateCode) {
795
796         try {
797
798             if (unit == null) {
799                 // build and record parsed units
800
this.parseThreshold = 0; // will request a full parse
801
beginToCompile(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] { sourceUnit });
802                 // process all units (some more could be injected in the loop by the lookup environment)
803
unit = this.unitsToProcess[0];
804             } else {
805                 // initial type binding creation
806
this.lookupEnvironment.buildTypeBindings(unit, null /*no access restriction*/);
807
808                 // binding resolution
809
this.lookupEnvironment.completeTypeBindings();
810             }
811
812             if (nodeSearcher == null) {
813                 this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed
814
} else {
815                 int searchPosition = nodeSearcher.position;
816                 char[] source = sourceUnit.getContents();
817                 int length = source.length;
818                 if (searchPosition >= 0 && searchPosition <= length) {
819                     unit.traverse(nodeSearcher, unit.scope);
820
821                     org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
822
823                     this.parser.scanner.setSource(source, unit.compilationResult);
824
825                     if (node != null) {
826                         org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
827                         if (node instanceof AbstractMethodDeclaration) {
828                             ((AbstractMethodDeclaration)node).parseStatements(this.parser, unit);
829                         } else if (enclosingTypeDeclaration != null) {
830                             if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) {
831                                 ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit);
832                             } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
833                                 ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethod(this.parser, unit);
834                             }
835                         }
836                     }
837                 }
838             }
839
840             if (unit.scope != null) {
841                 // fault in fields & methods
842
unit.scope.faultInTypes();
843                 if (unit.scope != null && verifyMethods) {
844                     // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117
845
// verify inherited methods
846
unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier());
847                 }
848                 // type checking
849
unit.resolve();
850
851                 // flow analysis
852
if (analyzeCode) unit.analyseCode();
853
854                 // code generation
855
if (generateCode) unit.generateCode();
856             }
857             if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration
858
this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
859             return unit;
860         } catch (AbortCompilation e) {
861             this.handleInternalException(e, unit);
862             return unit == null ? this.unitsToProcess[0] : unit;
863         } catch (Error JavaDoc e) {
864             this.handleInternalException(e, unit, null);
865             throw e; // rethrow
866
} catch (RuntimeException JavaDoc e) {
867             this.handleInternalException(e, unit, null);
868             throw e; // rethrow
869
} finally {
870             // No reset is performed there anymore since,
871
// within the CodeAssist (or related tools),
872
// the compiler may be called *after* a call
873
// to this resolve(...) method. And such a call
874
// needs to have a compiler with a non-empty
875
// environment.
876
// this.reset();
877
}
878     }
879     /*
880      * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
881      */

882     public CompilationUnitDeclaration resolve(
883             org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
884             boolean verifyMethods,
885             boolean analyzeCode,
886             boolean generateCode) {
887
888         return resolve(
889             null, /* no existing compilation unit declaration*/
890             sourceUnit,
891             null/*no node searcher*/,
892             verifyMethods,
893             analyzeCode,
894             generateCode);
895     }
896
897     /*
898      * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
899      */

900     public CompilationUnitDeclaration resolve(
901             CompilationUnitDeclaration unit,
902             org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
903             boolean verifyMethods,
904             boolean analyzeCode,
905             boolean generateCode) {
906
907         return resolve(
908             unit,
909             sourceUnit,
910             null/*no node searcher*/,
911             verifyMethods,
912             analyzeCode,
913             generateCode);
914     }
915
916     private void worked(int work) {
917         if (this.monitor != null) {
918             if (this.monitor.isCanceled())
919                 throw new OperationCanceledException();
920             this.monitor.worked(work);
921         }
922     }
923 }
924
Popular Tags