blob: e6b3fd1b4d2234beaacb383603d99671e25c079d [file] [log] [blame]
/*******************************************************************************
* 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
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended 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;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
/**
* <h4>OTDT changes:</h4>
* <dl>
* <dt>What:<dd> setup and use Dependencies for calling into the compiler.
* </dl>
*/
@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 <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
*
* @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.
*/
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) {
environment.printTimeSpent();
}
} 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;
cancelableNameEnvironment.printTimeSpent();
}
} 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;
cancelableNameEnvironment.printTimeSpent();
}
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;
//{ObjectTeams:
/* orig:
try {
:giro */
try (Config config = Dependencies.setup(this, this.parser, this.lookupEnvironment,
true/*verify*/, !this.options.ignoreMethodBodies/*analyze*/, !this.options.ignoreMethodBodies/*generate*/,
true, true, false))
{
// SH+KM}
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;
//{ObjectTeams:
/* orig:
try {
:giro */
try (Config config = Dependencies.setup(this, this.parser, this.lookupEnvironment,
true/*verify*/, !this.options.ignoreMethodBodies/*analyze*/, !this.options.ignoreMethodBodies/*generate*/,
true, true, false))
{
//SH}
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) {
//{ObjectTeams:
/* orig:
try {
:giro */
try (Config config = Dependencies.setup(this, this.parser, this.lookupEnvironment,
verifyMethods, analyzeCode, generateCode, true, true, false))
{
// SH}
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,..):
//{ObjectTeams: also due to role files the unit corresponding to sourceUnit need not be in position 0. SH}
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;
}
//{ObjectTeams: no more method bodies, have explicitly parsed those we need:
unit.parseMethodBodies = false;
// SH}
}
}
if (unit.scope != null) {
CompilationUnitDeclaration previousUnit = this.lookupEnvironment.unitBeingCompleted;
this.lookupEnvironment.unitBeingCompleted = unit;
try {
//{ObjectTeams: replace single step by Dependencies:
/* orig:
// 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();
*/
if (generateCode)
Dependencies.ensureState(unit, ITranslationStates.STATE_BYTE_CODE_GENERATED);
else if (analyzeCode)
Dependencies.ensureState(unit, ITranslationStates.STATE_CODE_ANALYZED);
else
Dependencies.ensureState(unit, ITranslationStates.STATE_RESOLVED);
// SH}
// finalize problems (suppressWarnings)
unit.finalizeProblems();
} finally {
this.lookupEnvironment.unitBeingCompleted = previousUnit; // paranoia, always null in org.eclipse.jdt.core.tests.dom.RunAllTests
}
}
// TODO(SH): release also role file units!
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);
}
}
}