1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.core.dom;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.OperationCanceledException;
20 import net.sourceforge.phpdt.core.ICompilationUnit;
21 import net.sourceforge.phpdt.core.IJavaElement;
22 import net.sourceforge.phpdt.core.IJavaProject;
23 import net.sourceforge.phpdt.core.JavaModelException;
24 import net.sourceforge.phpdt.core.WorkingCopyOwner;
25 import org.eclipse.jdt.core.compiler.CategorizedProblem;
26 import net.sourceforge.phpdt.core.compiler.CharOperation;
27 import net.sourceforge.phpdt.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 net.sourceforge.phpdt.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 net.sourceforge.phpdt.internal.compiler.lookup.AnnotationBinding;
40 import net.sourceforge.phpdt.internal.compiler.lookup.Binding;
41 import net.sourceforge.phpdt.internal.compiler.lookup.ExtraCompilerModifiers;
42 import net.sourceforge.phpdt.internal.compiler.lookup.PackageBinding;
43 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
44 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
45 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
46 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
47 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
48 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
49 import org.eclipse.jdt.internal.compiler.util.Messages;
50 import org.eclipse.jdt.internal.core.BinaryMember;
51 import org.eclipse.jdt.internal.core.CancelableNameEnvironment;
52 import org.eclipse.jdt.internal.core.CancelableProblemFactory;
53 import net.sourceforge.phpdt.internal.core.JavaProject;
54 import org.eclipse.jdt.internal.core.NameLookup;
55 import org.eclipse.jdt.internal.core.SourceRefElement;
56 import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
57 import org.eclipse.jdt.internal.core.util.BindingKeyResolver;
58 import net.sourceforge.phpdt.internal.core.util.CommentRecorderParser;
59 import org.eclipse.jdt.internal.core.util.DOMFinder;
61 class CompilationUnitResolver extends Compiler {
64 static class IntArrayList {
65 public int[] list = new int[5];
66 public int length = 0;
67 public void add(int i) {
68 if (this.list.length == this.length) {
69 System.arraycopy(this.list, 0, this.list = new int[this.length*2], 0, this.length);
71 this.list[this.length++] = i;
76 * The sources that were requested.
77 * Map from file name (char[]) to ICompilationUnit.
79 HashtableOfObject requestedSources;
82 * The binding keys that were requested.
83 * Map from file name (char[]) to BindingKey (or ArrayList if multiple keys in the same file).
85 HashtableOfObject requestedKeys;
87 DefaultBindingResolver.BindingTables bindingTables;
89 boolean hasCompilationAborted;
91 private IProgressMonitor monitor;
94 * Answer a new CompilationUnitVisitor using the given name environment and compiler options.
95 * The environment and options will be in effect for the lifetime of the compiler.
96 * When the compiler is run, compilation results are sent to the given requestor.
98 * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment
99 * Environment used by the compiler in order to resolve type and package
100 * names. The name environment implements the actual connection of the compiler
101 * to the outside world (for example, in batch mode the name environment is performing
102 * pure file accesses, reuse previous build state or connection to repositories).
103 * Note: the name environment is responsible for implementing the actual classpath
106 * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy
107 * Configurable part for problem handling, allowing the compiler client to
108 * specify the rules for handling problems (stop on first error or accumulate
109 * them all) and at the same time perform some actions such as opening a dialog
110 * in UI when compiling interactively.
111 * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies
113 * @param compilerOptions The compiler options to use for the resolution.
115 * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
116 * Component which will receive and persist all compilation results and is intended
117 * to consume them as they are produced. Typically, in a batch compiler, it is
118 * responsible for writing out the actual .class files to the file system.
119 * @see org.eclipse.jdt.internal.compiler.CompilationResult
121 * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
122 * Factory used inside the compiler to create problem descriptors. It allows the
123 * compiler client to supply its own representation of compilation problems in
124 * order to avoid object conversions. Note that the factory is not supposed
125 * to accumulate the created problems, the compiler will gather them all and hand
126 * them back as part of the compilation unit result.
128 public CompilationUnitResolver(
129 INameEnvironment environment,
130 IErrorHandlingPolicy policy,
131 CompilerOptions compilerOptions,
132 ICompilerRequestor requestor,
133 IProblemFactory problemFactory,
134 IProgressMonitor monitor) {
136 super(environment, policy, compilerOptions, requestor, problemFactory);
137 this.hasCompilationAborted = false;
138 this.monitor =monitor;
142 * Add additional source types
144 public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
145 // Need to reparse the entire source of the compilation unit so as to get source positions
146 // (case of processing a source that was not known by beginToCompile (e.g. when asking to createBinding))
147 SourceTypeElementInfo sourceType = (SourceTypeElementInfo) sourceTypes[0];
148 accept((org.eclipse.jdt.internal.compiler.env.ICompilationUnit) sourceType.getHandle().getCompilationUnit(), accessRestriction);
152 * Add the initial set of compilation units into the loop
153 * -> build compilation unit declarations, their bindings and record their results.
155 protected void beginToCompile(net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit[] sourceUnits, String[] bindingKeys) {
156 int sourceLength = sourceUnits.length;
157 int keyLength = bindingKeys.length;
158 int maxUnits = sourceLength + keyLength;
160 this.unitsToProcess = new CompilationUnitDeclaration[maxUnits];
163 // walks the source units
164 this.requestedSources = new HashtableOfObject();
165 for (int i = 0; i < sourceLength; i++) {
166 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = sourceUnits[i];
167 CompilationUnitDeclaration parsedUnit;
168 CompilationResult unitResult =
169 new CompilationResult(sourceUnit, index++, maxUnits, this.options.maxProblemsPerUnit);
171 if (options.verbose) {
173 Messages.bind(Messages.compilation_request,
175 String.valueOf(index++ + 1),
176 String.valueOf(maxUnits),
177 new String(sourceUnit.getFileName())
180 // diet parsing for large collection of units
181 if (this.totalUnits < this.parseThreshold) {
182 parsedUnit = this.parser.parse(sourceUnit, unitResult);
184 parsedUnit = this.parser.dietParse(sourceUnit, unitResult);
186 // initial type binding creation
187 this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
188 addCompilationUnit(sourceUnit, parsedUnit);
189 this.requestedSources.put(unitResult.getFileName(), sourceUnit);
192 sourceUnits[i] = null; // no longer hold onto the unit
196 // walk the binding keys
197 this.requestedKeys = new HashtableOfObject();
198 for (int i = 0; i < keyLength; i++) {
199 BindingKeyResolver resolver = new BindingKeyResolver(bindingKeys[i], this, this.lookupEnvironment);
200 resolver.parse(true/*pause after fully qualified name*/);
201 // 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.
202 // Skipping it will speed up performance because the call will open jars. (theodora)
203 CompilationUnitDeclaration parsedUnit = resolver.hasTypeName() ? resolver.getCompilationUnitDeclaration() : null;
204 if (parsedUnit != null) {
205 char[] fileName = parsedUnit.compilationResult.getFileName();
206 Object existing = this.requestedKeys.get(fileName);
207 if (existing == null)
208 this.requestedKeys.put(fileName, resolver);
209 else if (existing instanceof ArrayList)
210 ((ArrayList) existing).add(resolver);
212 ArrayList list = new ArrayList();
215 this.requestedKeys.put(fileName, list);
219 char[] key = resolver.hasTypeName()
220 ? resolver.getKey().toCharArray() // binary binding
221 : CharOperation.concatWith(resolver.compoundName(), '.'); // package binding or base type binding
222 this.requestedKeys.put(key, resolver);
227 // binding resolution
228 lookupEnvironment.completeTypeBindings();
231 IBinding createBinding(String key) {
232 if (this.bindingTables == null)
233 throw new RuntimeException("Cannot be called outside ASTParser#createASTs(...)"); //$NON-NLS-1$
234 BindingKeyResolver keyResolver = new BindingKeyResolver(key, this, this.lookupEnvironment);
235 Binding compilerBinding = keyResolver.getCompilerBinding();
236 if (compilerBinding == null) return null;
237 DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null/*no owner*/, this.bindingTables, false);
238 return resolver.getBinding(compilerBinding);
241 public static CompilationUnit convert(CompilationUnitDeclaration compilationUnitDeclaration, char[] source, int apiLevel, Map options, boolean needToResolveBindings, WorkingCopyOwner owner, DefaultBindingResolver.BindingTables bindingTables, int flags, IProgressMonitor monitor) {
242 BindingResolver resolver = null;
243 AST ast = AST.newAST(apiLevel);
244 ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
245 CompilationUnit compilationUnit = null;
246 ASTConverter converter = new ASTConverter(options, needToResolveBindings, monitor);
247 if (needToResolveBindings) {
248 resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, owner, bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
249 ast.setFlag(flags | AST.RESOLVED_BINDINGS);
251 resolver = new BindingResolver();
254 ast.setBindingResolver(resolver);
255 converter.setAST(ast);
256 compilationUnit = converter.convert(compilationUnitDeclaration, source);
257 compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions());
258 ast.setDefaultNodeFlag(0);
259 ast.setOriginalModificationCount(ast.modificationCount());
260 return compilationUnit;
263 protected static CompilerOptions getCompilerOptions(Map options, boolean statementsRecovery) {
264 CompilerOptions compilerOptions = new CompilerOptions(options);
265 compilerOptions.performMethodsFullRecovery = statementsRecovery;
266 compilerOptions.performStatementsRecovery = statementsRecovery;
267 compilerOptions.parseLiteralExpressionsAsConstants = false;
268 compilerOptions.storeAnnotations = true /*store annotations in the bindings*/;
269 return compilerOptions;
272 * Low-level API performing the actual compilation
274 protected static IErrorHandlingPolicy getHandlingPolicy() {
276 // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
277 return new IErrorHandlingPolicy() {
278 public boolean stopOnFirstError() {
281 public boolean proceedOnErrors() {
282 return false; // stop if there are some errors
288 * Answer the component to which will be handed back compilation results from the compiler
290 protected static ICompilerRequestor getRequestor() {
291 return new ICompilerRequestor() {
292 public void acceptResult(CompilationResult compilationResult) {
299 * @see org.eclipse.jdt.internal.compiler.Compiler#initializeParser()
301 public void initializeParser() {
302 this.parser = new CommentRecorderParser(this.problemReporter, false);
304 public void process(CompilationUnitDeclaration unit, int i) {
305 // don't resolve a second time the same unit (this would create the same binding twice)
306 char[] fileName = unit.compilationResult.getFileName();
307 if (!this.requestedKeys.containsKey(fileName) && !this.requestedSources.containsKey(fileName))
308 super.process(unit, i);
311 * Compiler crash recovery in case of unexpected runtime exceptions
313 protected void handleInternalException(
314 Throwable internalException,
315 CompilationUnitDeclaration unit,
316 CompilationResult result) {
317 super.handleInternalException(internalException, unit, result);
319 removeUnresolvedBindings(unit);
324 * Compiler recovery in case of internal AbortCompilation event
326 protected void handleInternalException(
327 AbortCompilation abortException,
328 CompilationUnitDeclaration unit) {
329 super.handleInternalException(abortException, unit);
331 removeUnresolvedBindings(unit);
333 this.hasCompilationAborted = true;
336 public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) {
338 CompilerOptions compilerOptions = new CompilerOptions(options);
339 Parser parser = new CommentRecorderParser(
341 DefaultErrorHandlingPolicies.proceedWithAllProblems(),
343 new DefaultProblemFactory()),
345 int unitLength = compilationUnits.length;
346 if (monitor != null) monitor.beginTask("", unitLength); //$NON-NLS-1$
347 for (int i = 0; i < unitLength; i++) {
348 net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit sourceUnit = (net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit) compilationUnits[i];
349 CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
350 CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
352 if (compilationUnitDeclaration.ignoreMethodBodies) {
353 compilationUnitDeclaration.ignoreFurtherInvestigation = true;
354 // if initial diet parse did not work, no need to dig into method bodies.
358 //fill the methods bodies in order for the code to be generated
359 //real parse of the method....
360 net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
362 for (int j = 0, typeLength = types.length; j < typeLength; j++)
363 types[j].parseMethods(parser, compilationUnitDeclaration);
367 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);
368 node.setTypeRoot(compilationUnits[i]);
371 astRequestor.acceptAST(compilationUnits[i], node);
373 if (monitor != null) monitor.worked(1);
376 if (monitor != null) monitor.done();
380 public static CompilationUnitDeclaration parse(
381 net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit sourceUnit,
382 NodeSearcher nodeSearcher,
385 if (sourceUnit == null) {
386 throw new IllegalStateException();
388 CompilerOptions compilerOptions = new CompilerOptions(settings);
389 boolean statementsRecovery = (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0;
390 compilerOptions.performMethodsFullRecovery = statementsRecovery;
391 compilerOptions.performStatementsRecovery = statementsRecovery;
392 Parser parser = new CommentRecorderParser(
394 DefaultErrorHandlingPolicies.proceedWithAllProblems(),
396 new DefaultProblemFactory()),
398 CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
399 CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
401 if (compilationUnitDeclaration.ignoreMethodBodies) {
402 compilationUnitDeclaration.ignoreFurtherInvestigation = true;
403 // if initial diet parse did not work, no need to dig into method bodies.
407 if (nodeSearcher != null) {
408 char[] source = parser.scanner.getSource();
409 int searchPosition = nodeSearcher.position;
410 if (searchPosition < 0 || searchPosition > source.length) {
411 // the position is out of range. There is no need to search for a node.
412 return compilationUnitDeclaration;
415 compilationUnitDeclaration.traverse(nodeSearcher, compilationUnitDeclaration.scope);
417 net.sourceforge.phpdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
419 return compilationUnitDeclaration;
422 net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
424 if (node instanceof AbstractMethodDeclaration) {
425 ((AbstractMethodDeclaration)node).parseStatements(parser, compilationUnitDeclaration);
426 } else if (enclosingTypeDeclaration != null) {
427 if (node instanceof net.sourceforge.phpdt.internal.compiler.ast.Initializer) {
428 ((net.sourceforge.phpdt.internal.compiler.ast.Initializer) node).parseStatements(parser, enclosingTypeDeclaration, compilationUnitDeclaration);
429 } else if (node instanceof net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration) {
430 ((net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(parser, compilationUnitDeclaration);
434 //fill the methods bodies in order for the code to be generated
435 //real parse of the method....
436 net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
438 for (int i = 0, length = types.length; i < length; i++)
439 types[i].parseMethods(parser, compilationUnitDeclaration);
442 return compilationUnitDeclaration;
445 public static void resolve(
446 ICompilationUnit[] compilationUnits,
447 String[] bindingKeys,
448 ASTRequestor requestor,
451 IJavaProject javaProject,
452 WorkingCopyOwner owner,
454 IProgressMonitor monitor) {
456 CancelableNameEnvironment environment = null;
457 CancelableProblemFactory problemFactory = null;
459 if (monitor != null) {
460 int amountOfWork = (compilationUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve
461 monitor.beginTask("", amountOfWork); //$NON-NLS-1$
463 environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, monitor);
464 problemFactory = new CancelableProblemFactory(monitor);
465 CompilationUnitResolver resolver =
466 new CompilationUnitResolver(
469 getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0),
474 resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner, flags);
475 if (NameLookup.VERBOSE) {
476 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
477 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
479 } catch (JavaModelException e) {
480 // project doesn't exist -> simple parse without resolving
481 parse(compilationUnits, requestor, apiLevel, options, flags, monitor);
483 if (monitor != null) monitor.done();
484 if (environment != null) {
485 environment.monitor = null; // don't hold a reference to this external object
487 if (problemFactory != null) {
488 problemFactory.monitor = null; // don't hold a reference to this external object
492 public static CompilationUnitDeclaration resolve(
493 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
494 IJavaProject javaProject,
495 NodeSearcher nodeSearcher,
497 WorkingCopyOwner owner,
499 IProgressMonitor monitor) throws JavaModelException {
501 CompilationUnitDeclaration unit = null;
502 CancelableNameEnvironment environment = null;
503 CancelableProblemFactory problemFactory = null;
504 CompilationUnitResolver resolver = null;
506 environment = new CancelableNameEnvironment(((JavaProject)javaProject), owner, monitor);
507 problemFactory = new CancelableProblemFactory(monitor);
509 new CompilationUnitResolver(
512 getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0),
519 null, // no existing compilation unit declaration
522 true, // method verification
523 true, // analyze code
524 true); // generate code
525 if (resolver.hasCompilationAborted) {
526 // the bindings could not be resolved due to missing types in name environment
527 // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541
528 CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags);
529 final int problemCount = unit.compilationResult.problemCount;
530 if (problemCount != 0) {
531 unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount];
532 System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount);
533 unitDeclaration.compilationResult.problemCount = problemCount;
535 return unitDeclaration;
537 if (NameLookup.VERBOSE) {
538 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
539 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
543 if (environment != null) {
544 environment.monitor = null; // don't hold a reference to this external object
546 if (problemFactory != null) {
547 problemFactory.monitor = null; // don't hold a reference to this external object
549 // first unit cleanup is done by caller, but cleanup all enqueued requested units (not processed)
550 // if (resolver != null) {
551 // for (int i = 1; i < resolver.totalUnits; i++) { // could be more requested units
552 // CompilationUnitDeclaration parsedUnit = resolver.unitsToProcess[i];
553 // if (parsedUnit.scope != null)
554 // parsedUnit.scope.faultInTypes(); // force resolution of signatures, so clients can query DOM AST
555 // parsedUnit.cleanUp();
560 public static IBinding[] resolve(
561 final IJavaElement[] elements,
564 IJavaProject javaProject,
565 WorkingCopyOwner owner,
567 IProgressMonitor monitor) {
569 final int length = elements.length;
570 final HashMap sourceElementPositions = new HashMap(); // a map from ICompilationUnit to int[] (positions in elements)
572 final HashtableOfObjectToInt binaryElementPositions = new HashtableOfObjectToInt(); // a map from String (binding key) to int (position in elements)
573 for (int i = 0; i < length; i++) {
574 IJavaElement element = elements[i];
575 if (!(element instanceof SourceRefElement))
576 throw new IllegalStateException(element + " is not part of a compilation unit or class file"); //$NON-NLS-1$
577 Object cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
580 IntArrayList intList = (IntArrayList) sourceElementPositions.get(cu);
581 if (intList == null) {
582 sourceElementPositions.put(cu, intList = new IntArrayList());
589 String key = ((BinaryMember) element).getKey(true/*open to get resolved info*/);
590 binaryElementPositions.put(key, i);
591 } catch (JavaModelException e) {
592 throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$
596 ICompilationUnit[] cus = new ICompilationUnit[cuNumber];
597 sourceElementPositions.keySet().toArray(cus);
599 int bindingKeyNumber = binaryElementPositions.size();
600 String[] bindingKeys = new String[bindingKeyNumber];
601 binaryElementPositions.keysToArray(bindingKeys);
603 class Requestor extends ASTRequestor {
604 IBinding[] bindings = new IBinding[length];
605 public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
606 // TODO (jerome) optimize to visit the AST only once
607 IntArrayList intList = (IntArrayList) sourceElementPositions.get(source);
608 for (int i = 0; i < intList.length; i++) {
609 final int index = intList.list[i];
610 SourceRefElement element = (SourceRefElement) elements[index];
611 DOMFinder finder = new DOMFinder(ast, element, true/*resolve binding*/);
614 } catch (JavaModelException e) {
615 throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$
617 this.bindings[index] = finder.foundBinding;
620 public void acceptBinding(String bindingKey, IBinding binding) {
621 int index = binaryElementPositions.get(bindingKey);
622 this.bindings[index] = binding;
625 Requestor requestor = new Requestor();
626 resolve(cus, bindingKeys, requestor, apiLevel, compilerOptions, javaProject, owner, flags, monitor);
627 return requestor.bindings;
630 * When unit result is about to be accepted, removed back pointers
631 * to unresolved bindings
633 public void removeUnresolvedBindings(CompilationUnitDeclaration compilationUnitDeclaration) {
634 final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
636 for (int i = 0, max = types.length; i < max; i++) {
637 removeUnresolvedBindings(types[i]);
641 private void removeUnresolvedBindings(net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration type) {
642 final net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration[] memberTypes = type.memberTypes;
643 if (memberTypes != null) {
644 for (int i = 0, max = memberTypes.length; i < max; i++){
645 removeUnresolvedBindings(memberTypes[i]);
648 if (type.binding != null && (type.binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
652 final org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = type.fields;
653 if (fields != null) {
654 for (int i = 0, max = fields.length; i < max; i++){
655 if (fields[i].binding != null && (fields[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
656 fields[i].binding = null;
661 final AbstractMethodDeclaration[] methods = type.methods;
662 if (methods != null) {
663 for (int i = 0, max = methods.length; i < max; i++){
664 if (methods[i].binding != null && (methods[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
665 methods[i].binding = null;
671 private void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map compilerOptions, WorkingCopyOwner owner, int flags) {
673 // temporarily connect ourselves to the ASTResolver - must disconnect when done
674 astRequestor.compilationUnitResolver = this;
675 this.bindingTables = new DefaultBindingResolver.BindingTables();
676 CompilationUnitDeclaration unit = null;
679 int length = compilationUnits.length;
680 org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length];
681 System.arraycopy(compilationUnits, 0, sourceUnits, 0, length);
682 beginToCompile(sourceUnits, bindingKeys);
683 // process all units (some more could be injected in the loop by the lookup environment)
684 for (; i < this.totalUnits; i++) {
685 if (this.requestedSources.size() == 0 && this.requestedKeys.size() == 0) {
686 // no need to keep resolving if no more ASTs and no more binding keys are needed
687 // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935
688 // cleanup remaining units
689 for (; i < this.totalUnits; i++) {
690 this.unitsToProcess[i].cleanUp();
691 this.unitsToProcess[i] = null;
695 unit = this.unitsToProcess[i];
697 super.process(unit, i); // this.process(...) is optimized to not process already known units
700 char[] fileName = unit.compilationResult.getFileName();
701 ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName);
702 if (source != null) {
704 CompilationResult compilationResult = unit.compilationResult;
705 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit;
706 char[] contents = sourceUnit.getContents();
707 AST ast = AST.newAST(apiLevel);
708 ast.setFlag(flags | AST.RESOLVED_BINDINGS);
709 ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
710 ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor);
711 BindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
712 ast.setBindingResolver(resolver);
713 converter.setAST(ast);
714 CompilationUnit compilationUnit = converter.convert(unit, contents);
715 compilationUnit.setTypeRoot(source);
716 compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions());
717 ast.setDefaultNodeFlag(0);
718 ast.setOriginalModificationCount(ast.modificationCount());
720 // pass it to requestor
721 astRequestor.acceptAST(source, compilationUnit);
727 Object key = this.requestedKeys.get(fileName);
728 if (key instanceof BindingKeyResolver) {
729 reportBinding(key, astRequestor, owner, unit);
731 } else if (key instanceof ArrayList) {
732 Iterator iterator = ((ArrayList) key).iterator();
733 while (iterator.hasNext()) {
734 reportBinding(iterator.next(), astRequestor, owner, unit);
739 // 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
740 this.requestedSources.removeKey(fileName);
741 this.requestedKeys.removeKey(fileName);
743 // cleanup compilation unit result
746 this.unitsToProcess[i] = null; // release reference to processed unit declaration
747 this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
750 // remaining binding keys
751 DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
752 Object[] keys = this.requestedKeys.valueTable;
753 for (int j = 0, keysLength = keys.length; j < keysLength; j++) {
754 BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j];
755 if (keyResolver == null) continue;
756 Binding compilerBinding = keyResolver.getCompilerBinding();
757 IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding);
758 // pass it to requestor
759 astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding);
762 } catch (OperationCanceledException e) {
764 } catch (AbortCompilation e) {
765 this.handleInternalException(e, unit);
767 this.handleInternalException(e, unit, null);
769 } catch (RuntimeException e) {
770 this.handleInternalException(e, unit, null);
773 // disconnect ourselves from ast requestor
774 astRequestor.compilationUnitResolver = null;
778 private void reportBinding(Object key, ASTRequestor astRequestor, WorkingCopyOwner owner, CompilationUnitDeclaration unit) {
779 BindingKeyResolver keyResolver = (BindingKeyResolver) key;
780 Binding compilerBinding = keyResolver.getCompilerBinding();
781 if (compilerBinding != null) {
782 DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, false);
783 AnnotationBinding annotationBinding = keyResolver.getAnnotationBinding();
785 if (annotationBinding != null) {
786 binding = resolver.getAnnotationInstance(annotationBinding);
788 binding = resolver.getBinding(compilerBinding);
791 astRequestor.acceptBinding(keyResolver.getKey(), binding);
795 private CompilationUnitDeclaration resolve(
796 CompilationUnitDeclaration unit,
797 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
798 NodeSearcher nodeSearcher,
799 boolean verifyMethods,
801 boolean generateCode) {
806 // build and record parsed units
807 this.parseThreshold = 0; // will request a full parse
808 beginToCompile(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] { sourceUnit });
809 // process all units (some more could be injected in the loop by the lookup environment)
810 unit = this.unitsToProcess[0];
812 // initial type binding creation
813 this.lookupEnvironment.buildTypeBindings(unit, null /*no access restriction*/);
815 // binding resolution
816 this.lookupEnvironment.completeTypeBindings();
819 if (nodeSearcher == null) {
820 this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed
822 int searchPosition = nodeSearcher.position;
823 char[] source = sourceUnit.getContents();
824 int length = source.length;
825 if (searchPosition >= 0 && searchPosition <= length) {
826 unit.traverse(nodeSearcher, unit.scope);
828 org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
831 // save existing values to restore them at the end of the parsing process
832 // see bug 47079 for more details
833 int[] oldLineEnds = this.parser.scanner.lineEnds;
834 int oldLinePtr = this.parser.scanner.linePtr;
836 this.parser.scanner.setSource(source, unit.compilationResult);
838 org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
839 if (node instanceof AbstractMethodDeclaration) {
840 ((AbstractMethodDeclaration)node).parseStatements(this.parser, unit);
841 } else if (enclosingTypeDeclaration != null) {
842 if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) {
843 ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit);
844 } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
845 ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(this.parser, unit);
848 // this is done to prevent any side effects on the compilation unit result
849 // line separator positions array.
850 this.parser.scanner.lineEnds = oldLineEnds;
851 this.parser.scanner.linePtr = oldLinePtr;
856 if (unit.scope != null) {
857 // fault in fields & methods
858 unit.scope.faultInTypes();
859 if (unit.scope != null && verifyMethods) {
860 // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117
861 // verify inherited methods
862 unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier());
868 if (analyzeCode) unit.analyseCode();
871 if (generateCode) unit.generateCode();
873 // finalize problems (suppressWarnings)
874 unit.finalizeProblems();
876 if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration
877 this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
879 } catch (AbortCompilation e) {
880 this.handleInternalException(e, unit);
881 return unit == null ? this.unitsToProcess[0] : unit;
883 this.handleInternalException(e, unit, null);
885 } catch (RuntimeException e) {
886 this.handleInternalException(e, unit, null);
889 // No reset is performed there anymore since,
890 // within the CodeAssist (or related tools),
891 // the compiler may be called *after* a call
892 // to this resolve(...) method. And such a call
893 // needs to have a compiler with a non-empty
899 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
901 public CompilationUnitDeclaration resolve(
902 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
903 boolean verifyMethods,
905 boolean generateCode) {
908 null, /* no existing compilation unit declaration*/
910 null/*no node searcher*/,
917 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
919 public CompilationUnitDeclaration resolve(
920 CompilationUnitDeclaration unit,
921 org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
922 boolean verifyMethods,
924 boolean generateCode) {
929 null/*no node searcher*/,
935 private void worked(int work) {
936 if (this.monitor != null) {
937 if (this.monitor.isCanceled())
938 throw new OperationCanceledException();
939 this.monitor.worked(work);