Copyright (c) 2000, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Stephan Herrmann - 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
/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - 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.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; @SuppressWarnings({"rawtypes", "unchecked"}) public class LookupEnvironment implements ProblemReasons, TypeConstants {
Map from typeBinding -> accessRestriction rule
/** * 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.
/** * 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.
/** 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.
/** 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.
/** * 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; 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);
Construct the root LookupEnvironment, corresponding to the UnNamedModule.
/** 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.
/** 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.
/** * 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) { 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; 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 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 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; } } 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.
/** 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.
/** 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.
/** 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) { 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 { 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++) { (this.unitBeingCompleted = this.units[i]).scope.checkAndSetImports(); } this.stepCompleted = CHECK_AND_SET_IMPORTS; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted = this.units[i]).scope.connectTypeHierarchy(); } this.stepCompleted = CONNECT_TYPE_HIERARCHY; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { CompilationUnitScope unitScope = (this.unitBeingCompleted = this.units[i]).scope; unitScope.checkParameterizedTypes(); unitScope.buildFieldsAndMethods(); this.units[i] = null; // release unnecessary reference to the parsed unit } this.stepCompleted = BUILD_FIELDS_AND_METHODS; 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; } if (this.stepCompleted == BUILD_FIELDS_AND_METHODS) { // 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 { if (parsedUnit.scope == null) return; // parsing errors were too severe if (this.stepCompleted >= CHECK_AND_SET_IMPORTS) (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); if (this.stepCompleted >= CONNECT_TYPE_HIERARCHY) (this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy(); this.unitBeingCompleted = null; } } /* * 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) { 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) (rootEnv.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); } for (int i = 0; i < unitCount; i++) { CompilationUnitDeclaration parsedUnit = parsedUnits[i]; if (parsedUnit.scope != null) (rootEnv.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy(); } for (int i = 0; i < unitCount; i++) { CompilationUnitDeclaration parsedUnit = parsedUnits[i]; if (parsedUnit.scope != null) { (rootEnv.unitBeingCompleted = parsedUnit).scope.checkParameterizedTypes(); if (buildFieldsAndMethods[i]) parsedUnit.scope.buildFieldsAndMethods(); } } 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 --> param X
/** * 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.
Params:
  • type – the TypeBinding to raw convert
  • forceRawEnclosingType – forces recursive raw conversion of enclosing types (used in Javadoc references only)
Returns:TypeBinding the raw converted TypeBinding
/** * 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.
/** * 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) { 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) return this.typeSystem.getParameterizedType((ReferenceBinding) genericType.unannotated(), typeArguments, enclosingType, annotations); return this.typeSystem.getParameterizedType(genericType, typeArguments, enclosingType); } public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { return this.typeSystem.getParameterizedType(genericType, typeArguments, enclosingType, annotations); } 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
/** * 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.
/** * 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, null); 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); } public ReferenceBinding getResolvedType(char[][] compoundName, ModuleBinding moduleBinding, Scope scope) { if (this.module != moduleBinding) return moduleBinding.environment.getResolvedType(compoundName, moduleBinding, scope); 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); return createMissingType(null, compoundName); } public ReferenceBinding getResolvedJavaBaseType(char[][] compoundName, Scope scope) { return getResolvedType(compoundName, javaBaseModule(), scope); } /* 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; } 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! */ private ReferenceBinding getTypeFromCompoundName(char[][] compoundName, boolean isParameterized, boolean wasMissingType) { 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); } // 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! */ 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; } 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. */ 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. }
Associate a given type with some access restriction (did not store the restriction directly into binding, since sparse information)
/** * 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); } 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; } }