blob: b9a038f46cd3d568bc685a6c87d9c1d1d10ff0a0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2020 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 - contributions for
* bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment
* bug 186342 - [compiler][null] Using annotations for null checking
* bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults
* bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
* bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files
* Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* Bug 415291 - [1.8][null] differentiate type incompatibilities due to null annotations
* Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
* Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled
* Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
* Bug 416183 - [1.8][compiler][null] Overload resolution fails with null annotations
* Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking
* Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
* Bug 416190 - [1.8][null] detect incompatible overrides due to null type annotations
* Bug 424624 - [1.8][null] if a static-object with annotation @NonNull is used, a warning is shown
* Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables
* Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type
* Bug 434602 - Possible error with inferred null annotations leading to contradictory null annotations
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
* Bug 453475 - [1.8][null] Contradictory null annotations (4.5 M3 edition)
* Bug 457079 - Regression: type inference
* Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
* Bug 455180 - IllegalStateException in AnnotatableTypeSystem.getRawType
* Bug 470467 - [null] Nullness of special Enum methods not detected from .class file
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ClassFilePool;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.util.HashtableOfModule;
import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
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;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.StateHelper;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RoleSplitter;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.TeamMethodGenerator;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstEdit;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleFileHelper;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer;
/**
* OTDT changes:
*
* Dependency control:
* ===================
* What: Connect buildTypeBindings/completeTypeBindings with Dependencies.
* Why: All different kinds of parsers/compilers need to call {build,complete}TypeBindings(..),
* where such building must be synchronized with other compilation phases.
*
* What: Signal when we are done with completeTypeBindings()
* Why: Dependencies needs to know.
*
* Role files:
* ===========
* What: When building types for a role file, find and link the enclosing team.
*
* What: Changed detection of type/package collision to include default package.
* Why: In Java such collision is undefined within the default package.
* However, for OT/J we need this to find matching team package/type in the
* default package.
*
* Role local types:
* =================
* What: Set enclosing type of local type of role.
* Why: Local types are not usually read from byte code (no use), but we need them for copy inheritance.
* How: RoleModel.addUnresolvedLocalType() stores current role in LookupEnvironment.enclosingRole.
* BinaryTypeBinding.cachePartsFrom() reads that information and sets enclosingType.
*
* Visibility:
* ===========
* What: Changed getTypeFromConstantPoolName() to public
* Why: The PayedBy and RoleLocalTypes byte code attributes need to resolve types given their
* constant pool name.
*
* What: Changed RoleLocalTypes() to public.
* Why: ConstantPoolObjectReader needs to resolve types given their signature.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class LookupEnvironment implements ProblemReasons, TypeConstants {
/**
* Map from typeBinding -> accessRestriction rule
*/
private Map accessRestrictions;
ImportBinding[] defaultImports; // ROOT_ONLY
/**
* The root environment driving the current compilation.
* Other mutable fields in this class marked as ROOT_ONLY must always be accessed from the root environment.
* It is assumed that external clients only know the root environment, whereas calls internally in the compiler
* have to delegate to root where necessary.
* Immutable fields with "global" semantics are SHARED among environments via aliasing.
*/
public final LookupEnvironment root;
public ModuleBinding UnNamedModule;
public ModuleBinding JavaBaseModule;
public ModuleBinding module;
public PlainPackageBinding defaultPackage;
/** All visible toplevel packages, i.e. observable packages associated with modules read by the current module. */
HashtableOfPackage knownPackages;
private int lastCompletedUnitIndex = -1; // ROOT_ONLY
private int lastUnitIndex = -1; // ROOT_ONLY
TypeSystem typeSystem; // SHARED
public INameEnvironment nameEnvironment; // SHARED
public CompilerOptions globalOptions; // SHARED
public ProblemReporter problemReporter; // SHARED
public ClassFilePool classFilePool; // SHARED
// indicate in which step on the compilation we are.
// step 1 : build the reference binding
// step 2 : conect the hierarchy (connect bindings)
// step 3 : build fields and method bindings.
private int stepCompleted; // ROOT_ONLY
public ITypeRequestor typeRequestor; // SHARED
private SimpleLookupTable uniqueParameterizedGenericMethodBindings;
// key is a string with the method selector value is an array of method bindings
private SimpleLookupTable uniquePolymorphicMethodBindings;
private SimpleLookupTable uniqueGetClassMethodBinding; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=300734
boolean useModuleSystem; // true when compliance >= 9 and nameEnvironment is module aware
// key is a string with the module name value is a module binding
public HashtableOfModule knownModules; // SHARED
public CompilationUnitDeclaration unitBeingCompleted = null; // only set while completing units -- ROOT_ONLY
public Object missingClassFileLocation = null; // only set when resolving certain references, to help locating problems
private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4]; // ROOT_ONLY
private MethodVerifier verifier;
private ArrayList missingTypes;
Set<SourceTypeBinding> typesBeingConnected; // SHARED
public boolean isProcessingAnnotations = false; // ROOT_ONLY
public boolean mayTolerateMissingType = false;
PackageBinding nullableAnnotationPackage; // the package supposed to contain the Nullable annotation type
PackageBinding nonnullAnnotationPackage; // the package supposed to contain the NonNull annotation type
PackageBinding nonnullByDefaultAnnotationPackage; // the package supposed to contain the NonNullByDefault annotation type
AnnotationBinding nonNullAnnotation;
AnnotationBinding nullableAnnotation;
Map<String,Integer> allNullAnnotations = null;
final List<MethodBinding> deferredEnumMethods; // SHARED: during early initialization we cannot mark Enum-methods as nonnull.
/** Global access to the outermost active inference context as the universe for inference variable interning. */
InferenceContext18 currentInferenceContext;
/**
* Flag that should be set during annotation traversal or similar runs
* to prevent caching of failures regarding imports of yet to be generated classes.
*/
public boolean suppressImportErrors; // per module
public String moduleVersion; // ROOT_ONLY
final static int BUILD_FIELDS_AND_METHODS = 4;
final static int BUILD_TYPE_HIERARCHY = 1;
final static int CHECK_AND_SET_IMPORTS = 2;
final static int CONNECT_TYPE_HIERARCHY = 3;
//{ObjectTeams: include this step into LookupEnvironment's control:
final static int ROLES_LINKED = 5;
// SH}
static final ProblemPackageBinding TheNotFoundPackage = new ProblemPackageBinding(CharOperation.NO_CHAR, NotFound, null/*not perfect*/);
static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR_CHAR, null, NotFound);
static final ModuleBinding TheNotFoundModule = new ModuleBinding(CharOperation.NO_CHAR);
//{ObjectTeams: shared instance within a compilation:
private TeamMethodGenerator teamMethodGenerator;
public TeamMethodGenerator getTeamMethodGenerator() {
if (this.teamMethodGenerator == null)
this.teamMethodGenerator = new TeamMethodGenerator(this.globalOptions.weavingScheme);
return this.teamMethodGenerator;
}
// SH}
/** Construct the root LookupEnvironment, corresponding to the UnNamedModule. */
public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions globalOptions, ProblemReporter problemReporter, INameEnvironment nameEnvironment) {
this.root = this;
this.UnNamedModule = new ModuleBinding.UnNamedModule(this);
this.module = this.UnNamedModule;
this.typeRequestor = typeRequestor;
this.globalOptions = globalOptions;
this.problemReporter = problemReporter;
this.defaultPackage = new PlainPackageBinding(this); // assume the default package always exists
this.defaultImports = null;
this.nameEnvironment = nameEnvironment;
this.knownPackages = new HashtableOfPackage();
this.uniqueParameterizedGenericMethodBindings = new SimpleLookupTable(3);
this.uniquePolymorphicMethodBindings = new SimpleLookupTable(3);
this.missingTypes = null;
this.accessRestrictions = new HashMap(3);
this.classFilePool = ClassFilePool.newInstance();
this.typesBeingConnected = new HashSet<>();
this.deferredEnumMethods = new ArrayList<>();
this.typeSystem = this.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8 && this.globalOptions.storeAnnotations ? new AnnotatableTypeSystem(this) : new TypeSystem(this);
this.knownModules = new HashtableOfModule();
this.useModuleSystem = nameEnvironment instanceof IModuleAwareNameEnvironment && globalOptions.complianceLevel >= ClassFileConstants.JDK9;
this.resolutionListeners = new IQualifiedTypeResolutionListener[0];
}
/** Construct a specific LookupEnvironment, corresponding to the given module. */
LookupEnvironment(LookupEnvironment rootEnv, ModuleBinding module) {
this.root = rootEnv;
this.UnNamedModule = rootEnv.UnNamedModule;
this.module = module;
this.typeRequestor = rootEnv.typeRequestor;
this.globalOptions = rootEnv.globalOptions;
this.problemReporter = rootEnv.problemReporter;
this.defaultPackage = new PlainPackageBinding(this); // assume the default package always exists
this.defaultImports = null;
this.nameEnvironment = rootEnv.nameEnvironment;
this.knownPackages = new HashtableOfPackage();
this.uniqueParameterizedGenericMethodBindings = new SimpleLookupTable(3);
this.uniquePolymorphicMethodBindings = new SimpleLookupTable(3);
this.missingTypes = null;
this.accessRestrictions = new HashMap(3);
this.classFilePool = rootEnv.classFilePool;
this.typesBeingConnected = rootEnv.typesBeingConnected;
this.deferredEnumMethods = rootEnv.deferredEnumMethods;
this.typeSystem = rootEnv.typeSystem;
// knownModules is unused in specific LookupEnvironments
this.useModuleSystem = rootEnv.useModuleSystem;
}
// NOTE: only for resolving!
public ModuleBinding getModule(char[] name) {
if (this.root != this)
return this.root.getModule(name);
if (name == null || name == ModuleBinding.UNNAMED || CharOperation.equals(name, ModuleBinding.ALL_UNNAMED))
return this.UnNamedModule;
ModuleBinding moduleBinding = this.knownModules.get(name);
if (moduleBinding == null) {
if (this.useModuleSystem) {
IModule mod = ((IModuleAwareNameEnvironment) this.nameEnvironment).getModule(name);
if (mod != null) {
this.typeRequestor.accept(mod, this);
moduleBinding = this.root.knownModules.get(name);
}
} else
return this.UnNamedModule;
}
return moduleBinding;
}
/**
* Ask the name environment for a type which corresponds to the compoundName.
* Answer null if the name cannot be found.
*/
public ReferenceBinding askForType(char[][] compoundName, /*@NonNull*/ModuleBinding clientModule) {
// FIXME(SH): it might happen that this method finds a binary role,
// later the team is found as a source type having the role inline!!!
assert clientModule != null : "lookup needs a module"; //$NON-NLS-1$
NameEnvironmentAnswer[] answers = null;
if (this.useModuleSystem) {
IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.nameEnvironment;
answers = askForTypeFromModules(clientModule, clientModule.getAllRequiredModules(),
mod -> moduleEnv.findType(compoundName, mod.nameForLookup()));
} else {
NameEnvironmentAnswer answer = this.nameEnvironment.findType(compoundName);
if (answer != null) {
answer.moduleBinding = this.module;
answers = new NameEnvironmentAnswer[] { answer };
}
}
if (answers == null)
return null;
ReferenceBinding candidate = null;
for (NameEnvironmentAnswer answer : answers) {
if (answer == null) continue;
//{ObjectTeams: if we were looking specifically for a source type, and if this is satisfied now, reset to normal:
if (!answer.isBinaryType() && Config.hasConfig())
Config.setSourceTypeRequired(false);
// SH}
ModuleBinding answerModule = answer.moduleBinding != null ? answer.moduleBinding : this.UnNamedModule;
if (answer.isBinaryType()) {
// the type was found as a .class file
PackageBinding pkg = answerModule.environment.computePackageFrom(compoundName, false /* valid pkg */);
this.typeRequestor.accept(answer.getBinaryType(), pkg, answer.getAccessRestriction());
ReferenceBinding binding = pkg.getType0(compoundName[compoundName.length - 1]);
if (binding instanceof BinaryTypeBinding) {
((BinaryTypeBinding) binding).module = answerModule;
if (pkg.enclosingModule == null)
pkg.enclosingModule = answerModule;
}
} else if (answer.isCompilationUnit()) {
// the type was found as a .java file, try to build it then search the cache
this.typeRequestor.accept(answer.getCompilationUnit(), answer.getAccessRestriction());
} else if (answer.isSourceType()) {
// the type was found as a source model
PackageBinding pkg = answerModule.environment.computePackageFrom(compoundName, false /* valid pkg */);
this.typeRequestor.accept(answer.getSourceTypes(), pkg, answer.getAccessRestriction());
ReferenceBinding binding = pkg.getType0(compoundName[compoundName.length - 1]);
if (binding instanceof SourceTypeBinding) {
((SourceTypeBinding) binding).module = answerModule;
if (pkg.enclosingModule == null)
pkg.enclosingModule = answerModule;
}
}
candidate = combine(candidate, answerModule.environment.getCachedType(compoundName), clientModule);
}
return candidate;
}
/* Ask the oracle for a type named name in the packageBinding.
* Answer null if the name cannot be found.
*/
ReferenceBinding askForType(PackageBinding packageBinding, char[] name, ModuleBinding clientModule) {
assert clientModule != null : "lookup needs a module"; //$NON-NLS-1$
if (packageBinding == null) {
packageBinding = this.defaultPackage;
}
NameEnvironmentAnswer[] answers = null;
if (this.useModuleSystem) {
IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.nameEnvironment;
final PackageBinding pack = packageBinding;
// leverage module information from the (split?) package as to prefer NotAccessible over NotFound:
answers = askForTypeFromModules(null, packageBinding.getDeclaringModules(),
mod -> fromSplitPackageOrOracle(moduleEnv, mod, pack, name));
} else {
NameEnvironmentAnswer answer = this.nameEnvironment.findType(name, packageBinding.compoundName);
if (answer != null) {
answer.moduleBinding = this.module;
answers = new NameEnvironmentAnswer[] { answer };
}
}
if (answers == null)
return null;
ReferenceBinding candidate = null;
for (NameEnvironmentAnswer answer : answers) {
if (answer == null) continue;
if (candidate != null && candidate.problemId() == ProblemReasons.Ambiguous)
return candidate; // saw enough
//{ObjectTeams: if we were looking specifically for a source type, and if this is satisfied now, reset to normal:
if (!answer.isBinaryType() && Config.hasConfig())
Config.setSourceTypeRequired(false);
// SH}
ModuleBinding answerModule = answer.moduleBinding != null ? answer.moduleBinding : this.UnNamedModule;
PackageBinding answerPackage = packageBinding;
if (answerModule != null) {
if (!answerPackage.isDeclaredIn(answerModule))
continue; // this answer is not reachable via the packageBinding
answerPackage = answerPackage.getIncarnation(answerModule);
}
if (answer.isResolvedBinding()) {
candidate = combine(candidate, answer.getResolvedBinding(), clientModule);
continue;
} else if (answer.isBinaryType()) {
// the type was found as a .class file
this.typeRequestor.accept(answer.getBinaryType(), answerPackage, answer.getAccessRestriction());
ReferenceBinding binding = answerPackage.getType0(name);
if (binding instanceof BinaryTypeBinding) {
((BinaryTypeBinding) binding).module = answerModule;
}
} else if (answer.isCompilationUnit()) {
// the type was found as a .java file, try to build it then search the cache
//{ObjectTeams: prevent marking type as STATE_FINAL in case of caught abort()
boolean prevFlag = false;
TypeDeclaration typeDeclaration = null;
if (this.problemReporter.referenceContext instanceof TypeDeclaration) {
typeDeclaration = (TypeDeclaration)this.problemReporter.referenceContext;
prevFlag = typeDeclaration.willCatchAbort;
typeDeclaration.willCatchAbort = true;
}
// SH}
try {
this.typeRequestor.accept(answer.getCompilationUnit(), answer.getAccessRestriction());
} catch (AbortCompilation abort) {
if (CharOperation.equals(name, TypeConstants.PACKAGE_INFO_NAME))
return null; // silently, requestor may not be able to handle compilation units (HierarchyResolver)
throw abort;
}
//{ObjectTeams: reset
finally {
if (typeDeclaration != null)
typeDeclaration.willCatchAbort = prevFlag;
}
//SH}
} else if (answer.isSourceType()) {
// the type was found as a source model
this.typeRequestor.accept(answer.getSourceTypes(), answerPackage, answer.getAccessRestriction());
ReferenceBinding binding = answerPackage.getType0(name);
if (binding instanceof SourceTypeBinding) {
((SourceTypeBinding) binding).module = answerModule;
}
String externalAnnotationPath = answer.getExternalAnnotationPath();
if (externalAnnotationPath != null && this.globalOptions.isAnnotationBasedNullAnalysisEnabled && binding instanceof SourceTypeBinding) {
ExternalAnnotationSuperimposer.apply((SourceTypeBinding) binding, externalAnnotationPath);
}
candidate = combine(candidate, binding, clientModule);
continue;
}
candidate = combine(candidate, answerPackage.getType0(name), clientModule);
}
return candidate;
}
/** Combine up-to two candidate types. If both types are present let accessibility from the given clientModule decide. */
private ReferenceBinding combine(ReferenceBinding one, ReferenceBinding two, ModuleBinding clientModule) {
if (one == null) return two;
if (two == null) return one;
if (one.fPackage == null || !clientModule.canAccess(one.fPackage)) return two;
if (two.fPackage == null || !clientModule.canAccess(two.fPackage)) return one;
if (one == two) return one; //$IDENTITY-COMPARISON$
return new ProblemReferenceBinding(one.compoundName, one, ProblemReasons.Ambiguous); // TODO(SHMOD): use a new problem ID
}
/** Collect answers from the oracle concerning the given clientModule (if present) and each of a set of other modules. */
private NameEnvironmentAnswer[] askForTypeFromModules(ModuleBinding clientModule, ModuleBinding[] otherModules,
Function<ModuleBinding,NameEnvironmentAnswer> oracle)
{
if (clientModule != null && clientModule.nameForLookup().length == 0) {
NameEnvironmentAnswer answer = oracle.apply(clientModule);
if (answer != null)
answer.moduleBinding = this.root.getModuleFromAnswer(answer);
return new NameEnvironmentAnswer[] { answer };
} else {
boolean found = false;
NameEnvironmentAnswer[] answers = null;
if (clientModule != null) {
answers = new NameEnvironmentAnswer[otherModules.length+1];
NameEnvironmentAnswer answer = oracle.apply(clientModule);
if (answer != null) {
answer.moduleBinding = clientModule;
answers[answers.length-1] = answer;
found = true;
}
} else {
answers = new NameEnvironmentAnswer[otherModules.length];
}
for (int i = 0; i < otherModules.length; i++) {
NameEnvironmentAnswer answer = oracle.apply(otherModules[i]);
if (answer != null) {
if (answer.moduleBinding == null) {
char[] nameFromAnswer = answer.moduleName();
if (CharOperation.equals(nameFromAnswer, otherModules[i].moduleName)) {
answer.moduleBinding = otherModules[i];
} else {
answer.moduleBinding = getModule(nameFromAnswer);
}
}
answers[i] = answer;
found = true;
}
}
return found ? answers : null;
}
}
/** First check for a known type in a split package and otherwise ask the oracle. */
private static NameEnvironmentAnswer fromSplitPackageOrOracle(IModuleAwareNameEnvironment moduleEnv, ModuleBinding module,
PackageBinding packageBinding, char[] name)
{
if (packageBinding instanceof SplitPackageBinding) {
// when asking a split package getType0() we may have answered null in case of ambiguity (not knowing the module context).
// now check if the module-incarnation of the package has the type:
// (needed because the moduleEnv will not answer initial types).
ReferenceBinding binding = ((SplitPackageBinding) packageBinding).getType0ForModule(module, name);
if (binding != null && binding.isValidBinding()) {
if (binding instanceof UnresolvedReferenceBinding)
binding = ((UnresolvedReferenceBinding) binding).resolve(module.environment, false);
if (binding.isValidBinding())
return new NameEnvironmentAnswer(binding, module);
}
}
return moduleEnv.findType(name, packageBinding.compoundName, module.nameForLookup());
}
private ModuleBinding getModuleFromAnswer(NameEnvironmentAnswer answer) {
char[] moduleName = answer.moduleName();
if (moduleName != null) {
ModuleBinding moduleBinding;
if (!this.useModuleSystem || moduleName == ModuleBinding.UNNAMED) {
moduleBinding = this.UnNamedModule;
} else {
moduleBinding = this.knownModules.get(moduleName);
if (moduleBinding == null && this.nameEnvironment instanceof IModuleAwareNameEnvironment) {
IModule iModule = ((IModuleAwareNameEnvironment) this.nameEnvironment).getModule(moduleName);
try {
this.typeRequestor.accept(iModule, this);
moduleBinding = this.knownModules.get(moduleName);
} catch (NullPointerException e) {
System.err.println("Bug 529367: moduleName: " + new String(moduleName) + "iModule null" + //$NON-NLS-1$ //$NON-NLS-2$
(iModule == null ? "true" : "false")); //$NON-NLS-1$ //$NON-NLS-2$]
throw e;
}
}
}
return moduleBinding;
}
return null;
}
public boolean canTypeBeAccessed(SourceTypeBinding binding, Scope scope) {
ModuleBinding client = scope.module();
return client.canAccess(binding.fPackage);
}
/* Create the initial type bindings for the compilation unit.
*
* See completeTypeBindings() for a description of the remaining steps
*
* NOTE: This method can be called multiple times as additional source files are needed
*/
public void buildTypeBindings(CompilationUnitDeclaration unit, AccessRestriction accessRestriction) {
//{ObjectTeams: wrap to redirect control through dependencies:
Dependencies.ensureState(unit, this, accessRestriction, ITranslationStates.STATE_BINDINGS_BUILT);
}
// for use by Dependencies only:
// PRE: ROLE_FILES_LINKED, because roles files need team to be set.
public void internalBuildTypeBindings(CompilationUnitDeclaration unit, AccessRestriction accessRestriction)
{
// SH}
CompilationUnitScope scope;
ModuleBinding unitModule = null;
if (unit.moduleDeclaration != null) {
char[] moduleName = unit.moduleDeclaration.moduleName;
scope = new CompilationUnitScope(unit, this.globalOptions);
unitModule = unit.moduleDeclaration.setBinding(new SourceModuleBinding(moduleName, scope, this.root));
} else {
if (this.globalOptions.sourceLevel >= ClassFileConstants.JDK9) {
unitModule = unit.module(this);
}
scope = new CompilationUnitScope(unit, unitModule != null ? unitModule.environment : this);
}
scope.buildTypeBindings(accessRestriction);
LookupEnvironment rootEnv = this.root;
int unitsLength = rootEnv.units.length;
if (++rootEnv.lastUnitIndex >= unitsLength)
System.arraycopy(rootEnv.units, 0, rootEnv.units = new CompilationUnitDeclaration[2 * unitsLength], 0, unitsLength);
rootEnv.units[rootEnv.lastUnitIndex] = unit;
}
/* Cache the binary type since we know it is needed during this compile.
*
* Answer the created BinaryTypeBinding or null if the type is already in the cache.
*/
public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, AccessRestriction accessRestriction) {
return cacheBinaryType(binaryType, true, accessRestriction);
}
/* Cache the binary type since we know it is needed during this compile.
*
* Answer the created BinaryTypeBinding or null if the type is already in the cache.
*/
public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, boolean needFieldsAndMethods, AccessRestriction accessRestriction) {
char[][] compoundName = CharOperation.splitOn('/', binaryType.getName());
ReferenceBinding existingType = getCachedType(compoundName);
if (existingType == null || existingType instanceof UnresolvedReferenceBinding)
// only add the binary type if its not already in the cache
return createBinaryTypeFrom(binaryType, computePackageFrom(compoundName, false /* valid pkg */), needFieldsAndMethods, accessRestriction);
return null; // the type already exists & can be retrieved from the cache
}
public void completeTypeBindings() {
if (this != this.root) {
this.root.completeTypeBindings();
return;
}
this.stepCompleted = BUILD_TYPE_HIERARCHY;
for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
//{ObjectTeams: no double treatment:
if (this.units[i].state.getState() < ITranslationStates.STATE_LENV_CHECK_AND_SET_IMPORTS)
// SH}
(this.unitBeingCompleted = this.units[i]).scope.checkAndSetImports();
//{ObjectTeams: record that we are done (don't mark RoFi CUs, have their own imports to process):
StateHelper.setStateRecursive(this.units[i], ITranslationStates.STATE_LENV_CHECK_AND_SET_IMPORTS, false);
//SH}
}
this.stepCompleted = CHECK_AND_SET_IMPORTS;
for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
//{ObjectTeams: extra step and avoid double treatment:
boolean done = false;
Dependencies.checkReadKnownRoles(this.units[i]);
if (this.units[i].state.getState() < ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY) {
// SH}
(this.unitBeingCompleted = this.units[i]).scope.connectTypeHierarchy();
//{ObjectTeams: record that we are done:
done = true;
}
StateHelper.setStateRecursive(this.units[i], ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY, done);
// SH}
}
this.stepCompleted = CONNECT_TYPE_HIERARCHY;
for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
//{ObjectTeams: no double treatment:
boolean done = false;
if (this.units[i].state.getState() < ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS)
{
// SH}
CompilationUnitScope unitScope = (this.unitBeingCompleted = this.units[i]).scope;
unitScope.checkParameterizedTypes();
unitScope.buildFieldsAndMethods();
//{ObjectTeams: record that we are done:
done = true;
}
StateHelper.setStateRecursive(this.units[i], ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS, done);
/* orig: defer to next loop:
this.units[i] = null; // release unnecessary reference to the parsed unit
:giro */
// SH}
}
this.stepCompleted = BUILD_FIELDS_AND_METHODS;
//{ObjectTeams: one more step to handle here:
for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
boolean done = false;
if (this.units[i].state.getState() < ITranslationStates.STATE_ROLES_LINKED) {
RoleSplitter.linkRoles(this.units[i]);
done = true;
}
StateHelper.setStateRecursive(this.units[i], ITranslationStates.STATE_ROLES_LINKED, done);
this.units[i] = null; // release unnecessary reference to the parsed unit
}
this.stepCompleted = ROLES_LINKED;
// SH}
this.lastCompletedUnitIndex = this.lastUnitIndex;
this.unitBeingCompleted = null;
}
/*
* 1. Connect the type hierarchy for the type bindings created for parsedUnits.
* 2. Create the field bindings
* 3. Create the method bindings
*/
/* We know each known compilationUnit is free of errors at this point...
*
* Each step will create additional bindings unless a problem is detected, in which
* case either the faulty import/superinterface/field/method will be skipped or a
* suitable replacement will be substituted (such as Object for a missing superclass)
*/
public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) {
if (this != this.root) {
this.root.completeTypeBindings(parsedUnit);
return;
}
//{ObjectTeams: redirect to Dependencies to process all steps <= stepCompleted
checkConnectTeamToRoFi(parsedUnit);
Dependencies.ensureState(parsedUnit, getDependenciesStateCompleted());
}
// for use by Dependiencies only:
public int internalCompleteTypeBindings(CompilationUnitDeclaration parsedUnit) {
if (this != this.root) {
return this.root.internalCompleteTypeBindings(parsedUnit);
}
if (this.unitBeingCompleted == parsedUnit)
return 0; // avoid re-entrance
int todo = this.stepCompleted;
//SH}
//{ObjectTeams: different last step:
/* orig:
if (this.stepCompleted == BUILD_FIELDS_AND_METHODS) {
:giro */
if (this.stepCompleted == ROLES_LINKED) {
// SH}
// This can only happen because the original set of units are completely built and
// are now being processed, so we want to treat all the additional units as a group
// until they too are completely processed.
completeTypeBindings();
} else {
//{ObjectTeams:
// add return value:
/* orig:
if (parsedUnit.scope == null) return; // parsing errors were too severe
:giro */
if (parsedUnit.scope == null) return 0; // parsing errors were too severe
// request step from encl. team?
if (parsedUnit.isRoleUnit()) { // this implies types[0] exists
SourceTypeBinding roleBinding = parsedUnit.types[0].binding;
if (roleBinding != null) {
ReferenceBinding enclosingType = roleBinding.enclosingType();
if (enclosingType != null) {
TeamModel enclosingTeam = enclosingType.getTeamModel();
if ( enclosingTeam != null
&& enclosingTeam._state.getProcessingState() == ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY)
todo = CONNECT_TYPE_HIERARCHY;
}
}
}
// orig:
if (this.stepCompleted >= CHECK_AND_SET_IMPORTS)
(this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports();
/*
if (this.stepCompleted >= CONNECT_TYPE_HIERARCHY)
:giro */
if (todo >= CONNECT_TYPE_HIERARCHY)
// SH}
(this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy();
//{ObjectTeams: one more step:
if (todo >= ROLES_LINKED)
RoleSplitter.linkRoles(this.unitBeingCompleted = parsedUnit);
// SH}
this.unitBeingCompleted = null;
}
//{ObjectTeams: report actual step achieved:
return todo;
// SH}
}
/*
* Used by other compiler tools which do not start by calling completeTypeBindings().
*
* 1. Connect the type hierarchy for the type bindings created for parsedUnits.
* 2. Create the field bindings
* 3. Create the method bindings
*/
/*
* Each step will create additional bindings unless a problem is detected, in which
* case either the faulty import/superinterface/field/method will be skipped or a
* suitable replacement will be substituted (such as Object for a missing superclass)
*/
public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, boolean buildFieldsAndMethods) {
//{ObjectTeams: redirect to Dependencies:
Config.assertBuildFieldsAndMethods(buildFieldsAndMethods);
Config config = Config.getConfig();
boolean modeSave = config.setBundledCompleteTypeBindingsMode(false);
checkConnectTeamToRoFi(parsedUnit);
Dependencies.ensureState(parsedUnit, ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS);
config.setBundledCompleteTypeBindingsMode(modeSave);
}
void internalCompleteTypeBindings(CompilationUnitDeclaration parsedUnit, int requestedState, boolean buildFieldsAndMethods) {
// SH}
if (parsedUnit.scope == null) return; // parsing errors were too severe
LookupEnvironment rootEnv = this.root;
CompilationUnitDeclaration previousUnitBeingCompleted = rootEnv.unitBeingCompleted;
(rootEnv.unitBeingCompleted = parsedUnit).scope.checkAndSetImports();
parsedUnit.scope.connectTypeHierarchy();
parsedUnit.scope.checkParameterizedTypes();
if (buildFieldsAndMethods)
parsedUnit.scope.buildFieldsAndMethods();
rootEnv.unitBeingCompleted = previousUnitBeingCompleted;
}
/*
* Used by other compiler tools which do not start by calling completeTypeBindings()
* and have more than 1 unit to complete.
*
* 1. Connect the type hierarchy for the type bindings created for parsedUnits.
* 2. Create the field bindings
* 3. Create the method bindings
*/
public void completeTypeBindings(CompilationUnitDeclaration[] parsedUnits, boolean[] buildFieldsAndMethods, int unitCount) {
LookupEnvironment rootEnv = this.root;
for (int i = 0; i < unitCount; i++) {
CompilationUnitDeclaration parsedUnit = parsedUnits[i];
if (parsedUnit.scope != null)
//{ObjectTeams: no double treatment:
if (parsedUnit.state.getState() < ITranslationStates.STATE_LENV_CHECK_AND_SET_IMPORTS)
// SH}
(rootEnv.unitBeingCompleted = parsedUnit).scope.checkAndSetImports();
//{ObjectTeams: record that we are done (don't mark RoFi CUs, have their own imports to process):
StateHelper.setStateRecursive(parsedUnit, ITranslationStates.STATE_LENV_CHECK_AND_SET_IMPORTS, false);
//SH}
}
for (int i = 0; i < unitCount; i++) {
CompilationUnitDeclaration parsedUnit = parsedUnits[i];
if (parsedUnit.scope != null)
//{ObjectTeams: extra step and avoid double treatment:
{
boolean done = false;
Dependencies.checkReadKnownRoles(parsedUnit);
if (parsedUnit.state.getState() < ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY) {
// SH}
(rootEnv.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy();
//{ObjectTeams: record that we are done:
done = true;
}
StateHelper.setStateRecursive(parsedUnit, ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY, done);
}
// SH}
}
for (int i = 0; i < unitCount; i++) {
CompilationUnitDeclaration parsedUnit = parsedUnits[i];
if (parsedUnit.scope != null) {
//{ObjectTeams: no double treatment:
boolean done = false;
if (parsedUnit.state.getState() < ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS)
{
// also roles with anchored baseclass need fields:
if (TypeAnalyzer.containsAnchoredBaseclass(parsedUnit))
buildFieldsAndMethods[i] = true;
// SH}
(rootEnv.unitBeingCompleted = parsedUnit).scope.checkParameterizedTypes();
if (buildFieldsAndMethods[i])
parsedUnit.scope.buildFieldsAndMethods();
//{ObjectTeams: roles *always* need their baseclass:
else
parsedUnit.scope.connectBaseclass();
// record that we are done:
done = true;
}
StateHelper.setStateRecursive(parsedUnit, ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS, done);
// SH}
}
}
rootEnv.unitBeingCompleted = null;
}
public TypeBinding computeBoxingType(TypeBinding type) {
TypeBinding boxedType;
switch (type.id) {
case TypeIds.T_JavaLangBoolean :
return TypeBinding.BOOLEAN;
case TypeIds.T_JavaLangByte :
return TypeBinding.BYTE;
case TypeIds.T_JavaLangCharacter :
return TypeBinding.CHAR;
case TypeIds.T_JavaLangShort :
return TypeBinding.SHORT;
case TypeIds.T_JavaLangDouble :
return TypeBinding.DOUBLE;
case TypeIds.T_JavaLangFloat :
return TypeBinding.FLOAT;
case TypeIds.T_JavaLangInteger :
return TypeBinding.INT;
case TypeIds.T_JavaLangLong :
return TypeBinding.LONG;
case TypeIds.T_int :
boxedType = getType(JAVA_LANG_INTEGER, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_INTEGER, null, NotFound);
case TypeIds.T_byte :
boxedType = getType(JAVA_LANG_BYTE, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_BYTE, null, NotFound);
case TypeIds.T_short :
boxedType = getType(JAVA_LANG_SHORT, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_SHORT, null, NotFound);
case TypeIds.T_char :
boxedType = getType(JAVA_LANG_CHARACTER, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_CHARACTER, null, NotFound);
case TypeIds.T_long :
boxedType = getType(JAVA_LANG_LONG, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_LONG, null, NotFound);
case TypeIds.T_float :
boxedType = getType(JAVA_LANG_FLOAT, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_FLOAT, null, NotFound);
case TypeIds.T_double :
boxedType = getType(JAVA_LANG_DOUBLE, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_DOUBLE, null, NotFound);
case TypeIds.T_boolean :
boxedType = getType(JAVA_LANG_BOOLEAN, javaBaseModule());
if (boxedType != null) return boxedType;
return new ProblemReferenceBinding(JAVA_LANG_BOOLEAN, null, NotFound);
// case TypeIds.T_int :
// return getResolvedType(JAVA_LANG_INTEGER, null);
// case TypeIds.T_byte :
// return getResolvedType(JAVA_LANG_BYTE, null);
// case TypeIds.T_short :
// return getResolvedType(JAVA_LANG_SHORT, null);
// case TypeIds.T_char :
// return getResolvedType(JAVA_LANG_CHARACTER, null);
// case TypeIds.T_long :
// return getResolvedType(JAVA_LANG_LONG, null);
// case TypeIds.T_float :
// return getResolvedType(JAVA_LANG_FLOAT, null);
// case TypeIds.T_double :
// return getResolvedType(JAVA_LANG_DOUBLE, null);
// case TypeIds.T_boolean :
// return getResolvedType(JAVA_LANG_BOOLEAN, null);
}
// allow indirect unboxing conversion for wildcards and type parameters
switch (type.kind()) {
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE :
case Binding.TYPE_PARAMETER :
case Binding.INTERSECTION_TYPE18:
switch (type.erasure().id) {
case TypeIds.T_JavaLangBoolean :
return TypeBinding.BOOLEAN;
case TypeIds.T_JavaLangByte :
return TypeBinding.BYTE;
case TypeIds.T_JavaLangCharacter :
return TypeBinding.CHAR;
case TypeIds.T_JavaLangShort :
return TypeBinding.SHORT;
case TypeIds.T_JavaLangDouble :
return TypeBinding.DOUBLE;
case TypeIds.T_JavaLangFloat :
return TypeBinding.FLOAT;
case TypeIds.T_JavaLangInteger :
return TypeBinding.INT;
case TypeIds.T_JavaLangLong :
return TypeBinding.LONG;
}
break;
case Binding.POLY_TYPE:
return ((PolyTypeBinding) type).computeBoxingType();
}
return type;
}
public ModuleBinding javaBaseModule() {
if (this.JavaBaseModule != null)
return this.JavaBaseModule;
if (this.root != this)
return this.JavaBaseModule = this.root.javaBaseModule();
ModuleBinding resolvedModel = null;
if (this.useModuleSystem)
resolvedModel = getModule(TypeConstants.JAVA_BASE);
return this.JavaBaseModule = (resolvedModel != null ? resolvedModel : this.UnNamedModule); // fall back to pre-Jigsaw view
}
private PackageBinding computePackageFrom(char[][] constantPoolName, boolean isMissing) {
if (constantPoolName.length == 1)
return this.defaultPackage;
PackageBinding packageBinding = getPackage0(constantPoolName[0]);
if (packageBinding == null || packageBinding == TheNotFoundPackage) {
if (this.useModuleSystem) {
if (this.module.isUnnamed()) {
char[][] declaringModules = ((IModuleAwareNameEnvironment) this.nameEnvironment).getUniqueModulesDeclaringPackage(new char[][] {constantPoolName[0]}, ModuleBinding.ANY);
if (declaringModules != null) {
for (char[] mod : declaringModules) {
ModuleBinding declaringModule = this.root.getModule(mod);
if (declaringModule != null)
packageBinding = SplitPackageBinding.combine(declaringModule.getTopLevelPackage(constantPoolName[0]), packageBinding, this.module);
}
}
} else {
packageBinding = this.module.getTopLevelPackage(constantPoolName[0]);
}
}
if (packageBinding == null || packageBinding == TheNotFoundPackage) {
packageBinding = this.module.createDeclaredToplevelPackage(constantPoolName[0]);
}
if (isMissing) packageBinding.tagBits |= TagBits.HasMissingType;
this.knownPackages.put(constantPoolName[0], packageBinding); // TODO: split?
}
for (int i = 1, length = constantPoolName.length - 1; i < length; i++) {
PackageBinding parent = packageBinding;
if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null || packageBinding == TheNotFoundPackage) {
if (this.useModuleSystem) {
if (this.module.isUnnamed()) {
char[][] currentCompoundName = CharOperation.arrayConcat(parent.compoundName, constantPoolName[i]);
char[][] declaringModules = ((IModuleAwareNameEnvironment) this.nameEnvironment).getModulesDeclaringPackage(
currentCompoundName, ModuleBinding.ANY);
if (declaringModules != null) {
for (char[] mod : declaringModules) {
ModuleBinding declaringModule = this.root.getModule(mod);
if (declaringModule != null)
packageBinding = SplitPackageBinding.combine(declaringModule.getVisiblePackage(currentCompoundName), packageBinding, this.module);
}
}
} else {
packageBinding = this.module.getVisiblePackage(parent, constantPoolName[i]);
}
}
if (packageBinding == null || packageBinding == TheNotFoundPackage) {
packageBinding = this.module.createDeclaredPackage(CharOperation.subarray(constantPoolName, 0, i + 1), parent);
}
if (isMissing) {
packageBinding.tagBits |= TagBits.HasMissingType;
}
packageBinding = parent.addPackage(packageBinding, this.module);
}
}
if (packageBinding instanceof SplitPackageBinding) {
PackageBinding candidate = null;
// select from incarnations the unique package containing CUs, if any:
for (PackageBinding incarnation : ((SplitPackageBinding) packageBinding).incarnations) {
if (incarnation.hasCompilationUnit(false)) {
if (candidate != null) {
candidate = null;
break; // likely to report "accessible from more than one module" downstream
}
candidate = incarnation;
}
}
if (candidate != null)
return candidate;
}
return packageBinding;
}
/**
* Convert a given source type into a parameterized form if generic.
* generic X<E> --> param X<E>
*/
public ReferenceBinding convertToParameterizedType(ReferenceBinding originalType) {
if (originalType != null) {
boolean isGeneric = originalType.isGenericType();
if (!isGeneric && !originalType.hasEnclosingInstanceContext())
return originalType;
ReferenceBinding originalEnclosingType = originalType.enclosingType();
ReferenceBinding convertedEnclosingType = originalEnclosingType;
boolean needToConvert = isGeneric;
if (originalEnclosingType != null && originalType.hasEnclosingInstanceContext()) {
convertedEnclosingType = convertToParameterizedType(originalEnclosingType);
needToConvert |= TypeBinding.notEquals(originalEnclosingType, convertedEnclosingType);
}
if (needToConvert) {
return createParameterizedType(originalType, isGeneric ? originalType.typeVariables() : null, convertedEnclosingType);
}
}
return originalType;
}
/**
* Returns the given binding's raw type binding.
* @param type the TypeBinding to raw convert
* @param forceRawEnclosingType forces recursive raw conversion of enclosing types (used in Javadoc references only)
* @return TypeBinding the raw converted TypeBinding
*/
public TypeBinding convertToRawType(TypeBinding type, boolean forceRawEnclosingType) {
int dimension;
TypeBinding originalType;
switch(type.kind()) {
case Binding.BASE_TYPE :
case Binding.TYPE_PARAMETER:
case Binding.WILDCARD_TYPE:
case Binding.INTERSECTION_TYPE:
case Binding.RAW_TYPE:
return type;
case Binding.ARRAY_TYPE:
dimension = type.dimensions();
originalType = type.leafComponentType();
break;
default:
if (type.id == TypeIds.T_JavaLangObject)
return type; // Object is not generic
dimension = 0;
originalType = type;
}
boolean needToConvert;
switch (originalType.kind()) {
case Binding.BASE_TYPE :
return type;
case Binding.GENERIC_TYPE :
needToConvert = true;
break;
case Binding.PARAMETERIZED_TYPE :
ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) originalType;
needToConvert = paramType.genericType().isGenericType(); // only recursive call to enclosing type can find parameterizedType with arguments
break;
default :
needToConvert = false;
break;
}
forceRawEnclosingType &= !originalType.isStatic();
ReferenceBinding originalEnclosing = originalType.enclosingType();
TypeBinding convertedType;
if (originalEnclosing == null) {
convertedType = needToConvert ? createRawType((ReferenceBinding)originalType.erasure(), null) : originalType;
} else {
ReferenceBinding convertedEnclosing;
if (!((ReferenceBinding)originalType).hasEnclosingInstanceContext()) {
convertedEnclosing = (ReferenceBinding) originalEnclosing.original();
} else {
if (originalEnclosing.kind() == Binding.RAW_TYPE) {
convertedEnclosing = originalEnclosing;
needToConvert = true;
} else if (forceRawEnclosingType && !needToConvert/*stop recursion when conversion occurs*/) {
convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing, forceRawEnclosingType);
needToConvert = TypeBinding.notEquals(originalEnclosing, convertedEnclosing); // only convert generic or parameterized types
} else if (needToConvert) {
convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing, false);
} else {
convertedEnclosing = convertToParameterizedType(originalEnclosing);
}
}
if (needToConvert) {
convertedType = createRawType((ReferenceBinding) originalType.erasure(), convertedEnclosing);
} else if (TypeBinding.notEquals(originalEnclosing, convertedEnclosing)) {
convertedType = createParameterizedType((ReferenceBinding) originalType.erasure(), null, convertedEnclosing);
} else {
convertedType = originalType;
}
}
if (TypeBinding.notEquals(originalType, convertedType)) {
return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType;
}
return type;
}
/**
* Convert an array of types in raw forms.
* Only allocate an array if anything is different.
*/
public ReferenceBinding[] convertToRawTypes(ReferenceBinding[] originalTypes, boolean forceErasure, boolean forceRawEnclosingType) {
if (originalTypes == null) return null;
ReferenceBinding[] convertedTypes = originalTypes;
for (int i = 0, length = originalTypes.length; i < length; i++) {
ReferenceBinding originalType = originalTypes[i];
ReferenceBinding convertedType = (ReferenceBinding) convertToRawType(forceErasure ? originalType.erasure() : originalType, forceRawEnclosingType);
if (TypeBinding.notEquals(convertedType, originalType)) {
if (convertedTypes == originalTypes) {
System.arraycopy(originalTypes, 0, convertedTypes = new ReferenceBinding[length], 0, i);
}
convertedTypes[i] = convertedType;
} else if (convertedTypes != originalTypes) {
convertedTypes[i] = originalType;
}
}
return convertedTypes;
}
// variation for unresolved types in binaries (consider generic type as raw)
public TypeBinding convertUnresolvedBinaryToRawType(TypeBinding type) {
int dimension;
TypeBinding originalType;
switch(type.kind()) {
case Binding.BASE_TYPE :
case Binding.TYPE_PARAMETER:
case Binding.WILDCARD_TYPE:
case Binding.INTERSECTION_TYPE:
case Binding.RAW_TYPE:
return type;
case Binding.ARRAY_TYPE:
dimension = type.dimensions();
originalType = type.leafComponentType();
break;
default:
if (type.id == TypeIds.T_JavaLangObject)
return type; // Object is not generic
dimension = 0;
originalType = type;
}
boolean needToConvert;
switch (originalType.kind()) {
case Binding.BASE_TYPE :
return type;
case Binding.GENERIC_TYPE :
needToConvert = true;
break;
case Binding.PARAMETERIZED_TYPE :
ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) originalType;
needToConvert = paramType.genericType().isGenericType(); // only recursive call to enclosing type can find parameterizedType with arguments
break;
default :
needToConvert = false;
break;
}
ReferenceBinding originalEnclosing = originalType.enclosingType();
TypeBinding convertedType;
if (originalEnclosing == null) {
convertedType = needToConvert ? createRawType((ReferenceBinding)originalType.erasure(), null) : originalType;
} else {
if (!needToConvert && originalType.isStatic())
return originalType;
ReferenceBinding convertedEnclosing = (ReferenceBinding) convertUnresolvedBinaryToRawType(originalEnclosing);
if (TypeBinding.notEquals(convertedEnclosing, originalEnclosing)) {
needToConvert = true;
}
if (needToConvert) {
convertedType = createRawType((ReferenceBinding) originalType.erasure(), convertedEnclosing);
} else {
convertedType = originalType;
}
}
if (TypeBinding.notEquals(originalType, convertedType)) {
return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType;
}
return type;
}
/* Used to guarantee annotation identity: we do that only for marker annotations and others with all default values.
We don't have the machinery for the general case as of now.
*/
public AnnotationBinding createAnnotation(ReferenceBinding annotationType, ElementValuePair[] pairs) {
if (pairs.length != 0) {
AnnotationBinding.setMethodBindings(annotationType, pairs);
return new AnnotationBinding(annotationType, pairs);
}
return this.typeSystem.getAnnotationType(annotationType, true);
}
/* Used to guarantee annotation identity: we do that only for marker annotations and others with all default values.
We don't have the machinery for the general case as of now.
*/
public AnnotationBinding createUnresolvedAnnotation(ReferenceBinding annotationType, ElementValuePair[] pairs) {
if (pairs.length != 0) {
return new UnresolvedAnnotationBinding(annotationType, pairs, this);
}
return this.typeSystem.getAnnotationType(annotationType, false);
}
/*
* Used to guarantee array type identity.
*/
public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount) {
return this.typeSystem.getArrayType(leafComponentType, dimensionCount);
}
public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount, AnnotationBinding [] annotations) {
return this.typeSystem.getArrayType(leafComponentType, dimensionCount, annotations);
}
public TypeBinding createIntersectionType18(ReferenceBinding[] intersectingTypes) {
if (!intersectingTypes[0].isClass()) {
Arrays.sort(intersectingTypes, new Comparator<TypeBinding>() {
@Override
public int compare(TypeBinding o1, TypeBinding o2) {
//
return o1.isClass() ? -1 : (o2.isClass() ? 1 : CharOperation.compareTo(o1.readableName(), o2.readableName()));
}
});
}
return this.typeSystem.getIntersectionType18(intersectingTypes);
}
public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
return createBinaryTypeFrom(binaryType, packageBinding, true, accessRestriction);
}
public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, boolean needFieldsAndMethods, AccessRestriction accessRestriction) {
if (this != packageBinding.environment)
return packageBinding.environment.createBinaryTypeFrom(binaryType, packageBinding, needFieldsAndMethods, accessRestriction);
BinaryTypeBinding binaryBinding = new BinaryTypeBinding(packageBinding, binaryType, this);
// resolve any array bindings which reference the unresolvedType
ReferenceBinding cachedType = packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]);
if (cachedType != null && !cachedType.isUnresolvedType()) {
if (cachedType.isBinaryBinding()) // sanity check... at this point the cache should ONLY contain unresolved types
return (BinaryTypeBinding) cachedType;
// it is possible with a large number of source files (exceeding AbstractImageBuilder.MAX_AT_ONCE) that a member type can be in the cache as an UnresolvedType,
// but because its enclosingType is resolved while its created (call to BinaryTypeBinding constructor), its replaced with a source type
return null;
}
packageBinding.addType(binaryBinding);
setAccessRestriction(binaryBinding, accessRestriction);
binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods);
return binaryBinding;
}
/*
* Used to create types denoting missing types.
* If package is given, then reuse the package; if not then infer a package from compound name.
* If the package is existing, then install the missing type in type cache
*/
public MissingTypeBinding createMissingType(PackageBinding packageBinding, char[][] compoundName) {
// create a proxy for the missing BinaryType
if (packageBinding == null) {
packageBinding = computePackageFrom(compoundName, true /* missing */);
if (packageBinding == TheNotFoundPackage) packageBinding = this.defaultPackage;
}
MissingTypeBinding missingType = new MissingTypeBinding(packageBinding, compoundName, this);
if (missingType.id != TypeIds.T_JavaLangObject) {
// make Object be its superclass - it could in turn be missing as well
ReferenceBinding objectType = getType(TypeConstants.JAVA_LANG_OBJECT, javaBaseModule());
if (objectType == null) {
objectType = createMissingType(null, TypeConstants.JAVA_LANG_OBJECT); // create a proxy for the missing Object type
}
missingType.setMissingSuperclass(objectType);
}
packageBinding.addType(missingType);
if (this.missingTypes == null)
this.missingTypes = new ArrayList(3);
this.missingTypes.add(missingType);
return missingType;
}
/*
* 1. Connect the type hierarchy for the type bindings created for parsedUnits.
* 2. Create the field bindings
* 3. Create the method bindings
*/
public PackageBinding createPackage(char[][] compoundName) {
return createPlainPackage(compoundName);
}
public PlainPackageBinding createPlainPackage(char[][] compoundName) {
//{ObjectTeams: JDT didn't detect collision for toplevel type/package, because default package is weird ;-)
// however, for OT/J we must change this to detect matching team package even at top-level.
if (compoundName.length == 1) {
ReferenceBinding foundType = this.defaultPackage.getType0(compoundName[0]);
if (foundType!= null && foundType != TheNotFoundType)
return null;
}
// SH}
PackageBinding packageBinding = this.module.getDeclaredPackage(CharOperation.concatWith(compoundName, '.'));
if (packageBinding != null && packageBinding.isValidBinding()) {
// restart from the toplevel package to proceed with clash analysis below
packageBinding = this.getTopLevelPackage(compoundName[0]);
} else {
packageBinding = getPackage0(compoundName[0]);
if (packageBinding == null || packageBinding == TheNotFoundPackage) {
packageBinding = this.module.getOrCreateDeclaredPackage(new char[][] {compoundName[0]});
if (this.useModuleSystem) {
char[][] declaringModuleNames = null;
if (this.module.isUnnamed()) {
IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.nameEnvironment;
declaringModuleNames = moduleEnv.getUniqueModulesDeclaringPackage(new char[][] {packageBinding.readableName()}, ModuleBinding.ANY);
}
packageBinding = this.module.combineWithPackagesFromOtherRelevantModules(packageBinding, packageBinding.compoundName, declaringModuleNames);
}
this.knownPackages.put(compoundName[0], packageBinding); // update in case of split package
}
}
for (int i = 1, length = compoundName.length; i < length; i++) {
// check to see if it collides with a known type...
// this case can only happen if the package does not exist as a directory in the file system
// otherwise when the source type was defined, the correct error would have been reported
// unless its an unresolved type which is referenced from an inconsistent class file
// NOTE: empty packages are not packages according to changes in JLS v2, 7.4.3
// so not all types cause collision errors when they're created even though the package did exist
if (packageBinding.hasType0Any(compoundName[i]))
return null;
PackageBinding parent = packageBinding;
if ((packageBinding = parent.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage) {
// if the package is unknown, check to see if a type exists which would collide with the new package
// catches the case of a package statement of: package java.lang.Object;
// since the package can be added after a set of source files have already been compiled,
// we need to check whenever a package is created
if(this.nameEnvironment instanceof INameEnvironmentExtension) {
//When the nameEnvironment is an instance of INameEnvironmentWithProgress, it can get avoided to search for secondaryTypes (see flag).
// This is a performance optimization, because it is very expensive to search for secondary types and it isn't necessary to check when creating a package,
// because package name can not collide with a secondary type name.
if (((INameEnvironmentExtension)this.nameEnvironment).findType(compoundName[i], parent.compoundName, false, this.module.nameForLookup()) != null) {
return null;
}
} else {
if (this.nameEnvironment.findType(compoundName[i], parent.compoundName) != null) {
return null;
}
}
PackageBinding singleParent = parent.getIncarnation(this.module);
if (singleParent != parent && singleParent != null) {
// parent.getPackage0() may have been too shy, so drill into the split:
packageBinding = singleParent.getPackage0(compoundName[i]);
}
if (packageBinding == null) {
packageBinding = this.module.createDeclaredPackage(CharOperation.subarray(compoundName, 0, i + 1), parent);
packageBinding = parent.addPackage(packageBinding, this.module);
}
}
}
return packageBinding.getIncarnation(this.module);
}
public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, RawTypeBinding rawType) {
// cached info is array of already created parameterized types for this type
ParameterizedGenericMethodBinding[] cachedInfo = (ParameterizedGenericMethodBinding[])this.uniqueParameterizedGenericMethodBindings.get(genericMethod);
boolean needToGrow = false;
int index = 0;
if (cachedInfo != null){
nextCachedMethod :
// iterate existing parameterized for reusing one with same type arguments if any
for (int max = cachedInfo.length; index < max; index++){
ParameterizedGenericMethodBinding cachedMethod = cachedInfo[index];
if (cachedMethod == null) break nextCachedMethod;
if (!cachedMethod.isRaw) continue nextCachedMethod;
if (cachedMethod.declaringClass != (rawType == null ? genericMethod.declaringClass : rawType)) continue nextCachedMethod; //$IDENTITY-COMPARISON$
return cachedMethod;
}
needToGrow = true;
} else {
cachedInfo = new ParameterizedGenericMethodBinding[5];
this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo);
}
// grow cache ?
int length = cachedInfo.length;
if (needToGrow && index == length){
System.arraycopy(cachedInfo, 0, cachedInfo = new ParameterizedGenericMethodBinding[length*2], 0, length);
this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo);
}
// add new binding
ParameterizedGenericMethodBinding parameterizedGenericMethod = new ParameterizedGenericMethodBinding(genericMethod, rawType, this);
cachedInfo[index] = parameterizedGenericMethod;
return parameterizedGenericMethod;
}
public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, TypeBinding[] typeArguments) {
return createParameterizedGenericMethod(genericMethod, typeArguments, null);
}
public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, TypeBinding[] typeArguments, TypeBinding targetType) {
return createParameterizedGenericMethod(genericMethod, typeArguments, false, false, targetType);
}
public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, TypeBinding[] typeArguments,
boolean inferredWithUncheckedConversion, boolean hasReturnProblem, TypeBinding targetType)
{
// cached info is array of already created parameterized types for this type
ParameterizedGenericMethodBinding[] cachedInfo = (ParameterizedGenericMethodBinding[])this.uniqueParameterizedGenericMethodBindings.get(genericMethod);
int argLength = typeArguments == null ? 0: typeArguments.length;
boolean needToGrow = false;
int index = 0;
if (cachedInfo != null){
nextCachedMethod :
// iterate existing parameterized for reusing one with same type arguments if any
for (int max = cachedInfo.length; index < max; index++){
ParameterizedGenericMethodBinding cachedMethod = cachedInfo[index];
if (cachedMethod == null) break nextCachedMethod;
if (cachedMethod.isRaw) continue nextCachedMethod;
if (cachedMethod.targetType != targetType) continue nextCachedMethod; //$IDENTITY-COMPARISON$
if (cachedMethod.inferredWithUncheckedConversion != inferredWithUncheckedConversion) continue nextCachedMethod;
TypeBinding[] cachedArguments = cachedMethod.typeArguments;
int cachedArgLength = cachedArguments == null ? 0 : cachedArguments.length;
if (argLength != cachedArgLength) continue nextCachedMethod;
for (int j = 0; j < cachedArgLength; j++){
if (typeArguments[j] != cachedArguments[j]) continue nextCachedMethod; //$IDENTITY-COMPARISON$
}
if (inferredWithUncheckedConversion) { // JSL 18.5.2: "If unchecked conversion was necessary..."
// don't tolerate remaining parameterized types / type variables, should have been eliminated by erasure:
if (cachedMethod.returnType.isParameterizedType() || cachedMethod.returnType.isTypeVariable()) continue;
for (TypeBinding exc : cachedMethod.thrownExceptions)
if (exc.isParameterizedType() || exc.isTypeVariable()) continue nextCachedMethod;
}
// all arguments match, reuse current
return cachedMethod;
}
needToGrow = true;
} else {
cachedInfo = new ParameterizedGenericMethodBinding[5];
this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo);
}
// grow cache ?
int length = cachedInfo.length;
if (needToGrow && index == length){
System.arraycopy(cachedInfo, 0, cachedInfo = new ParameterizedGenericMethodBinding[length*2], 0, length);
this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo);
}
// add new binding
ParameterizedGenericMethodBinding parameterizedGenericMethod =
new ParameterizedGenericMethodBinding(genericMethod, typeArguments, this, inferredWithUncheckedConversion, hasReturnProblem, targetType);
cachedInfo[index] = parameterizedGenericMethod;
return parameterizedGenericMethod;
}
public PolymorphicMethodBinding createPolymorphicMethod(MethodBinding originalPolymorphicMethod, TypeBinding[] parameters, Scope scope) {
// cached info is array of already created polymorphic methods for this type
String key = new String(originalPolymorphicMethod.selector);
PolymorphicMethodBinding[] cachedInfo = (PolymorphicMethodBinding[]) this.uniquePolymorphicMethodBindings.get(key);
int parametersLength = parameters == null ? 0: parameters.length;
TypeBinding[] parametersTypeBinding = new TypeBinding[parametersLength];
for (int i = 0; i < parametersLength; i++) {
TypeBinding parameterTypeBinding = parameters[i];
if (parameterTypeBinding.id == TypeIds.T_null) {
parametersTypeBinding[i] = getType(JAVA_LANG_VOID, javaBaseModule());
} else {
if (parameterTypeBinding.isPolyType()) {
PolyTypeBinding ptb = (PolyTypeBinding) parameterTypeBinding;
if (scope instanceof BlockScope && ptb.expression.resolvedType == null) {
ptb.expression.setExpectedType(scope.getJavaLangObject());
parametersTypeBinding[i] = ptb.expression.resolveType((BlockScope) scope);
} else {
parametersTypeBinding[i] = ptb.expression.resolvedType;
}
} else {
parametersTypeBinding[i] = parameterTypeBinding.erasure();
}
}
}
boolean needToGrow = false;
int index = 0;
if (cachedInfo != null) {
nextCachedMethod :
// iterate existing polymorphic method for reusing one with same type arguments if any
for (int max = cachedInfo.length; index < max; index++) {
PolymorphicMethodBinding cachedMethod = cachedInfo[index];
if (cachedMethod == null) {
break nextCachedMethod;
}
if (cachedMethod.matches(parametersTypeBinding, originalPolymorphicMethod.returnType)) {
return cachedMethod;
}
}
needToGrow = true;
} else {
cachedInfo = new PolymorphicMethodBinding[5];
this.uniquePolymorphicMethodBindings.put(key, cachedInfo);
}
// grow cache ?
int length = cachedInfo.length;
if (needToGrow && index == length) {
System.arraycopy(cachedInfo, 0, cachedInfo = new PolymorphicMethodBinding[length*2], 0, length);
this.uniquePolymorphicMethodBindings.put(key, cachedInfo);
}
// add new binding
PolymorphicMethodBinding polymorphicMethod = new PolymorphicMethodBinding(
originalPolymorphicMethod,
parametersTypeBinding);
cachedInfo[index] = polymorphicMethod;
return polymorphicMethod;
}
public boolean usesAnnotatedTypeSystem() {
return this.typeSystem.isAnnotatedTypeSystem();
}
public MethodBinding updatePolymorphicMethodReturnType(PolymorphicMethodBinding binding, TypeBinding typeBinding) {
// update the return type to be the given return type, but reuse existing binding if one can match
String key = new String(binding.selector);
PolymorphicMethodBinding[] cachedInfo = (PolymorphicMethodBinding[]) this.uniquePolymorphicMethodBindings.get(key);
boolean needToGrow = false;
int index = 0;
TypeBinding[] parameters = binding.parameters;
if (cachedInfo != null) {
nextCachedMethod :
// iterate existing polymorphic method for reusing one with same type arguments if any
for (int max = cachedInfo.length; index < max; index++) {
PolymorphicMethodBinding cachedMethod = cachedInfo[index];
if (cachedMethod == null) {
break nextCachedMethod;
}
if (cachedMethod.matches(parameters, typeBinding)) {
return cachedMethod;
}
}
needToGrow = true;
} else {
cachedInfo = new PolymorphicMethodBinding[5];
this.uniquePolymorphicMethodBindings.put(key, cachedInfo);
}
// grow cache ?
int length = cachedInfo.length;
if (needToGrow && index == length) {
System.arraycopy(cachedInfo, 0, cachedInfo = new PolymorphicMethodBinding[length*2], 0, length);
this.uniquePolymorphicMethodBindings.put(key, cachedInfo);
}
// add new binding
PolymorphicMethodBinding polymorphicMethod = new PolymorphicMethodBinding(
binding.original(),
typeBinding,
parameters);
cachedInfo[index] = polymorphicMethod;
return polymorphicMethod;
}
public ParameterizedMethodBinding createGetClassMethod(TypeBinding receiverType, MethodBinding originalMethod, Scope scope) {
// see if we have already cached this method for the given receiver type.
ParameterizedMethodBinding retVal = null;
if (this.uniqueGetClassMethodBinding == null) {
this.uniqueGetClassMethodBinding = new SimpleLookupTable(3);
} else {
retVal = (ParameterizedMethodBinding)this.uniqueGetClassMethodBinding.get(receiverType);
}
if (retVal == null) {
retVal = ParameterizedMethodBinding.instantiateGetClass(receiverType, originalMethod, scope);
this.uniqueGetClassMethodBinding.put(receiverType, retVal);
}
return retVal;
}
public ReferenceBinding createMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) {
return this.typeSystem.getMemberType(memberType, enclosingType);
}
public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
AnnotationBinding[] annotations = genericType.typeAnnotations;
if (annotations != Binding.NO_ANNOTATIONS)
//{ObjectTeams: additional parameters: for dependent types:
/* orig:
return this.typeSystem.getParameterizedType((ReferenceBinding) genericType.unannotated(), typeArguments, enclosingType, annotations);
return this.typeSystem.getParameterizedType(genericType, typeArguments, enclosingType);
:giro */
return this.typeSystem.getParameterizedType((ReferenceBinding) genericType.unannotated(), typeArguments, null, -1, enclosingType, annotations);
return this.typeSystem.getParameterizedType(genericType, typeArguments, null, -1, enclosingType);
// SH}
}
public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
//{ObjectTeams: additional parameters: for dependent types:
/* orig:
return this.typeSystem.getParameterizedType(genericType, typeArguments, enclosingType, annotations);
:giro */
return this.typeSystem.getParameterizedType(genericType, typeArguments, null, -1, enclosingType, annotations);
// SH}
}
//{ObjectTeams: for anchored role types:
public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments,
ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
if (teamAnchor != null) {
genericType = genericType.getRealType();
}
switch (genericType.kind()) {
case Binding.TYPE_PARAMETER:
break;
case Binding.PARAMETERIZED_TYPE:
case Binding.RAW_TYPE:
genericType = genericType.actualType();
//$FALL-THROUGH$
case Binding.TYPE:
case Binding.GENERIC_TYPE:
genericType = (ReferenceBinding) genericType.prototype();
}
return this.typeSystem.getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType, annotations);
}
// SH}
public ReferenceBinding maybeCreateParameterizedType(ReferenceBinding nonGenericType, ReferenceBinding enclosingType) {
boolean canSeeEnclosingTypeParameters = enclosingType != null
&& (enclosingType.isParameterizedType() | enclosingType.isRawType())
&& !nonGenericType.isStatic();
if (canSeeEnclosingTypeParameters)
return createParameterizedType(nonGenericType, null, enclosingType);
return nonGenericType;
}
public TypeBinding createAnnotatedType(TypeBinding type, AnnotationBinding[][] annotations) {
return this.typeSystem.getAnnotatedType(type, annotations);
}
// Variant to handle incoming type possibly carrying annotations.
public TypeBinding createAnnotatedType(TypeBinding type, AnnotationBinding[] newbies) {
final int newLength = newbies == null ? 0 : newbies.length;
if (type == null || newLength == 0)
return type;
AnnotationBinding [] oldies = type.getTypeAnnotations();
final int oldLength = oldies == null ? 0 : oldies.length;
if (oldLength > 0) {
System.arraycopy(newbies, 0, newbies = new AnnotationBinding[newLength + oldLength], 0, newLength);
System.arraycopy(oldies, 0, newbies, newLength, oldLength);
}
if (this.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
// filter duplicate null annotations
// (do we want to filter other annotations as well? only if not repeatable?)
long tagBitsSeen = 0;
AnnotationBinding[] filtered = new AnnotationBinding[newbies.length];
int count = 0;
for (int i = 0; i < newbies.length; i++) {
if (newbies[i] == null) {
filtered[count++] = null;
// reset tagBitsSeen for next array dimension
tagBitsSeen = 0;
continue;
}
long tagBits = 0;
if (newbies[i].type.hasNullBit(TypeIds.BitNonNullAnnotation)) {
tagBits = TagBits.AnnotationNonNull;
} else if (newbies[i].type.hasNullBit(TypeIds.BitNullableAnnotation)) {
tagBits = TagBits.AnnotationNullable;
}
if ((tagBitsSeen & tagBits) == 0) {
tagBitsSeen |= tagBits;
filtered[count++] = newbies[i];
}
}
if (count < newbies.length)
System.arraycopy(filtered, 0, newbies = new AnnotationBinding[count], 0, count);
}
return this.typeSystem.getAnnotatedType(type, new AnnotationBinding [][] { newbies });
}
public RawTypeBinding createRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) {
AnnotationBinding[] annotations = genericType.typeAnnotations;
if (annotations != Binding.NO_ANNOTATIONS)
return this.typeSystem.getRawType((ReferenceBinding) genericType.unannotated(), enclosingType, annotations);
return this.typeSystem.getRawType(genericType, enclosingType);
}
public RawTypeBinding createRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
return this.typeSystem.getRawType(genericType, enclosingType, annotations);
}
public WildcardBinding createWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
if (genericType != null) {
AnnotationBinding[] annotations = genericType.typeAnnotations;
if (annotations != Binding.NO_ANNOTATIONS)
return this.typeSystem.getWildcard((ReferenceBinding) genericType.unannotated(), rank, bound, otherBounds, boundKind, annotations);
}
return this.typeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind);
}
public CaptureBinding createCapturedWildcard(WildcardBinding wildcard, ReferenceBinding contextType, int start, int end, ASTNode cud, int id) {
return this.typeSystem.getCapturedWildcard(wildcard, contextType, start, end, cud, id);
}
public WildcardBinding createWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding [] annotations) {
return this.typeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind, annotations);
}
/**
* Returns the access restriction associated to a given type, or null if none
*/
public AccessRestriction getAccessRestriction(TypeBinding type) {
return (AccessRestriction) this.accessRestrictions.get(type);
}
/**
* Answer the type for the compoundName if it exists in the cache.
* Answer theNotFoundType if it could not be resolved the first time
* it was looked up, otherwise answer null.
*
* NOTE: Do not use for nested types... the answer is NOT the same for a.b.C or a.b.C.D.E
* assuming C is a type in both cases. In the a.b.C.D.E case, null is the answer.
*/
public ReferenceBinding getCachedType(char[][] compoundName) {
ReferenceBinding result = getCachedType0(compoundName);
if (result == null && this.useModuleSystem) {
ModuleBinding[] modulesToSearch = this.module.isUnnamed() || this.module.isAuto
? this.root.knownModules.valueTable
: this.module.getAllRequiredModules();
for (ModuleBinding someModule : modulesToSearch) {
if (someModule == null) continue;
result = someModule.environment.getCachedType0(compoundName);
if (result != null && result.isValidBinding())
break;
}
}
return result;
}
public ReferenceBinding getCachedType0(char[][] compoundName) {
if (compoundName.length == 1) {
return this.defaultPackage.getType0(compoundName[0]);
}
PackageBinding packageBinding = getPackage0(compoundName[0]);
if (packageBinding == null || packageBinding == TheNotFoundPackage)
return null;
// we should be asking via the correct LE, so peel any SPB at the root:
packageBinding = packageBinding.getIncarnation(this.module);
if (packageBinding == null || packageBinding == TheNotFoundPackage)
return null;
for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++)
if ((packageBinding = packageBinding.getPackage0Any(compoundName[i])) == null || packageBinding == TheNotFoundPackage)
return null;
return packageBinding.getType0(compoundName[compoundName.length - 1]);
}
public AnnotationBinding getNullableAnnotation() {
if (this.nullableAnnotation != null)
return this.nullableAnnotation;
if (this.root != this) {
return this.nullableAnnotation = this.root.getNullableAnnotation();
}
ReferenceBinding nullable = getResolvedType(this.globalOptions.nullableAnnotationName, null);
return this.nullableAnnotation = this.typeSystem.getAnnotationType(nullable, true);
}
public char[][] getNullableAnnotationName() {
return this.globalOptions.nullableAnnotationName;
}
public AnnotationBinding getNonNullAnnotation() {
if (this.nonNullAnnotation != null)
return this.nonNullAnnotation;
if (this.root != this) {
return this.nonNullAnnotation = this.root.getNonNullAnnotation();
}
ReferenceBinding nonNull = getResolvedType(this.globalOptions.nonNullAnnotationName, this.UnNamedModule, null, true);
return this.nonNullAnnotation = this.typeSystem.getAnnotationType(nonNull, true);
}
public AnnotationBinding[] nullAnnotationsFromTagBits(long nullTagBits) {
if (nullTagBits == TagBits.AnnotationNonNull)
return new AnnotationBinding[] { getNonNullAnnotation() };
else if (nullTagBits == TagBits.AnnotationNullable)
return new AnnotationBinding[] { getNullableAnnotation() };
return null;
}
public char[][] getNonNullAnnotationName() {
return this.globalOptions.nonNullAnnotationName;
}
public char[][] getNonNullByDefaultAnnotationName() {
return this.globalOptions.nonNullByDefaultAnnotationName;
}
int getNullAnnotationBit(char[][] qualifiedTypeName) {
if (this.allNullAnnotations == null) {
this.allNullAnnotations = new HashMap<>();
this.allNullAnnotations.put(CharOperation.toString(this.globalOptions.nonNullAnnotationName), TypeIds.BitNonNullAnnotation);
this.allNullAnnotations.put(CharOperation.toString(this.globalOptions.nullableAnnotationName), TypeIds.BitNullableAnnotation);
this.allNullAnnotations.put(CharOperation.toString(this.globalOptions.nonNullByDefaultAnnotationName), TypeIds.BitNonNullByDefaultAnnotation);
for (String name : this.globalOptions.nullableAnnotationSecondaryNames)
this.allNullAnnotations.put(name, TypeIds.BitNullableAnnotation);
for (String name : this.globalOptions.nonNullAnnotationSecondaryNames)
this.allNullAnnotations.put(name, TypeIds.BitNonNullAnnotation);
for (String name : this.globalOptions.nonNullByDefaultAnnotationSecondaryNames)
this.allNullAnnotations.put(name, TypeIds.BitNonNullByDefaultAnnotation);
}
String qualifiedTypeString = CharOperation.toString(qualifiedTypeName);
Integer typeBit = this.allNullAnnotations.get(qualifiedTypeString);
return typeBit == null ? 0 : typeBit;
}
public boolean isNullnessAnnotationPackage(PackageBinding pkg) {
return this.nonnullAnnotationPackage == pkg || this.nullableAnnotationPackage == pkg || this.nonnullByDefaultAnnotationPackage == pkg;
}
public boolean usesNullTypeAnnotations() {
if(this.root != this) {
return this.root.usesNullTypeAnnotations();
}
if (this.globalOptions.useNullTypeAnnotations != null)
return this.globalOptions.useNullTypeAnnotations;
initializeUsesNullTypeAnnotation();
for (MethodBinding enumMethod : this.deferredEnumMethods) {
int purpose = 0;
if (CharOperation.equals(enumMethod.selector, TypeConstants.VALUEOF)) {
purpose = SyntheticMethodBinding.EnumValueOf;
} else if (CharOperation.equals(enumMethod.selector, TypeConstants.VALUES)) {
purpose = SyntheticMethodBinding.EnumValues;
}
if (purpose != 0)
SyntheticMethodBinding.markNonNull(enumMethod, purpose, this);
}
this.deferredEnumMethods.clear();
return this.globalOptions.useNullTypeAnnotations;
}
private void initializeUsesNullTypeAnnotation() {
this.globalOptions.useNullTypeAnnotations = Boolean.FALSE;
if (!this.globalOptions.isAnnotationBasedNullAnalysisEnabled || this.globalOptions.originalSourceLevel < ClassFileConstants.JDK1_8)
return;
ReferenceBinding nullable;
ReferenceBinding nonNull;
boolean origMayTolerateMissingType = this.mayTolerateMissingType;
this.mayTolerateMissingType = true;
try {
nullable = this.nullableAnnotation != null ? this.nullableAnnotation.getAnnotationType()
: getType(this.getNullableAnnotationName(), this.UnNamedModule); // FIXME(SHMOD) module for null annotations??
nonNull = this.nonNullAnnotation != null ? this.nonNullAnnotation.getAnnotationType()
: getType(this.getNonNullAnnotationName(), this.UnNamedModule);
} finally {
this.mayTolerateMissingType = origMayTolerateMissingType;
}
if (nullable == null && nonNull == null)
return;
if (nullable == null || nonNull == null)
return; // TODO should report an error about inconsistent setup
long nullableMetaBits = nullable.getAnnotationTagBits() & TagBits.AnnotationForTypeUse;
long nonNullMetaBits = nonNull.getAnnotationTagBits() & TagBits.AnnotationForTypeUse;
if (nullableMetaBits != nonNullMetaBits)
return; // TODO should report an error about inconsistent setup
if (nullableMetaBits == 0)
return;
this.globalOptions.useNullTypeAnnotations = Boolean.TRUE;
}
/* Answer the top level package named name if it exists in the cache.
* Answer theNotFoundPackage if it could not be resolved the first time
* it was looked up, otherwise answer null.
*
* NOTE: Senders must convert theNotFoundPackage into a real problem
* package if its to returned.
*/
PackageBinding getPackage0(char[] name) {
return this.knownPackages.get(name);
}
/* Answer the type corresponding to the compoundName.
* Ask the name environment for the type if its not in the cache.
* Fail with a classpath error if the type cannot be found.
*/
public ReferenceBinding getResolvedType(char[][] compoundName, Scope scope) {
return getResolvedType(compoundName, scope == null ? this.UnNamedModule : scope.module(), scope, false);
}
public ReferenceBinding getResolvedType(char[][] compoundName, ModuleBinding moduleBinding, Scope scope, boolean implicitAnnotationUse) {
if (this.module != moduleBinding)
return moduleBinding.environment.getResolvedType(compoundName, moduleBinding, scope, implicitAnnotationUse);
ReferenceBinding type = getType(compoundName, moduleBinding);
if (type != null) return type;
// create a proxy for the missing BinaryType
// report the missing class file first
this.problemReporter.isClassPathCorrect(
compoundName,
scope == null ? this.root.unitBeingCompleted : scope.referenceCompilationUnit(),
this.missingClassFileLocation, implicitAnnotationUse);
return createMissingType(null, compoundName);
}
public ReferenceBinding getResolvedJavaBaseType(char[][] compoundName, Scope scope) {
return getResolvedType(compoundName, javaBaseModule(), scope, false);
}
/* Answer the top level package named name.
* Ask the oracle for the package if its not in the cache.
* Answer null if the package cannot be found.
*/
PackageBinding getTopLevelPackage(char[] name) {
if (this.useModuleSystem) {
return this.module.getTopLevelPackage(name);
}
PackageBinding packageBinding = getPackage0(name);
if (packageBinding != null) {
if (packageBinding == TheNotFoundPackage)
return null;
return packageBinding;
}
if (this.nameEnvironment.isPackage(null, name)) {
this.knownPackages.put(name, packageBinding = this.module.createDeclaredToplevelPackage(name));
return packageBinding;
}
this.knownPackages.put(name, TheNotFoundPackage); // saves asking the oracle next time
return null;
}
public ReferenceBinding getType(char[][] compoundName) {
return getType(compoundName, this.UnNamedModule);
}
/* Answer the type corresponding to the compoundName.
* Ask the name environment for the type if its not in the cache.
* Answer null if the type cannot be found.
*/
public ReferenceBinding getType(char[][] compoundName, ModuleBinding mod) {
ReferenceBinding referenceBinding;
if (compoundName.length == 1) {
if ((referenceBinding = this.defaultPackage.getType0(compoundName[0])) == null) {
PackageBinding packageBinding = getPackage0(compoundName[0]);
if (packageBinding != null && packageBinding != TheNotFoundPackage)
return null; // collides with a known package... should not call this method in such a case
referenceBinding = askForType(this.defaultPackage, compoundName[0], mod);
}
} else {
PackageBinding packageBinding = getPackage0(compoundName[0]);
if (packageBinding == TheNotFoundPackage)
return null;
if (packageBinding != null) {
for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) {
if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null)
break;
if (packageBinding == TheNotFoundPackage)
return null;
}
}
if (packageBinding == null)
referenceBinding = askForType(compoundName, mod);
else if ((referenceBinding = packageBinding.getType0(compoundName[compoundName.length - 1])) == null)
referenceBinding = askForType(packageBinding, compoundName[compoundName.length - 1], mod);
}
if (referenceBinding == null || referenceBinding == TheNotFoundType)
return null;
referenceBinding = (ReferenceBinding) BinaryTypeBinding.resolveType(referenceBinding, this, false /* no raw conversion for now */);
// compoundName refers to a nested type incorrectly (for example, package1.A$B)
// if (referenceBinding.isNestedType())
// return new ProblemReferenceBinding(compoundName, referenceBinding, InternalNameProvided);
return referenceBinding;
}
//{ObjectTeams: special entry for RoleFileHelper:
// when searching the enclosing team for a role file, we must intercept the team,
// before its hierarchy is connected as to connect team and role file first.
/** pending type declaration that is waiting for its enclosing team. */
private TypeDeclaration pendingRoFi= null;
/** expected name of the team enclosing `pendingRoFi'. */
private char[][] expectedTeamName= null;
/**
* Look for the enclosing type of a role file. If the enclosing team is newly
* accepted into this compilation process, intercept the team as to connect
* team and role file, before connecting the team's hierarchy.
*
* @param compoundName expected name of the enclosing team
* @param roleType the type in the role file.
* @return the resolved binding of the enclosing team.
*/
public ReferenceBinding getTeamForRoFi(char[][] compoundName, TypeDeclaration roleType)
{
TypeDeclaration pendingRoFiSave= this.pendingRoFi;
char[][] expectedTeamNameSave= this.expectedTeamName;
this.pendingRoFi= roleType;
this.expectedTeamName= compoundName;
try {
return getType(compoundName);
} finally {
this.pendingRoFi= pendingRoFiSave;
this.expectedTeamName= expectedTeamNameSave;
}
}
/* Called from completeTypeBindings(two variants), this method checks whether the
* given unit has been waited for as the enclosing team of a role file.
* If so, connect team and role file.
*/
void checkConnectTeamToRoFi(CompilationUnitDeclaration parsedUnit) {
if (this.pendingRoFi == null) return;
if (parsedUnit.types == null) return;
for (TypeDeclaration type : parsedUnit.types) {
if ( type.binding != null
&& !type.isInterface()
&& RoleFileHelper.compoundNameMatch(type.binding.compoundName, this.expectedTeamName))
{
// linking role files was what triggered the current process, mark as done:
this.pendingRoFi.getRoleModel().setState(ITranslationStates.STATE_ROLE_FILES_LINKED);
// link:
AstEdit.addMemberTypeDeclaration(type, this.pendingRoFi);
// before the team can connect its hierarchy, its members must have bindings:
Dependencies.ensureRoleState(this.pendingRoFi.getRoleModel(), ITranslationStates.STATE_BINDINGS_BUILT);
// cleanup, these values have served their purpose:
this.pendingRoFi= null;
this.expectedTeamName= null;
return;
}
}
}
// SH}
private TypeBinding[] getTypeArgumentsFromSignature(SignatureWrapper wrapper, TypeVariableBinding[] staticVariables, ReferenceBinding enclosingType, ReferenceBinding genericType,
char[][][] missingTypeNames, ITypeAnnotationWalker walker)
{
java.util.ArrayList args = new java.util.ArrayList(2);
int rank = 0;
do {
args.add(getTypeFromVariantTypeSignature(wrapper, staticVariables, enclosingType, genericType, rank, missingTypeNames,
walker.toTypeArgument(rank++)));
} while (wrapper.signature[wrapper.start] != '>');
wrapper.start++; // skip '>'
TypeBinding[] typeArguments = new TypeBinding[args.size()];
args.toArray(typeArguments);
return typeArguments;
}
/* Answer the type corresponding to the compound name.
* Does not ask the oracle for the type if its not found in the cache... instead an
* unresolved type is returned which must be resolved before used.
*
* NOTE: Does NOT answer base types nor array types!
*/
//{ObjectTeams: changed private visibility to public
public ReferenceBinding getTypeFromCompoundName(char[][] compoundName, boolean isParameterized, boolean wasMissingType) {
// SH}
ReferenceBinding binding = getCachedType(compoundName);
if (binding == null) {
PackageBinding packageBinding = computePackageFrom(compoundName, false /* valid pkg */);
if(this.useModuleSystem) {
// the package might not have been seen in getCachedType, so retry
binding = packageBinding.getType0(compoundName[compoundName.length - 1]);
}
if(binding == null) {
binding = new UnresolvedReferenceBinding(compoundName, packageBinding);
if (wasMissingType) {
binding.tagBits |= TagBits.HasMissingType; // record it was bound to a missing type
}
packageBinding.addType(binding);
}
}
if (binding == TheNotFoundType) {
// report the missing class file first
if (!wasMissingType) {
/* Since missing types have been already been complained against while producing binaries, there is no class path
* misconfiguration now that did not also exist in some equivalent form while producing the class files which encode
* these missing types. So no need to bark again. Note that wasMissingType == true signals a type referenced in a .class
* file which could not be found when the binary was produced. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=364450 */
this.problemReporter.isClassPathCorrect(compoundName, this.root.unitBeingCompleted, this.missingClassFileLocation, false);
}
// create a proxy for the missing BinaryType
binding = createMissingType(null, compoundName);
} else if (!isParameterized) {
// check raw type, only for resolved types
binding = (ReferenceBinding) convertUnresolvedBinaryToRawType(binding);
}
return binding;
}
/* Answer the type corresponding to the name from the binary file.
* Does not ask the oracle for the type if its not found in the cache... instead an
* unresolved type is returned which must be resolved before used.
*
* NOTE: Does NOT answer base types nor array types!
*/
//{ObjectTeams:
public
//km}
ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int end, boolean isParameterized, char[][][] missingTypeNames, ITypeAnnotationWalker walker) {
if (end == -1)
end = signature.length;
char[][] compoundName = CharOperation.splitOn('/', signature, start, end);
boolean wasMissingType = false;
if (missingTypeNames != null) {
for (int i = 0, max = missingTypeNames.length; i < max; i++) {
if (CharOperation.equals(compoundName, missingTypeNames[i])) {
wasMissingType = true;
break;
}
}
}
ReferenceBinding binding = getTypeFromCompoundName(compoundName, isParameterized, wasMissingType);
if (walker != ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) {
binding = (ReferenceBinding) annotateType(binding, walker, missingTypeNames);
}
return binding;
}
//{ObjectTeams: changed default visibility to public
public
//SH}
ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int end, boolean isParameterized, char[][][] missingTypeNames) {
return getTypeFromConstantPoolName(signature, start, end, isParameterized, missingTypeNames, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
}
/* Answer the type corresponding to the signature from the binary file.
* Does not ask the oracle for the type if its not found in the cache... instead an
* unresolved type is returned which must be resolved before used.
*
* NOTE: Does answer base types & array types.
*/
//{ObjectTeams: changed default visibility to public
public
// SH}
TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean isParameterized, TypeBinding enclosingType,
char[][][] missingTypeNames, ITypeAnnotationWalker walker)
{
int dimension = 0;
while (signature[start] == '[') {
start++;
dimension++;
}
// annotations on dimensions?
AnnotationBinding [][] annotationsOnDimensions = null;
if (dimension > 0 && walker != ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) {
for (int i = 0; i < dimension; i++) {
AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0, true), this, missingTypeNames);
if (annotations != Binding.NO_ANNOTATIONS) {
if (annotationsOnDimensions == null)
annotationsOnDimensions = new AnnotationBinding[dimension][];
annotationsOnDimensions[i] = annotations;
}
walker = walker.toNextArrayDimension();
}
}
if (end == -1)
end = signature.length - 1;
// Just switch on signature[start] - the L case is the else
TypeBinding binding = null;
if (start == end) {
switch (signature[start]) {
case 'I' :
binding = TypeBinding.INT;
break;
case 'Z' :
binding = TypeBinding.BOOLEAN;
break;
case 'V' :
binding = TypeBinding.VOID;
break;
case 'C' :
binding = TypeBinding.CHAR;
break;
case 'D' :
binding = TypeBinding.DOUBLE;
break;
case 'B' :
binding = TypeBinding.BYTE;
break;
case 'F' :
binding = TypeBinding.FLOAT;
break;
case 'J' :
binding = TypeBinding.LONG;
break;
case 'S' :
binding = TypeBinding.SHORT;
break;
default :
this.problemReporter.corruptedSignature(enclosingType, signature, start);
// will never reach here, since error will cause abort
}
} else {
binding = getTypeFromConstantPoolName(signature, start + 1, end, isParameterized, missingTypeNames); // skip leading 'L' or 'T'
}
if (isParameterized) {
if (dimension != 0)
throw new IllegalStateException();
return binding;
}
if (walker != ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) {
binding = annotateType(binding, walker, missingTypeNames);
}
if (dimension != 0)
binding = this.typeSystem.getArrayType(binding, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions));
return binding;
}
private TypeBinding annotateType(TypeBinding binding, ITypeAnnotationWalker walker, char[][][] missingTypeNames) {
if (walker == ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) {
return binding;
}
int depth = binding.depth() + 1;
if (depth > 1) {
// need to count non-static nesting levels, resolved binding required for precision
if (binding.isUnresolvedType())
binding = ((UnresolvedReferenceBinding) binding).resolve(this, true);
depth = countNonStaticNestingLevels(binding) + 1;
}
AnnotationBinding [][] annotations = null;
for (int i = 0; i < depth; i++) {
AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(binding.id, i == depth - 1), this, missingTypeNames);
if (annots != null && annots.length > 0) {
if (annotations == null)
annotations = new AnnotationBinding[depth][];
annotations[i] = annots;
}
walker = walker.toNextNestedType();
}
if (annotations != null)
binding = createAnnotatedType(binding, annotations);
return binding;
}
// compute depth below lowest static enclosingType
private int countNonStaticNestingLevels(TypeBinding binding) {
if (binding.isUnresolvedType()) {
throw new IllegalStateException();
}
int depth = -1;
TypeBinding currentBinding = binding;
while (currentBinding != null) {
depth++;
if (currentBinding.isStatic())
break;
currentBinding = currentBinding.enclosingType();
}
return depth;
}
boolean qualifiedNameMatchesSignature(char[][] name, char[] signature) {
int s = 1; // skip 'L'
for (int i = 0; i < name.length; i++) {
char[] n = name[i];
for (int j = 0; j < n.length; j++)
if (n[j] != signature[s++])
return false;
if (signature[s] == ';' && i == name.length-1)
return true;
if (signature[s++] != '/')
return false;
}
return false;
}
public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariableBinding[] staticVariables, ReferenceBinding enclosingType,
char[][][] missingTypeNames, ITypeAnnotationWalker walker)
{
// TypeVariableSignature = 'T' Identifier ';'
// ArrayTypeSignature = '[' TypeSignature
// ClassTypeSignature = 'L' Identifier TypeArgs(optional) ';'
// or ClassTypeSignature '.' 'L' Identifier TypeArgs(optional) ';'
// TypeArgs = '<' VariantTypeSignature VariantTypeSignatures '>'
int dimension = 0;
while (wrapper.signature[wrapper.start] == '[') {
wrapper.start++;
dimension++;
}
// annotations on dimensions?
AnnotationBinding [][] annotationsOnDimensions = null;
if (dimension > 0 && walker != ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) {
for (int i = 0; i < dimension; i++) {
AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(0, true), this, missingTypeNames);
if (annotations != Binding.NO_ANNOTATIONS) {
if (annotationsOnDimensions == null)
annotationsOnDimensions = new AnnotationBinding[dimension][];
annotationsOnDimensions[i] = annotations;
}
walker = walker.toNextArrayDimension();
}
}
if (wrapper.signature[wrapper.start] == 'T') {
int varStart = wrapper.start + 1;
int varEnd = wrapper.computeEnd();
for (int i = staticVariables.length; --i >= 0;)
if (CharOperation.equals(staticVariables[i].sourceName, wrapper.signature, varStart, varEnd))
return getTypeFromTypeVariable(staticVariables[i], dimension, annotationsOnDimensions, walker, missingTypeNames);
ReferenceBinding initialType = enclosingType;
do {
TypeVariableBinding[] enclosingTypeVariables;
if (enclosingType instanceof BinaryTypeBinding) { // compiler normal case, no eager resolution of binary variables
enclosingTypeVariables = ((BinaryTypeBinding)enclosingType).typeVariables; // do not trigger resolution of variables
} else { // codepath only use by codeassist for decoding signatures
enclosingTypeVariables = enclosingType.typeVariables();
}
for (int i = enclosingTypeVariables.length; --i >= 0;)
if (CharOperation.equals(enclosingTypeVariables[i].sourceName, wrapper.signature, varStart, varEnd))
return getTypeFromTypeVariable(enclosingTypeVariables[i], dimension, annotationsOnDimensions, walker, missingTypeNames);
} while ((enclosingType = enclosingType.enclosingType()) != null);
this.problemReporter.undefinedTypeVariableSignature(CharOperation.subarray(wrapper.signature, varStart, varEnd), initialType);
return null; // cannot reach this, since previous problem will abort compilation
}
boolean isParameterized;
TypeBinding type = getTypeFromSignature(wrapper.signature, wrapper.start, wrapper.computeEnd(), isParameterized = (wrapper.end == wrapper.bracket), enclosingType, missingTypeNames, walker);
if (!isParameterized)
return dimension == 0 ? type : createArrayType(type, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions));
// type must be a ReferenceBinding at this point, cannot be a BaseTypeBinding or ArrayTypeBinding
ReferenceBinding actualType = (ReferenceBinding) type;
if (walker != ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER && actualType instanceof UnresolvedReferenceBinding)
if (actualType.depth() > 0)
actualType = (ReferenceBinding) BinaryTypeBinding.resolveType(actualType, this, false /* no raw conversion */); // must resolve member types before asking for enclosingType
ReferenceBinding actualEnclosing = actualType.enclosingType();
ITypeAnnotationWalker savedWalker = walker;
if(walker != ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER && actualType.depth() > 0) {
int nonStaticNestingLevels = countNonStaticNestingLevels(actualType);
for (int i = 0; i < nonStaticNestingLevels; i++) {
walker = walker.toNextNestedType();
}
}
TypeBinding[] typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, actualType, missingTypeNames, walker);
ReferenceBinding currentType = createParameterizedType(actualType, typeArguments, actualEnclosing);
ReferenceBinding plainCurrent = actualType;
while (wrapper.signature[wrapper.start] == '.') {
wrapper.start++; // skip '.'
int memberStart = wrapper.start;
char[] memberName = wrapper.nextWord();
plainCurrent = (ReferenceBinding) BinaryTypeBinding.resolveType(plainCurrent, this, false);
ReferenceBinding memberType = plainCurrent.getMemberType(memberName);
// need to protect against the member type being null when the signature is invalid
if (memberType == null)
this.problemReporter.corruptedSignature(currentType, wrapper.signature, memberStart); // aborts
if(memberType.isStatic()) {
// may happen for class files generated by eclipse before bug 460491 was fixed.
walker = savedWalker;
} else {
walker = walker.toNextNestedType();
}
if (wrapper.signature[wrapper.start] == '<') {
wrapper.start++; // skip '<'
typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, memberType, missingTypeNames, walker);
} else {
typeArguments = null;
}
if (typeArguments != null || // has type arguments, or ...
(!memberType.isStatic() && currentType.isParameterizedType())) // ... can see type arguments of enclosing
{
if (memberType.isStatic())
currentType = plainCurrent; // ignore bogus parameterization of enclosing
currentType = createParameterizedType(memberType, typeArguments, currentType);
} else {
currentType = memberType;
}
plainCurrent = memberType;
}
wrapper.start++; // skip ';'
TypeBinding annotatedType = annotateType(currentType, savedWalker, missingTypeNames);
return dimension == 0 ? annotatedType : createArrayType(annotatedType, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions));
}
private TypeBinding getTypeFromTypeVariable(TypeVariableBinding typeVariableBinding, int dimension, AnnotationBinding [][] annotationsOnDimensions, ITypeAnnotationWalker walker, char [][][] missingTypeNames) {
AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(-1, false), this, missingTypeNames);
if (annotations != null && annotations != Binding.NO_ANNOTATIONS)
typeVariableBinding = (TypeVariableBinding) createAnnotatedType(typeVariableBinding, new AnnotationBinding [][] { annotations });
if (dimension == 0) {
return typeVariableBinding;
}
return this.typeSystem.getArrayType(typeVariableBinding, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions));
}
TypeBinding getTypeFromVariantTypeSignature(
SignatureWrapper wrapper,
TypeVariableBinding[] staticVariables,
ReferenceBinding enclosingType,
ReferenceBinding genericType,
int rank,
char[][][] missingTypeNames,
ITypeAnnotationWalker walker) {
// VariantTypeSignature = '-' TypeSignature
// or '+' TypeSignature
// or TypeSignature
// or '*'
switch (wrapper.signature[wrapper.start]) {
case '-' :
// ? super aType
wrapper.start++;
TypeBinding bound = getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames, walker.toWildcardBound());
AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(-1, false), this, missingTypeNames);
return this.typeSystem.getWildcard(genericType, rank, bound, null /*no extra bound*/, Wildcard.SUPER, annotations);
case '+' :
// ? extends aType
wrapper.start++;
bound = getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames, walker.toWildcardBound());
annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(-1, false), this, missingTypeNames);
return this.typeSystem.getWildcard(genericType, rank, bound, null /*no extra bound*/, Wildcard.EXTENDS, annotations);
case '*' :
// ?
wrapper.start++;
annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(-1, false), this, missingTypeNames);
return this.typeSystem.getWildcard(genericType, rank, null, null /*no extra bound*/, Wildcard.UNBOUND, annotations);
default :
return getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames, walker);
}
}
boolean isMissingType(char[] typeName) {
for (int i = this.missingTypes == null ? 0 : this.missingTypes.size(); --i >= 0;) {
MissingTypeBinding missingType = (MissingTypeBinding) this.missingTypes.get(i);
if (CharOperation.equals(missingType.sourceName, typeName))
return true;
}
return false;
}
// The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready.
public MethodVerifier methodVerifier() {
// TODO(SHMOD): I'm not sure if the verifier would need to be created with a specific LE?
if (this.verifier == null)
this.verifier = newMethodVerifier();
return this.verifier;
}
public MethodVerifier newMethodVerifier() {
/* Always use MethodVerifier15. Even in a 1.4 project, we must internalize type variables and
observe any parameterization of super class and/or super interfaces in order to be able to
detect overriding in the presence of generics.
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=324850
*/
return new MethodVerifier15(this);
}
public void releaseClassFiles(org.eclipse.jdt.internal.compiler.ClassFile[] classFiles) {
for (int i = 0, fileCount = classFiles.length; i < fileCount; i++)
this.classFilePool.release(classFiles[i]);
}
public void reset() {
if (this.root != this) {
this.root.reset();
return;
}
this.stepCompleted = 0;
this.knownModules = new HashtableOfModule();
this.UnNamedModule = new ModuleBinding.UnNamedModule(this);
this.module = this.UnNamedModule;
this.JavaBaseModule = null;
this.defaultPackage = new PlainPackageBinding(this); // assume the default package always exists
this.defaultImports = null;
this.knownPackages = new HashtableOfPackage();
this.accessRestrictions = new HashMap(3);
this.verifier = null;
// NOTE: remember to fix #updateCaches(...) when adding unique binding caches
this.uniqueParameterizedGenericMethodBindings = new SimpleLookupTable(3);
this.uniquePolymorphicMethodBindings = new SimpleLookupTable(3);
this.uniqueGetClassMethodBinding = null;
this.missingTypes = null;
this.typesBeingConnected = new HashSet();
for (int i = this.units.length; --i >= 0;)
this.units[i] = null;
this.lastUnitIndex = -1;
this.lastCompletedUnitIndex = -1;
this.unitBeingCompleted = null; // in case AbortException occurred
this.classFilePool.reset();
this.typeSystem.reset();
// name environment has a longer life cycle, and must be reset in
// the code which created it.
//{ObjectTeams: more state to release:
this.teamMethodGenerator = null;
// SH}
}
/**
* Associate a given type with some access restriction
* (did not store the restriction directly into binding, since sparse information)
*/
public void setAccessRestriction(ReferenceBinding type, AccessRestriction accessRestriction) {
if (accessRestriction == null) return;
type.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
this.accessRestrictions.put(type, accessRestriction);
}
void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
this.typeSystem.updateCaches(unresolvedType, resolvedType);
}
//{ObjectTeams: translate the step completed into a dependencies step (from ITranslationStates):
public int getDependenciesStateCompleted() {
switch (this.stepCompleted) {
case BUILD_TYPE_HIERARCHY:
return ITranslationStates.STATE_LENV_BUILD_TYPE_HIERARCHY;
case CHECK_AND_SET_IMPORTS:
return ITranslationStates.STATE_LENV_CHECK_AND_SET_IMPORTS;
case CONNECT_TYPE_HIERARCHY:
return ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY;
case BUILD_FIELDS_AND_METHODS:
return ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS;
case ROLES_LINKED:
return ITranslationStates.STATE_ROLES_LINKED;
}
return ITranslationStates.STATE_NONE;
}
// SH}
public IQualifiedTypeResolutionListener[] resolutionListeners; // ROOT_ONLY
public void addResolutionListener(IQualifiedTypeResolutionListener resolutionListener) {
synchronized (this.root) {
int length = this.root.resolutionListeners.length;
for (int i = 0; i < length; i++){
if (this.root.resolutionListeners[i].equals(resolutionListener))
return;
}
System.arraycopy(this.root.resolutionListeners, 0,
this.root.resolutionListeners = new IQualifiedTypeResolutionListener[length + 1], 0, length);
this.root.resolutionListeners[length] = resolutionListener;
}
}
public TypeBinding getUnannotatedType(TypeBinding typeBinding) {
return this.typeSystem.getUnannotatedType(typeBinding);
}
// Given a type, return all its variously annotated versions.
public TypeBinding[] getAnnotatedTypes(TypeBinding type) {
return this.typeSystem.getAnnotatedTypes(type);
}
public AnnotationBinding[] filterNullTypeAnnotations(AnnotationBinding[] typeAnnotations) {
if (typeAnnotations.length == 0)
return typeAnnotations;
AnnotationBinding[] filtered = new AnnotationBinding[typeAnnotations.length];
int count = 0;
for (int i = 0; i < typeAnnotations.length; i++) {
AnnotationBinding typeAnnotation = typeAnnotations[i];
if (typeAnnotation == null) {
count++; // sentinel in annotation sequence for array dimensions
} else {
if (!typeAnnotation.type.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation))
filtered[count++] = typeAnnotation;
}
}
if (count == 0)
return Binding.NO_ANNOTATIONS;
if (count == typeAnnotations.length)
return typeAnnotations;
System.arraycopy(filtered, 0, filtered = new AnnotationBinding[count], 0, count);
return filtered;
}
public boolean containsNullTypeAnnotation(IBinaryAnnotation[] typeAnnotations) {
if (typeAnnotations.length == 0)
return false;
for (int i = 0; i < typeAnnotations.length; i++) {
IBinaryAnnotation typeAnnotation = typeAnnotations[i];
char[] typeName = typeAnnotation.getTypeName();
// typeName must be "Lfoo/X;"
if (typeName == null || typeName.length < 3 || typeName[0] != 'L') continue;
char[][] name = CharOperation.splitOn('/', typeName, 1, typeName.length-1);
if (getNullAnnotationBit(name) != 0)
return true;
}
return false;
}
public boolean containsNullTypeAnnotation(AnnotationBinding[] typeAnnotations) {
if (typeAnnotations.length == 0)
return false;
for (int i = 0; i < typeAnnotations.length; i++) {
AnnotationBinding typeAnnotation = typeAnnotations[i];
if (typeAnnotation.type.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation))
return true;
}
return false;
}
public Binding getInaccessibleBinding(char[][] compoundName, ModuleBinding clientModule) {
if (this.root != this)
return this.root.getInaccessibleBinding(compoundName, clientModule);
if (this.nameEnvironment instanceof IModuleAwareNameEnvironment) {
IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.nameEnvironment;
int length = compoundName.length;
for (int j=length; j>0; j--) {
char[][] candidateName = CharOperation.subarray(compoundName, 0, j);
char[][] moduleNames = moduleEnv.getModulesDeclaringPackage(candidateName, ModuleBinding.ANY);
if (moduleNames != null) {
// in some module a package named candidateName exists, verify observability & inaccessibility:
PackageBinding inaccessiblePackage = null;
for (char[] moduleName : moduleNames) {
if (moduleName == ModuleBinding.UNOBSERVABLE)
continue;
ModuleBinding mod = getModule(moduleName);
if (mod != null) {
PackageBinding pack = mod.getVisiblePackage(candidateName);
if (pack != null && pack.isValidBinding()) {
if (clientModule.canAccess(pack))
return null;
inaccessiblePackage = pack;
}
}
}
if (inaccessiblePackage == null)
return null;
if (j < length) {
// does the package even contain a type of the next name segment?
TypeBinding type = inaccessiblePackage.getType(compoundName[j], inaccessiblePackage.enclosingModule);
if (type instanceof ReferenceBinding && type.isValidBinding())
return new ProblemReferenceBinding(compoundName, (ReferenceBinding) type, ProblemReasons.NotAccessible);
}
return new ProblemPackageBinding(candidateName, ProblemReasons.NotAccessible, this);
}
}
}
return null;
}
}