Copyright (c) 2000, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Stephan Herrmann - Contribution for bug 363858 - [dom] early throwing of AbortCompilation causes NPE in CompilationUnitResolver Bug 466279 - [hovering] IAE on hover when annotation-based null analysis is enabled
/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for * bug 363858 - [dom] early throwing of AbortCompilation causes NPE in CompilationUnitResolver * Bug 466279 - [hovering] IAE on hover when annotation-based null analysis is enabled *******************************************************************************/
package org.eclipse.jdt.core.dom; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.WorkingCopyOwner; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.ICompilerRequestor; import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; import org.eclipse.jdt.internal.compiler.IProblemFactory; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.jdt.internal.compiler.env.ISourceType; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; import org.eclipse.jdt.internal.compiler.util.Messages; import org.eclipse.jdt.internal.compiler.util.Util; import org.eclipse.jdt.internal.core.BinaryMember; import org.eclipse.jdt.internal.core.BinaryModule; import org.eclipse.jdt.internal.core.CancelableNameEnvironment; import org.eclipse.jdt.internal.core.CancelableProblemFactory; import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress; import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.LocalVariable; import org.eclipse.jdt.internal.core.NameLookup; import org.eclipse.jdt.internal.core.SourceRefElement; import org.eclipse.jdt.internal.core.SourceTypeElementInfo; import org.eclipse.jdt.internal.core.util.BindingKeyResolver; import org.eclipse.jdt.internal.core.util.CommentRecorderParser; import org.eclipse.jdt.internal.core.util.DOMFinder; @SuppressWarnings({ "rawtypes", "unchecked" }) class CompilationUnitResolver extends Compiler { public static final int RESOLVE_BINDING = 0x1; public static final int PARTIAL = 0x2; public static final int STATEMENT_RECOVERY = 0x4; public static final int IGNORE_METHOD_BODIES = 0x8; public static final int BINDING_RECOVERY = 0x10; public static final int INCLUDE_RUNNING_VM_BOOTCLASSPATH = 0x20; /* A list of int */ static class IntArrayList { public int[] list = new int[5]; public int length = 0; public void add(int i) { if (this.list.length == this.length) { System.arraycopy(this.list, 0, this.list = new int[this.length*2], 0, this.length); } this.list[this.length++] = i; } } /* * The sources that were requested. * Map from file name (char[]) to org.eclipse.jdt.internal.compiler.env.ICompilationUnit. */ HashtableOfObject requestedSources; /* * The binding keys that were requested. * Map from file name (char[]) to BindingKey (or ArrayList if multiple keys in the same file). */ HashtableOfObject requestedKeys; DefaultBindingResolver.BindingTables bindingTables; boolean hasCompilationAborted; CategorizedProblem abortProblem; private IProgressMonitor monitor;
Set to true if the receiver was initialized using a java project name environment
/** * Set to <code>true</code> if the receiver was initialized using a java project name environment */
boolean fromJavaProject;
Answer a new CompilationUnitVisitor using the given name environment and compiler options. The environment and options will be in effect for the lifetime of the compiler. When the compiler is run, compilation results are sent to the given requestor. @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment Environment used by the compiler in order to resolve type and package names. The name environment implements the actual connection of the compiler to the outside world (for example, in batch mode the name environment is performing pure file accesses, reuse previous build state or connection to repositories). Note: the name environment is responsible for implementing the actual classpath rules. @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy Configurable part for problem handling, allowing the compiler client to specify the rules for handling problems (stop on first error or accumulate them all) and at the same time perform some actions such as opening a dialog in UI when compiling interactively. @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies
Params:
  • compilerOptions – The compiler options to use for the resolution. @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor Component which will receive and persist all compilation results and is intended to consume them as they are produced. Typically, in a batch compiler, it is responsible for writing out the actual .class files to the file system. @see org.eclipse.jdt.internal.compiler.CompilationResult @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory Factory used inside the compiler to create problem descriptors. It allows the compiler client to supply its own representation of compilation problems in order to avoid object conversions. Note that the factory is not supposed to accumulate the created problems, the compiler will gather them all and hand them back as part of the compilation unit result.
/** * Answer a new CompilationUnitVisitor using the given name environment and compiler options. * The environment and options will be in effect for the lifetime of the compiler. * When the compiler is run, compilation results are sent to the given requestor. * * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment * Environment used by the compiler in order to resolve type and package * names. The name environment implements the actual connection of the compiler * to the outside world (for example, in batch mode the name environment is performing * pure file accesses, reuse previous build state or connection to repositories). * Note: the name environment is responsible for implementing the actual classpath * rules. * * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy * Configurable part for problem handling, allowing the compiler client to * specify the rules for handling problems (stop on first error or accumulate * them all) and at the same time perform some actions such as opening a dialog * in UI when compiling interactively. * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies * * @param compilerOptions The compiler options to use for the resolution. * * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor * Component which will receive and persist all compilation results and is intended * to consume them as they are produced. Typically, in a batch compiler, it is * responsible for writing out the actual .class files to the file system. * @see org.eclipse.jdt.internal.compiler.CompilationResult * * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory * Factory used inside the compiler to create problem descriptors. It allows the * compiler client to supply its own representation of compilation problems in * order to avoid object conversions. Note that the factory is not supposed * to accumulate the created problems, the compiler will gather them all and hand * them back as part of the compilation unit result. */
public CompilationUnitResolver( INameEnvironment environment, IErrorHandlingPolicy policy, CompilerOptions compilerOptions, ICompilerRequestor requestor, IProblemFactory problemFactory, IProgressMonitor monitor, boolean fromJavaProject) { super(environment, policy, compilerOptions, requestor, problemFactory); this.hasCompilationAborted = false; this.monitor =monitor; this.fromJavaProject = fromJavaProject; } /* * Add additional source types */ @Override public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { // Need to reparse the entire source of the compilation unit so as to get source positions // (case of processing a source that was not known by beginToCompile (e.g. when asking to createBinding)) SourceTypeElementInfo sourceType = (SourceTypeElementInfo) sourceTypes[0]; accept((org.eclipse.jdt.internal.compiler.env.ICompilationUnit) sourceType.getHandle().getCompilationUnit(), accessRestriction); } @Override public synchronized void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, AccessRestriction accessRestriction) { super.accept(sourceUnit, accessRestriction); }
Add the initial set of compilation units into the loop -> build compilation unit declarations, their bindings and record their results.
/** * Add the initial set of compilation units into the loop * -> build compilation unit declarations, their bindings and record their results. */
protected void beginToCompile(org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits, String[] bindingKeys) { int sourceLength = sourceUnits.length; int keyLength = bindingKeys.length; int maxUnits = sourceLength + keyLength; this.totalUnits = 0; this.unitsToProcess = new CompilationUnitDeclaration[maxUnits]; int index = 0; // walks the source units this.requestedSources = new HashtableOfObject(); for (int i = 0; i < sourceLength; i++) { org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = sourceUnits[i]; CompilationUnitDeclaration parsedUnit; CompilationResult unitResult = new CompilationResult(sourceUnit, index++, maxUnits, this.options.maxProblemsPerUnit); try { if (this.options.verbose) { this.out.println( Messages.bind(Messages.compilation_request, new String[] { String.valueOf(index++ + 1), String.valueOf(maxUnits), new String(sourceUnit.getFileName()) })); } if (this.parser instanceof CommentRecorderParser) { ((CommentRecorderParser) this.parser).resetComments(); } // diet parsing for large collection of units if (this.totalUnits < this.parseThreshold) { parsedUnit = this.parser.parse(sourceUnit, unitResult); } else { parsedUnit = this.parser.dietParse(sourceUnit, unitResult); } // initial type binding creation this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); addCompilationUnit(sourceUnit, parsedUnit); this.requestedSources.put(unitResult.getFileName(), sourceUnit); worked(1); } finally { sourceUnits[i] = null; // no longer hold onto the unit } } // walk the binding keys this.requestedKeys = new HashtableOfObject(); for (int i = 0; i < keyLength; i++) { BindingKeyResolver resolver = new BindingKeyResolver(bindingKeys[i], this, this.lookupEnvironment); resolver.parse(true/*pause after fully qualified name*/); // 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. // Skipping it will speed up performance because the call will open jars. (theodora) CompilationUnitDeclaration parsedUnit = resolver.hasTypeName() ? resolver.getCompilationUnitDeclaration() : null; if (parsedUnit != null) { char[] fileName = parsedUnit.compilationResult.getFileName(); Object existing = this.requestedKeys.get(fileName); if (existing == null) this.requestedKeys.put(fileName, resolver); else if (existing instanceof ArrayList) ((ArrayList) existing).add(resolver); else { ArrayList list = new ArrayList(); list.add(existing); list.add(resolver); this.requestedKeys.put(fileName, list); } } else { char[] key = resolver.hasTypeName() ? resolver.getKey().toCharArray() // binary binding : resolver.hasModuleName() ? resolver.moduleName() : CharOperation.concatWith(resolver.compoundName(), '.'); // package binding or base type binding this.requestedKeys.put(key, resolver); } worked(1); } // binding resolution this.lookupEnvironment.completeTypeBindings(); } IBinding createBinding(String key) { if (this.bindingTables == null) throw new RuntimeException("Cannot be called outside ASTParser#createASTs(...)"); //$NON-NLS-1$ BindingKeyResolver keyResolver = new BindingKeyResolver(key, this, this.lookupEnvironment); Binding compilerBinding = keyResolver.getCompilerBinding(); if (compilerBinding == null) return null; DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null/*no owner*/, this.bindingTables, false, this.fromJavaProject); return resolver.getBinding(compilerBinding); } public static CompilationUnit convert( CompilationUnitDeclaration compilationUnitDeclaration, char[] source, int apiLevel, Map options, boolean needToResolveBindings, WorkingCopyOwner owner, DefaultBindingResolver.BindingTables bindingTables, int flags, IProgressMonitor monitor, boolean fromJavaProject) { BindingResolver resolver = null; AST ast = AST.newAST(apiLevel, JavaCore.ENABLED.equals(options.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); String sourceModeSetting = (String) options.get(JavaCore.COMPILER_SOURCE); long sourceLevel = CompilerOptions.versionToJdkLevel(sourceModeSetting); if (sourceLevel == 0) { // unknown sourceModeSetting sourceLevel = ClassFileConstants.JDK1_3; } ast.scanner.sourceLevel = sourceLevel; String compliance = (String) options.get(JavaCore.COMPILER_COMPLIANCE); long complianceLevel = CompilerOptions.versionToJdkLevel(compliance); if (complianceLevel == 0) { // unknown sourceModeSetting complianceLevel = sourceLevel; } ast.scanner.complianceLevel = complianceLevel; ast.setDefaultNodeFlag(ASTNode.ORIGINAL); CompilationUnit compilationUnit = null; ASTConverter converter = new ASTConverter(options, needToResolveBindings, monitor); if (needToResolveBindings) { resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, owner, bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, fromJavaProject); ast.setFlag(flags | AST.RESOLVED_BINDINGS); } else { resolver = new BindingResolver(); ast.setFlag(flags); } ast.setBindingResolver(resolver); converter.setAST(ast); compilationUnit = converter.convert(compilationUnitDeclaration, source); compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions()); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return compilationUnit; } protected static CompilerOptions getCompilerOptions(Map options, boolean statementsRecovery) { CompilerOptions compilerOptions = new CompilerOptions(options); compilerOptions.performMethodsFullRecovery = statementsRecovery; compilerOptions.performStatementsRecovery = statementsRecovery; compilerOptions.parseLiteralExpressionsAsConstants = false; compilerOptions.storeAnnotations = true /*store annotations in the bindings*/; compilerOptions.ignoreSourceFolderWarningOption = true; return compilerOptions; } /* * Low-level API performing the actual compilation */ protected static IErrorHandlingPolicy getHandlingPolicy() { // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match) return new IErrorHandlingPolicy() { @Override public boolean stopOnFirstError() { return false; } @Override public boolean proceedOnErrors() { return false; // stop if there are some errors } @Override public boolean ignoreAllErrors() { return false; } }; } /* * Answer the component to which will be handed back compilation results from the compiler */ protected static ICompilerRequestor getRequestor() { return new ICompilerRequestor() { @Override public void acceptResult(CompilationResult compilationResult) { // do nothing } }; } @Override public void initializeParser() { this.parser = new CommentRecorderParser(this.problemReporter, false); } @Override public void process(CompilationUnitDeclaration unit, int i) { // don't resolve a second time the same unit (this would create the same binding twice) char[] fileName = unit.compilationResult.getFileName(); if (this.requestedKeys.get(fileName) == null && this.requestedSources.get(fileName) == null) super.process(unit, i); } /* * Compiler crash recovery in case of unexpected runtime exceptions */ @Override protected void handleInternalException( Throwable internalException, CompilationUnitDeclaration unit, CompilationResult result) { super.handleInternalException(internalException, unit, result); if (unit != null) { removeUnresolvedBindings(unit); } } /* * Compiler recovery in case of internal AbortCompilation event */ @Override protected void handleInternalException( AbortCompilation abortException, CompilationUnitDeclaration unit) { super.handleInternalException(abortException, unit); if (unit != null) { removeUnresolvedBindings(unit); } this.hasCompilationAborted = true; this.abortProblem = abortException.problem; } public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) { CompilerOptions compilerOptions = new CompilerOptions(options); compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; Parser parser = new CommentRecorderParser( new ProblemReporter( DefaultErrorHandlingPolicies.proceedWithAllProblems(), compilerOptions, new DefaultProblemFactory()), false); int unitLength = compilationUnits.length; SubMonitor subMonitor = SubMonitor.convert(monitor); for (int i = 0; i < unitLength; i++) { subMonitor.setWorkRemaining(unitLength - i); org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) compilationUnits[i]; CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); if (compilationUnitDeclaration.ignoreMethodBodies) { compilationUnitDeclaration.ignoreFurtherInvestigation = true; // if initial diet parse did not work, no need to dig into method bodies. continue; } //fill the methods bodies in order for the code to be generated //real parse of the method.... org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; if (types != null) { for (int j = 0, typeLength = types.length; j < typeLength; j++) { types[j].parseMethods(parser, compilationUnitDeclaration); } } // convert AST 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 */, subMonitor.split(1), true); node.setTypeRoot(compilationUnits[i]); // accept AST astRequestor.acceptAST(compilationUnits[i], node); } } public static void parse( String[] sourceUnits, String[] encodings, FileASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) { CompilerOptions compilerOptions = new CompilerOptions(options); compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; Parser parser = new CommentRecorderParser( new ProblemReporter( DefaultErrorHandlingPolicies.proceedWithAllProblems(), compilerOptions, new DefaultProblemFactory()), false); int unitLength = sourceUnits.length; SubMonitor subMonitor = SubMonitor.convert(monitor, unitLength); for (int i = 0; i < unitLength; i++) { SubMonitor iterationMonitor = subMonitor.split(1); char[] contents = null; String encoding = encodings != null ? encodings[i] : null; try { contents = Util.getFileCharContent(new File(sourceUnits[i]), encoding); } catch(IOException e) { // go to the next unit continue; } if (contents == null) { // go to the next unit continue; } org.eclipse.jdt.internal.compiler.batch.CompilationUnit compilationUnit = new org.eclipse.jdt.internal.compiler.batch.CompilationUnit(contents, sourceUnits[i], encoding); org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationUnit; CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); if (compilationUnitDeclaration.ignoreMethodBodies) { compilationUnitDeclaration.ignoreFurtherInvestigation = true; // if initial diet parse did not work, no need to dig into method bodies. continue; } //fill the methods bodies in order for the code to be generated //real parse of the method.... org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; if (types != null) { for (int j = 0, typeLength = types.length; j < typeLength; j++) { types[j].parseMethods(parser, compilationUnitDeclaration); } } // convert AST 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 */, iterationMonitor, true); node.setTypeRoot(null); // accept AST astRequestor.acceptAST(sourceUnits[i], node); } } public static CompilationUnitDeclaration parse( org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, NodeSearcher nodeSearcher, Map settings, int flags) { if (sourceUnit == null) { throw new IllegalStateException(); } CompilerOptions compilerOptions = new CompilerOptions(settings); boolean statementsRecovery = (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0; compilerOptions.performMethodsFullRecovery = statementsRecovery; compilerOptions.performStatementsRecovery = statementsRecovery; compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; Parser parser = new CommentRecorderParser( new ProblemReporter( DefaultErrorHandlingPolicies.proceedWithAllProblems(), compilerOptions, new DefaultProblemFactory()), false); CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); if (compilationUnitDeclaration.ignoreMethodBodies) { compilationUnitDeclaration.ignoreFurtherInvestigation = true; // if initial diet parse did not work, no need to dig into method bodies. return compilationUnitDeclaration; } if (nodeSearcher != null) { char[] source = parser.scanner.getSource(); int searchPosition = nodeSearcher.position; if (searchPosition < 0 || searchPosition > source.length) { // the position is out of range. There is no need to search for a node. return compilationUnitDeclaration; } compilationUnitDeclaration.traverse(nodeSearcher, compilationUnitDeclaration.scope); org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found; if (node == null) { return compilationUnitDeclaration; } org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType; if (node instanceof AbstractMethodDeclaration) { ((AbstractMethodDeclaration)node).parseStatements(parser, compilationUnitDeclaration); } else if (enclosingTypeDeclaration != null) { if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(parser, enclosingTypeDeclaration, compilationUnitDeclaration); } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(parser, compilationUnitDeclaration); } } } else { //fill the methods bodies in order for the code to be generated //real parse of the method.... org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; if (types != null) { for (int j = 0, typeLength = types.length; j < typeLength; j++) { types[j].parseMethods(parser, compilationUnitDeclaration); } } } return compilationUnitDeclaration; } public static void resolve( ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor, int apiLevel, Map options, IJavaProject javaProject, WorkingCopyOwner owner, int flags, IProgressMonitor monitor) { CancelableNameEnvironment environment = null; CancelableProblemFactory problemFactory = null; try { int amountOfWork = (compilationUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve SubMonitor subMonitor = SubMonitor.convert(monitor, amountOfWork); environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, subMonitor); problemFactory = new CancelableProblemFactory(subMonitor); CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; CompilationUnitResolver resolver = new CompilationUnitResolver( environment, getHandlingPolicy(), compilerOptions, getRequestor(), problemFactory, subMonitor, javaProject != null); resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner, flags); if (NameLookup.VERBOSE) { System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ } } catch (JavaModelException e) { // project doesn't exist -> simple parse without resolving parse(compilationUnits, requestor, apiLevel, options, flags, monitor); } finally { if (environment != null) { environment.setMonitor(null); // don't hold a reference to this external object } if (problemFactory != null) { problemFactory.monitor = null; // don't hold a reference to this external object } } } public static void resolve( String[] sourceUnits, String[] encodings, String[] bindingKeys, FileASTRequestor requestor, int apiLevel, Map options, List classpaths, int flags, IProgressMonitor monitor) { INameEnvironmentWithProgress environment = null; CancelableProblemFactory problemFactory = null; try { int amountOfWork = (sourceUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve SubMonitor subMonitor = SubMonitor.convert(monitor, amountOfWork); Classpath[] allEntries = new Classpath[classpaths.size()]; classpaths.toArray(allEntries); environment = new NameEnvironmentWithProgress(allEntries, null, subMonitor); problemFactory = new CancelableProblemFactory(subMonitor); CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; CompilationUnitResolver resolver = new CompilationUnitResolver( environment, getHandlingPolicy(), compilerOptions, getRequestor(), problemFactory, subMonitor, false); resolver.resolve(sourceUnits, encodings, bindingKeys, requestor, apiLevel, options, flags); if (NameLookup.VERBOSE && (environment instanceof CancelableNameEnvironment)) { CancelableNameEnvironment cancelableNameEnvironment = (CancelableNameEnvironment) environment; System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + cancelableNameEnvironment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + cancelableNameEnvironment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ } } finally { if (environment != null) { environment.setMonitor(null); // don't hold a reference to this external object } if (problemFactory != null) { problemFactory.monitor = null; // don't hold a reference to this external object } } } public static CompilationUnitDeclaration resolve( org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, IJavaProject javaProject, List classpaths, NodeSearcher nodeSearcher, Map options, WorkingCopyOwner owner, int flags, IProgressMonitor monitor) throws JavaModelException { CompilationUnitDeclaration unit = null; INameEnvironmentWithProgress environment = null; CancelableProblemFactory problemFactory = null; CompilationUnitResolver resolver = null; try { if (javaProject == null) { Classpath[] allEntries = new Classpath[classpaths.size()]; classpaths.toArray(allEntries); environment = new NameEnvironmentWithProgress(allEntries, null, monitor); } else { environment = new CancelableNameEnvironment((JavaProject) javaProject, owner, monitor); } problemFactory = new CancelableProblemFactory(monitor); CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); boolean ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; compilerOptions.ignoreMethodBodies = ignoreMethodBodies; resolver = new CompilationUnitResolver( environment, getHandlingPolicy(), compilerOptions, getRequestor(), problemFactory, monitor, javaProject != null); boolean analyzeAndGenerateCode = !ignoreMethodBodies; unit = resolver.resolve( null, // no existing compilation unit declaration sourceUnit, nodeSearcher, true, // method verification analyzeAndGenerateCode, // analyze code analyzeAndGenerateCode); // generate code if (resolver.hasCompilationAborted) { // the bindings could not be resolved due to missing types in name environment // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541 CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags); if (unit != null) { final int problemCount = unit.compilationResult.problemCount; if (problemCount != 0) { unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount]; System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount); unitDeclaration.compilationResult.problemCount = problemCount; } } else if (resolver.abortProblem != null) { unitDeclaration.compilationResult.problemCount = 1; unitDeclaration.compilationResult.problems = new CategorizedProblem[] { resolver.abortProblem }; } return unitDeclaration; } if (NameLookup.VERBOSE && environment instanceof CancelableNameEnvironment) { CancelableNameEnvironment cancelableNameEnvironment = (CancelableNameEnvironment) environment; System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + cancelableNameEnvironment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + cancelableNameEnvironment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ } return unit; } finally { if (environment != null) { // don't hold a reference to this external object environment.setMonitor(null); } if (problemFactory != null) { problemFactory.monitor = null; // don't hold a reference to this external object } } } public static IBinding[] resolve( final IJavaElement[] elements, int apiLevel, Map compilerOptions, IJavaProject javaProject, WorkingCopyOwner owner, int flags, IProgressMonitor monitor) { final int length = elements.length; final HashMap sourceElementPositions = new HashMap(); // a map from ICompilationUnit to int[] (positions in elements) int cuNumber = 0; final HashtableOfObjectToInt binaryElementPositions = new HashtableOfObjectToInt(); // a map from String (binding key) to int (position in elements) for (int i = 0; i < length; i++) { IJavaElement element = elements[i]; if (!(element instanceof SourceRefElement)) throw new IllegalStateException(element + " is not part of a compilation unit or class file"); //$NON-NLS-1$ Object cu = element.getAncestor(IJavaElement.COMPILATION_UNIT); if (cu != null) { // source member IntArrayList intList = (IntArrayList) sourceElementPositions.get(cu); if (intList == null) { sourceElementPositions.put(cu, intList = new IntArrayList()); cuNumber++; } intList.add(i); } else { // binary member or method argument try { String key; if (element instanceof BinaryMember) key = ((BinaryMember) element).getKey(true/*open to get resolved info*/); else if (element instanceof LocalVariable) key = ((LocalVariable) element).getKey(true/*open to get resolved info*/); else if (element instanceof org.eclipse.jdt.internal.core.TypeParameter) key = ((org.eclipse.jdt.internal.core.TypeParameter) element).getKey(true/*open to get resolved info*/); else if (element instanceof BinaryModule) key = ((BinaryModule) element).getKey(true); else throw new IllegalArgumentException(element + " has an unexpected type"); //$NON-NLS-1$ binaryElementPositions.put(key, i); } catch (JavaModelException e) { throw new IllegalArgumentException(element + " does not exist", e); //$NON-NLS-1$ } } } ICompilationUnit[] cus = new ICompilationUnit[cuNumber]; sourceElementPositions.keySet().toArray(cus); int bindingKeyNumber = binaryElementPositions.size(); String[] bindingKeys = new String[bindingKeyNumber]; binaryElementPositions.keysToArray(bindingKeys); class Requestor extends ASTRequestor { IBinding[] bindings = new IBinding[length]; @Override public void acceptAST(ICompilationUnit source, CompilationUnit ast) { // TODO (jerome) optimize to visit the AST only once IntArrayList intList = (IntArrayList) sourceElementPositions.get(source); for (int i = 0; i < intList.length; i++) { final int index = intList.list[i]; SourceRefElement element = (SourceRefElement) elements[index]; DOMFinder finder = new DOMFinder(ast, element, true/*resolve binding*/); try { finder.search(); } catch (JavaModelException e) { throw new IllegalArgumentException(element + " does not exist", e); //$NON-NLS-1$ } this.bindings[index] = finder.foundBinding; } } @Override public void acceptBinding(String bindingKey, IBinding binding) { int index = binaryElementPositions.get(bindingKey); this.bindings[index] = binding; } } Requestor requestor = new Requestor(); resolve(cus, bindingKeys, requestor, apiLevel, compilerOptions, javaProject, owner, flags, monitor); return requestor.bindings; } /* * When unit result is about to be accepted, removed back pointers * to unresolved bindings */ public void removeUnresolvedBindings(CompilationUnitDeclaration compilationUnitDeclaration) { final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; if (types != null) { for (int i = 0, max = types.length; i < max; i++) { removeUnresolvedBindings(types[i]); } } } private void removeUnresolvedBindings(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration type) { final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] memberTypes = type.memberTypes; if (memberTypes != null) { for (int i = 0, max = memberTypes.length; i < max; i++){ removeUnresolvedBindings(memberTypes[i]); } } if (type.binding != null && (type.binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { type.binding = null; } final org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = type.fields; if (fields != null) { for (int i = 0, max = fields.length; i < max; i++){ if (fields[i].binding != null && (fields[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { fields[i].binding = null; } } } final AbstractMethodDeclaration[] methods = type.methods; if (methods != null) { for (int i = 0, max = methods.length; i < max; i++){ if (methods[i].binding != null && (methods[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { methods[i].binding = null; } } } } private void resolve( ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map compilerOptions, WorkingCopyOwner owner, int flags) { // temporarily connect ourselves to the ASTResolver - must disconnect when done astRequestor.compilationUnitResolver = this; this.bindingTables = new DefaultBindingResolver.BindingTables(); CompilationUnitDeclaration unit = null; try { int length = compilationUnits.length; org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length]; System.arraycopy(compilationUnits, 0, sourceUnits, 0, length); beginToCompile(sourceUnits, bindingKeys); // process all units (some more could be injected in the loop by the lookup environment) for (int i = 0; i < this.totalUnits; i++) { if (resolvedRequestedSourcesAndKeys(i)) { // no need to keep resolving if no more ASTs and no more binding keys are needed // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935 // cleanup remaining units for (; i < this.totalUnits; i++) { this.unitsToProcess[i].cleanUp(); this.unitsToProcess[i] = null; } break; } unit = this.unitsToProcess[i]; try { super.process(unit, i); // this.process(...) is optimized to not process already known units // requested AST char[] fileName = unit.compilationResult.getFileName(); ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName); if (source != null) { // convert AST CompilationResult compilationResult = unit.compilationResult; org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit; char[] contents = sourceUnit.getContents(); AST ast = AST.newAST(apiLevel, JavaCore.ENABLED.equals(this.options.getMap().get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); ast.setFlag(flags | AST.RESOLVED_BINDINGS); ast.setDefaultNodeFlag(ASTNode.ORIGINAL); ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor); BindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, this.fromJavaProject); ast.setBindingResolver(resolver); converter.setAST(ast); CompilationUnit compilationUnit = converter.convert(unit, contents); compilationUnit.setTypeRoot(source); compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions()); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); // pass it to requestor astRequestor.acceptAST(source, compilationUnit); worked(1); // 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 this.requestedSources.put(fileName, null); // mark it as removed } // requested binding Object key = this.requestedKeys.get(fileName); if (key != null) { if (key instanceof BindingKeyResolver) { reportBinding(key, astRequestor, owner, unit); worked(1); } else if (key instanceof ArrayList) { Iterator iterator = ((ArrayList) key).iterator(); while (iterator.hasNext()) { reportBinding(iterator.next(), astRequestor, owner, unit); worked(1); } } // 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 this.requestedKeys.put(fileName, null); // mark it as removed } } finally { // cleanup compilation unit result unit.cleanUp(); } this.unitsToProcess[i] = null; // release reference to processed unit declaration this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); } // remaining binding keys DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, true); Object[] keys = this.requestedKeys.valueTable; for (int j = 0, keysLength = keys.length; j < keysLength; j++) { BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j]; if (keyResolver == null) continue; Binding compilerBinding = keyResolver.getCompilerBinding(); IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding); // pass it to requestor astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding); worked(1); } } catch (OperationCanceledException e) { throw e; } catch (AbortCompilation e) { this.handleInternalException(e, unit); } catch (Error | RuntimeException e) { this.handleInternalException(e, unit, null); throw e; // rethrow } finally { // disconnect ourselves from ast requestor astRequestor.compilationUnitResolver = null; } } private void resolve( String[] sourceCompilationUnits, String[] encodings, String[] bindingKeys, FileASTRequestor astRequestor, int apiLevel, Map compilerOptions, int flags) { // temporarily connect ourselves to the ASTResolver - must disconnect when done astRequestor.compilationUnitResolver = this; this.bindingTables = new DefaultBindingResolver.BindingTables(); CompilationUnitDeclaration unit = null; try { int length = sourceCompilationUnits.length; org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length]; int count = 0; for (int i = 0; i < length; i++) { char[] contents = null; String encoding = encodings != null ? encodings[i] : null; String sourceUnitPath = sourceCompilationUnits[i]; try { contents = Util.getFileCharContent(new File(sourceUnitPath), encoding); } catch(IOException e) { // go to the next unit continue; } if (contents == null) { // go to the next unit continue; } sourceUnits[count++] = new org.eclipse.jdt.internal.compiler.batch.CompilationUnit(contents, sourceUnitPath, encoding); } if (count < length) { org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] newArray = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[count]; System.arraycopy(sourceUnits, 0, newArray, 0, count); sourceUnits = newArray; } beginToCompile(sourceUnits, bindingKeys); // process all units (some more could be injected in the loop by the lookup environment) for (int i = 0; i < this.totalUnits; i++) { if (resolvedRequestedSourcesAndKeys(i)) { // no need to keep resolving if no more ASTs and no more binding keys are needed // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935 // cleanup remaining units for (; i < this.totalUnits; i++) { this.unitsToProcess[i].cleanUp(); this.unitsToProcess[i] = null; } break; } unit = this.unitsToProcess[i]; try { super.process(unit, i); // this.process(...) is optimized to not process already known units // requested AST char[] fileName = unit.compilationResult.getFileName(); org.eclipse.jdt.internal.compiler.env.ICompilationUnit source = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.requestedSources.get(fileName); if (source != null) { // convert AST CompilationResult compilationResult = unit.compilationResult; org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit; char[] contents = sourceUnit.getContents(); AST ast = AST.newAST(apiLevel, JavaCore.ENABLED.equals(compilerOptions.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); ast.setFlag(flags | AST.RESOLVED_BINDINGS); ast.setDefaultNodeFlag(ASTNode.ORIGINAL); ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor); BindingResolver resolver = new DefaultBindingResolver(unit.scope, null, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, this.fromJavaProject); ast.setBindingResolver(resolver); converter.setAST(ast); CompilationUnit compilationUnit = converter.convert(unit, contents); compilationUnit.setTypeRoot(null); compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions()); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); // pass it to requestor astRequestor.acceptAST(new String(source.getFileName()), compilationUnit); worked(1); // 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 this.requestedSources.put(fileName, null); // mark it as removed } // requested binding Object key = this.requestedKeys.get(fileName); if (key != null) { if (key instanceof BindingKeyResolver) { reportBinding(key, astRequestor, unit); worked(1); } else if (key instanceof ArrayList) { Iterator iterator = ((ArrayList) key).iterator(); while (iterator.hasNext()) { reportBinding(iterator.next(), astRequestor, unit); worked(1); } } // 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 this.requestedKeys.put(fileName, null); // mark it as removed } } finally { // cleanup compilation unit result unit.cleanUp(); } this.unitsToProcess[i] = null; // release reference to processed unit declaration this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); } // remaining binding keys DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, true); Object[] keys = this.requestedKeys.valueTable; for (int j = 0, keysLength = keys.length; j < keysLength; j++) { BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j]; if (keyResolver == null) continue; Binding compilerBinding = keyResolver.getCompilerBinding(); IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding); // pass it to requestor astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding); worked(1); } } catch (OperationCanceledException e) { throw e; } catch (AbortCompilation e) { this.handleInternalException(e, unit); } catch (Error | RuntimeException e) { this.handleInternalException(e, unit, null); throw e; // rethrow } finally { // disconnect ourselves from ast requestor astRequestor.compilationUnitResolver = null; } } private void reportBinding(Object key, ASTRequestor astRequestor, WorkingCopyOwner owner, CompilationUnitDeclaration unit) { BindingKeyResolver keyResolver = (BindingKeyResolver) key; Binding compilerBinding = keyResolver.getCompilerBinding(); if (compilerBinding != null) { DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, false, this.fromJavaProject); AnnotationBinding annotationBinding = keyResolver.getAnnotationBinding(); IBinding binding; if (annotationBinding != null) { binding = resolver.getAnnotationInstance(annotationBinding); } else { binding = resolver.getBinding(compilerBinding); } if (binding != null) astRequestor.acceptBinding(keyResolver.getKey(), binding); } } private void reportBinding(Object key, FileASTRequestor astRequestor, CompilationUnitDeclaration unit) { BindingKeyResolver keyResolver = (BindingKeyResolver) key; Binding compilerBinding = keyResolver.getCompilerBinding(); if (compilerBinding != null) { DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, null, this.bindingTables, false, this.fromJavaProject); AnnotationBinding annotationBinding = keyResolver.getAnnotationBinding(); IBinding binding; if (annotationBinding != null) { binding = resolver.getAnnotationInstance(annotationBinding); } else { binding = resolver.getBinding(compilerBinding); } if (binding != null) astRequestor.acceptBinding(keyResolver.getKey(), binding); } } private CompilationUnitDeclaration resolve( CompilationUnitDeclaration unit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, NodeSearcher nodeSearcher, boolean verifyMethods, boolean analyzeCode, boolean generateCode) { try { if (unit == null) { // build and record parsed units this.parseThreshold = 0; // will request a full parse beginToCompile(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] { sourceUnit }); // find the right unit from what was injected via accept(ICompilationUnit,..): for (int i=0, max = this.totalUnits; i < max; i++) { CompilationUnitDeclaration currentCompilationUnitDeclaration = this.unitsToProcess[i]; if (currentCompilationUnitDeclaration != null && currentCompilationUnitDeclaration.compilationResult.compilationUnit == sourceUnit) { unit = currentCompilationUnitDeclaration; break; } } if (unit == null) { unit = this.unitsToProcess[0]; // fall back to old behavior } } else { // initial type binding creation this.lookupEnvironment.buildTypeBindings(unit, null /*no access restriction*/); // binding resolution this.lookupEnvironment.completeTypeBindings(); } if (nodeSearcher == null) { this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed } else { int searchPosition = nodeSearcher.position; char[] source = sourceUnit.getContents(); int length = source.length; if (searchPosition >= 0 && searchPosition <= length) { unit.traverse(nodeSearcher, unit.scope); org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found; if (node != null) { // save existing values to restore them at the end of the parsing process // see bug 47079 for more details int[] oldLineEnds = this.parser.scanner.lineEnds; int oldLinePtr = this.parser.scanner.linePtr; this.parser.scanner.setSource(source, unit.compilationResult); org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType; if (node instanceof AbstractMethodDeclaration) { ((AbstractMethodDeclaration)node).parseStatements(this.parser, unit); } else if (enclosingTypeDeclaration != null) { if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit); } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(this.parser, unit); } } // this is done to prevent any side effects on the compilation unit result // line separator positions array. this.parser.scanner.lineEnds = oldLineEnds; this.parser.scanner.linePtr = oldLinePtr; } } } if (unit.scope != null) { CompilationUnitDeclaration previousUnit = this.lookupEnvironment.unitBeingCompleted; this.lookupEnvironment.unitBeingCompleted = unit; try { // fault in fields & methods unit.scope.faultInTypes(); if (unit.scope != null && verifyMethods) { // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117 // verify inherited methods unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier()); } // type checking unit.resolve(); // flow analysis if (analyzeCode) unit.analyseCode(); // code generation if (generateCode) unit.generateCode(); // finalize problems (suppressWarnings) unit.finalizeProblems(); } finally { this.lookupEnvironment.unitBeingCompleted = previousUnit; // paranoia, always null in org.eclipse.jdt.core.tests.dom.RunAllTests } } if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); return unit; } catch (AbortCompilation e) { this.handleInternalException(e, unit); return unit == null ? this.unitsToProcess[0] : unit; } catch (Error | RuntimeException e) { this.handleInternalException(e, unit, null); throw e; // rethrow } finally { // No reset is performed there anymore since, // within the CodeAssist (or related tools), // the compiler may be called *after* a call // to this resolve(...) method. And such a call // needs to have a compiler with a non-empty // environment. // this.reset(); } } /* * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process */ @Override public CompilationUnitDeclaration resolve( org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, boolean verifyMethods, boolean analyzeCode, boolean generateCode) { return resolve( null, /* no existing compilation unit declaration*/ sourceUnit, null/*no node searcher*/, verifyMethods, analyzeCode, generateCode); } boolean resolvedRequestedSourcesAndKeys(int unitIndexToProcess) { if (unitIndexToProcess < this.requestedSources.size() && unitIndexToProcess < this.requestedKeys.size()) return false; // must process at least this many units before checking to see if all are done Object[] sources = this.requestedSources.valueTable; for (int i = 0, l = sources.length; i < l; i++) if (sources[i] != null) return false; Object[] keys = this.requestedKeys.valueTable; for (int i = 0, l = keys.length; i < l; i++) if (keys[i] != null) return false; return true; } /* * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process */ @Override public CompilationUnitDeclaration resolve( CompilationUnitDeclaration unit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, boolean verifyMethods, boolean analyzeCode, boolean generateCode) { return resolve( unit, sourceUnit, null/*no node searcher*/, verifyMethods, analyzeCode, generateCode); } private void worked(int work) { if (this.monitor != null) { if (this.monitor.isCanceled()) throw new OperationCanceledException(); this.monitor.worked(work); } } }