fa5768257677dcfd142af4cd8fa7b755e00a0535
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / CompilationUnitResolver.java
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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.core.dom;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.Map;
17
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;
60
61 class CompilationUnitResolver extends Compiler {
62
63         /* A list of int */
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);
70                         }
71                                 this.list[this.length++] = i;
72                         }
73                 }
74
75         /*
76          * The sources that were requested.
77          * Map from file name (char[]) to ICompilationUnit.
78          */
79         HashtableOfObject requestedSources;
80
81         /*
82          * The binding keys that were requested.
83          * Map from file name (char[]) to BindingKey (or ArrayList if multiple keys in the same file).
84          */
85         HashtableOfObject requestedKeys;
86
87         DefaultBindingResolver.BindingTables bindingTables;
88
89         boolean hasCompilationAborted;
90
91         private IProgressMonitor monitor;
92
93         /**
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.
97          *
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
104          *            rules.
105          *
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
112          *
113          *      @param compilerOptions The compiler options to use for the resolution.
114          *
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
120          *
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.
127          */
128         public CompilationUnitResolver(
129                 INameEnvironment environment,
130                 IErrorHandlingPolicy policy,
131                 CompilerOptions compilerOptions,
132                 ICompilerRequestor requestor,
133                 IProblemFactory problemFactory,
134                 IProgressMonitor monitor) {
135
136                 super(environment, policy, compilerOptions, requestor, problemFactory);
137                 this.hasCompilationAborted = false;
138                 this.monitor =monitor;
139         }
140
141         /*
142          * Add additional source types
143          */
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);
149         }
150
151         /**
152          * Add the initial set of compilation units into the loop
153          *  ->  build compilation unit declarations, their bindings and record their results.
154          */
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;
159                 this.totalUnits = 0;
160                 this.unitsToProcess = new CompilationUnitDeclaration[maxUnits];
161                 int index = 0;
162
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);
170                         try {
171                                 if (options.verbose) {
172                                         this.out.println(
173                                                 Messages.bind(Messages.compilation_request,
174                                                 new String[] {
175                                                         String.valueOf(index++ + 1),
176                                                         String.valueOf(maxUnits),
177                                                         new String(sourceUnit.getFileName())
178                                                 }));
179                                 }
180                                 // diet parsing for large collection of units
181                                 if (this.totalUnits < this.parseThreshold) {
182                                         parsedUnit = this.parser.parse(sourceUnit, unitResult);
183                                 } else {
184                                         parsedUnit = this.parser.dietParse(sourceUnit, unitResult);
185                                 }
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);
190                                 worked(1);
191                         } finally {
192                                 sourceUnits[i] = null; // no longer hold onto the unit
193                         }
194                 }
195
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);
211                                 else {
212                                         ArrayList list = new ArrayList();
213                                         list.add(existing);
214                                         list.add(resolver);
215                                         this.requestedKeys.put(fileName, list);
216                                 }
217
218                         } else {
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);
223                         }
224                         worked(1);
225                 }
226
227                 // binding resolution
228                 lookupEnvironment.completeTypeBindings();
229         }
230
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);
239         }
240
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);
250                 } else {
251                         resolver = new BindingResolver();
252                         ast.setFlag(flags);
253                 }
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;
261         }
262
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;
270         }
271         /*
272          *  Low-level API performing the actual compilation
273          */
274         protected static IErrorHandlingPolicy getHandlingPolicy() {
275
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() {
279                                 return false;
280                         }
281                         public boolean proceedOnErrors() {
282                                 return false; // stop if there are some errors
283                         }
284                 };
285         }
286
287         /*
288          * Answer the component to which will be handed back compilation results from the compiler
289          */
290         protected static ICompilerRequestor getRequestor() {
291                 return new ICompilerRequestor() {
292                         public void acceptResult(CompilationResult compilationResult) {
293                                 // do nothing
294                         }
295                 };
296         }
297
298         /* (non-Javadoc)
299          * @see org.eclipse.jdt.internal.compiler.Compiler#initializeParser()
300          */
301         public void initializeParser() {
302                 this.parser = new CommentRecorderParser(this.problemReporter, false);
303         }
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);
309         }
310         /*
311          * Compiler crash recovery in case of unexpected runtime exceptions
312          */
313         protected void handleInternalException(
314                         Throwable internalException,
315                         CompilationUnitDeclaration unit,
316                         CompilationResult result) {
317                 super.handleInternalException(internalException, unit, result);
318                 if (unit != null) {
319                         removeUnresolvedBindings(unit);
320                 }
321         }
322
323         /*
324          * Compiler recovery in case of internal AbortCompilation event
325          */
326         protected void handleInternalException(
327                         AbortCompilation abortException,
328                         CompilationUnitDeclaration unit) {
329                 super.handleInternalException(abortException, unit);
330                 if (unit != null) {
331                         removeUnresolvedBindings(unit);
332                 }
333                 this.hasCompilationAborted = true;
334         }
335
336         public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) {
337                 try {
338                         CompilerOptions compilerOptions = new CompilerOptions(options);
339                         Parser parser = new CommentRecorderParser(
340                                 new ProblemReporter(
341                                                 DefaultErrorHandlingPolicies.proceedWithAllProblems(),
342                                                 compilerOptions,
343                                                 new DefaultProblemFactory()),
344                                 false);
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);
351
352                                 if (compilationUnitDeclaration.ignoreMethodBodies) {
353                                         compilationUnitDeclaration.ignoreFurtherInvestigation = true;
354                                         // if initial diet parse did not work, no need to dig into method bodies.
355                                         continue;
356                                 }
357
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;
361                                 if (types != null) {
362                                         for (int j = 0, typeLength = types.length; j < typeLength; j++)
363                                                 types[j].parseMethods(parser, compilationUnitDeclaration);
364                                 }
365
366                                 // convert AST
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]);
369
370                                 // accept AST
371                                 astRequestor.acceptAST(compilationUnits[i], node);
372
373                                 if (monitor != null) monitor.worked(1);
374                         }
375                 } finally {
376                         if (monitor != null) monitor.done();
377                 }
378         }
379
380         public static CompilationUnitDeclaration parse(
381                         net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit sourceUnit,
382                         NodeSearcher nodeSearcher,
383                         Map settings,
384                         int flags) {
385                 if (sourceUnit == null) {
386                         throw new IllegalStateException();
387                 }
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(
393                         new ProblemReporter(
394                                         DefaultErrorHandlingPolicies.proceedWithAllProblems(),
395                                         compilerOptions,
396                                         new DefaultProblemFactory()),
397                         false);
398                 CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
399                 CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
400
401                 if (compilationUnitDeclaration.ignoreMethodBodies) {
402                         compilationUnitDeclaration.ignoreFurtherInvestigation = true;
403                         // if initial diet parse did not work, no need to dig into method bodies.
404                         return null;
405                 }
406
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;
413                         }
414
415                         compilationUnitDeclaration.traverse(nodeSearcher, compilationUnitDeclaration.scope);
416
417                         net.sourceforge.phpdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
418                         if (node == null) {
419                                 return compilationUnitDeclaration;
420                         }
421
422                         net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
423
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);
431                                 }
432                         }
433                 } else {
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;
437                         if (types != null) {
438                                 for (int i = 0, length = types.length; i < length; i++)
439                                         types[i].parseMethods(parser, compilationUnitDeclaration);
440                         }
441                 }
442                 return compilationUnitDeclaration;
443         }
444
445         public static void resolve(
446                 ICompilationUnit[] compilationUnits,
447                 String[] bindingKeys,
448                 ASTRequestor requestor,
449                 int apiLevel,
450                 Map options,
451                 IJavaProject javaProject,
452                 WorkingCopyOwner owner,
453                 int flags,
454                 IProgressMonitor monitor) {
455
456                 CancelableNameEnvironment environment = null;
457                 CancelableProblemFactory problemFactory = null;
458                 try {
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$
462                         }
463                         environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, monitor);
464                         problemFactory = new CancelableProblemFactory(monitor);
465                         CompilationUnitResolver resolver =
466                                 new CompilationUnitResolver(
467                                         environment,
468                                         getHandlingPolicy(),
469                                         getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0),
470                                         getRequestor(),
471                                         problemFactory,
472                                         monitor);
473
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$
478                         }
479                 } catch (JavaModelException e) {
480                         // project doesn't exist -> simple parse without resolving
481                         parse(compilationUnits, requestor, apiLevel, options, flags, monitor);
482                 } finally {
483                         if (monitor != null) monitor.done();
484                         if (environment != null) {
485                                 environment.monitor = null; // don't hold a reference to this external object
486                         }
487                         if (problemFactory != null) {
488                                 problemFactory.monitor = null; // don't hold a reference to this external object
489                         }
490                 }
491         }
492         public static CompilationUnitDeclaration resolve(
493                         org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
494                         IJavaProject javaProject,
495                         NodeSearcher nodeSearcher,
496                         Map options,
497                         WorkingCopyOwner owner,
498                         int flags,
499                         IProgressMonitor monitor) throws JavaModelException {
500
501                 CompilationUnitDeclaration unit = null;
502                 CancelableNameEnvironment environment = null;
503                 CancelableProblemFactory problemFactory = null;
504                 CompilationUnitResolver resolver = null;
505                 try {
506                         environment = new CancelableNameEnvironment(((JavaProject)javaProject), owner, monitor);
507                         problemFactory = new CancelableProblemFactory(monitor);
508                         resolver =
509                                 new CompilationUnitResolver(
510                                         environment,
511                                         getHandlingPolicy(),
512                                         getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0),
513                                         getRequestor(),
514                                         problemFactory,
515                                         monitor);
516
517                         unit =
518                                 resolver.resolve(
519                                         null, // no existing compilation unit declaration
520                                         sourceUnit,
521                                         nodeSearcher,
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;
534                                 }
535                                 return unitDeclaration;
536                         }
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$
540                         }
541                         return unit;
542                 } finally {
543                         if (environment != null) {
544                                 environment.monitor = null; // don't hold a reference to this external object
545                         }
546                         if (problemFactory != null) {
547                                 problemFactory.monitor = null; // don't hold a reference to this external object
548                         }
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();
556 //                              }
557 //                      }
558                 }
559         }
560         public static IBinding[] resolve(
561                 final IJavaElement[] elements,
562                 int apiLevel,
563                 Map compilerOptions,
564                 IJavaProject javaProject,
565                 WorkingCopyOwner owner,
566                 int flags,
567                 IProgressMonitor monitor) {
568
569                 final int length = elements.length;
570                 final HashMap sourceElementPositions = new HashMap(); // a map from ICompilationUnit to int[] (positions in elements)
571                 int cuNumber = 0;
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);
578                         if (cu != null) {
579                                 // source member
580                                 IntArrayList intList = (IntArrayList) sourceElementPositions.get(cu);
581                                 if (intList == null) {
582                                         sourceElementPositions.put(cu, intList = new IntArrayList());
583                                         cuNumber++;
584                                 }
585                                 intList.add(i);
586                         } else {
587                                 // binary member
588                                 try {
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$
593                                 }
594                         }
595                 }
596                 ICompilationUnit[] cus = new ICompilationUnit[cuNumber];
597                 sourceElementPositions.keySet().toArray(cus);
598
599                 int bindingKeyNumber = binaryElementPositions.size();
600                 String[] bindingKeys = new String[bindingKeyNumber];
601                 binaryElementPositions.keysToArray(bindingKeys);
602
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*/);
612                                         try {
613                                                 finder.search();
614                                         } catch (JavaModelException e) {
615                                                 throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$
616                                         }
617                                         this.bindings[index] = finder.foundBinding;
618                                 }
619                         }
620                         public void acceptBinding(String bindingKey, IBinding binding) {
621                                 int index = binaryElementPositions.get(bindingKey);
622                                 this.bindings[index] = binding;
623                         }
624                 }
625                 Requestor requestor = new Requestor();
626                 resolve(cus, bindingKeys, requestor, apiLevel, compilerOptions, javaProject, owner, flags, monitor);
627                 return requestor.bindings;
628         }
629         /*
630          * When unit result is about to be accepted, removed back pointers
631          * to unresolved bindings
632          */
633         public void removeUnresolvedBindings(CompilationUnitDeclaration compilationUnitDeclaration) {
634                 final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
635                 if (types != null) {
636                         for (int i = 0, max = types.length; i < max; i++) {
637                                 removeUnresolvedBindings(types[i]);
638                         }
639                 }
640         }
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]);
646                         }
647                 }
648                 if (type.binding != null && (type.binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) {
649                         type.binding = null;
650                 }
651
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;
657                                 }
658                         }
659                 }
660
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;
666                                 }
667                         }
668                 }
669         }
670
671         private void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map compilerOptions, WorkingCopyOwner owner, int flags) {
672
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;
677                 int i = 0;
678                 try {
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;
692                                         }
693                                         break;
694                                 }
695                                 unit = this.unitsToProcess[i];
696                                 try {
697                                         super.process(unit, i); // this.process(...) is optimized to not process already known units
698
699                                         // requested AST
700                                         char[] fileName = unit.compilationResult.getFileName();
701                                         ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName);
702                                         if (source != null) {
703                                                 // convert AST
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());
719
720                                                 // pass it to requestor
721                                                 astRequestor.acceptAST(source, compilationUnit);
722
723                                                 worked(1);
724                                         }
725
726                                         // requested binding
727                                         Object key = this.requestedKeys.get(fileName);
728                                         if (key instanceof BindingKeyResolver) {
729                                                 reportBinding(key, astRequestor, owner, unit);
730                                                 worked(1);
731                                         } else if (key instanceof ArrayList) {
732                                                 Iterator iterator = ((ArrayList) key).iterator();
733                                                 while (iterator.hasNext()) {
734                                                         reportBinding(iterator.next(), astRequestor, owner, unit);
735                                                         worked(1);
736                                                 }
737                                         }
738
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);
742                                 } finally {
743                                         // cleanup compilation unit result
744                                         unit.cleanUp();
745                                 }
746                                 this.unitsToProcess[i] = null; // release reference to processed unit declaration
747                                 this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
748                         }
749
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);
760                                 worked(1);
761                         }
762                 } catch (OperationCanceledException e) {
763                         throw e;
764                 } catch (AbortCompilation e) {
765                         this.handleInternalException(e, unit);
766                 } catch (Error e) {
767                         this.handleInternalException(e, unit, null);
768                         throw e; // rethrow
769                 } catch (RuntimeException e) {
770                         this.handleInternalException(e, unit, null);
771                         throw e; // rethrow
772                 } finally {
773                         // disconnect ourselves from ast requestor
774                         astRequestor.compilationUnitResolver = null;
775                 }
776         }
777
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();
784                         IBinding binding;
785                         if (annotationBinding != null) {
786                                 binding = resolver.getAnnotationInstance(annotationBinding);
787                         } else {
788                                 binding = resolver.getBinding(compilerBinding);
789                         }
790                         if (binding != null)
791                                 astRequestor.acceptBinding(keyResolver.getKey(), binding);
792                 }
793         }
794
795         private CompilationUnitDeclaration resolve(
796                         CompilationUnitDeclaration unit,
797                         org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
798                         NodeSearcher nodeSearcher,
799                         boolean verifyMethods,
800                         boolean analyzeCode,
801                         boolean generateCode) {
802
803                 try {
804
805                         if (unit == null) {
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];
811                         } else {
812                                 // initial type binding creation
813                                 this.lookupEnvironment.buildTypeBindings(unit, null /*no access restriction*/);
814
815                                 // binding resolution
816                                 this.lookupEnvironment.completeTypeBindings();
817                         }
818
819                         if (nodeSearcher == null) {
820                                 this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed
821                         } else {
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);
827
828                                         org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
829
830                                         if (node != null) {
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;
835
836                                                 this.parser.scanner.setSource(source, unit.compilationResult);
837
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);
846                                                         }
847                                                 }
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;
852                                         }
853                                 }
854                         }
855
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());
863                                 }
864                                 // type checking
865                                 unit.resolve();
866
867                                 // flow analysis
868                                 if (analyzeCode) unit.analyseCode();
869
870                                 // code generation
871                                 if (generateCode) unit.generateCode();
872                                 
873                                 // finalize problems (suppressWarnings)
874                                 unit.finalizeProblems();
875                         }
876                         if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration
877                         this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
878                         return unit;
879                 } catch (AbortCompilation e) {
880                         this.handleInternalException(e, unit);
881                         return unit == null ? this.unitsToProcess[0] : unit;
882                 } catch (Error e) {
883                         this.handleInternalException(e, unit, null);
884                         throw e; // rethrow
885                 } catch (RuntimeException e) {
886                         this.handleInternalException(e, unit, null);
887                         throw e; // rethrow
888                 } finally {
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
894                         // environment.
895                         // this.reset();
896                 }
897         }
898         /*
899          * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
900          */
901         public CompilationUnitDeclaration resolve(
902                         org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
903                         boolean verifyMethods,
904                         boolean analyzeCode,
905                         boolean generateCode) {
906
907                 return resolve(
908                         null, /* no existing compilation unit declaration*/
909                         sourceUnit,
910                         null/*no node searcher*/,
911                         verifyMethods,
912                         analyzeCode,
913                         generateCode);
914         }
915
916         /*
917          * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
918          */
919         public CompilationUnitDeclaration resolve(
920                         CompilationUnitDeclaration unit,
921                         org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
922                         boolean verifyMethods,
923                         boolean analyzeCode,
924                         boolean generateCode) {
925
926                 return resolve(
927                         unit,
928                         sourceUnit,
929                         null/*no node searcher*/,
930                         verifyMethods,
931                         analyzeCode,
932                         generateCode);
933         }
934
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);
940                 }
941         }
942 }