org.eclipse.jdt.internal.compiler.lookup.PackageBinding Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* 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 186342 - [compiler][null] Using annotations for null checking
* bug 365519 - editorial cleanup after bug 186342 and bug 365387
* bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
import java.util.function.Predicate;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment;
import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage;
import org.eclipse.jdt.internal.compiler.util.HashtableOfType;
public class PackageBinding extends Binding implements TypeConstants {
public long tagBits = 0; // See values in the interface TagBits below
public char[][] compoundName;
PackageBinding parent;
ArrayList wrappingSplitPackageBindings;
public LookupEnvironment environment;
/** Types in this map are either uniquely visible in the current module or ProblemReferenceBindings. */
public HashtableOfType knownTypes;
/** All visible member packages, i.e. observable packages associated with modules read by the current module. */
HashtableOfPackage knownPackages;
// code representing the default that has been defined for this package (using @NonNullByDefault)
// one of Binding.{NO_NULL_DEFAULT,NULL_UNSPECIFIED_BY_DEFAULT,NONNULL_BY_DEFAULT}
private int defaultNullness = NO_NULL_DEFAULT;
public ModuleBinding enclosingModule;
/** Is this package exported from its module? NB: to query this property use {@link #isExported()} to ensure initialization. */
Boolean isExported;
protected PackageBinding() {
// for creating problem package
}
public PackageBinding(char[] topLevelPackageName, LookupEnvironment environment, ModuleBinding enclosingModule) {
this(new char[][] {topLevelPackageName}, null, environment, enclosingModule);
}
/* Create a normal package.
*/
public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnvironment environment, ModuleBinding enclosingModule) {
this.compoundName = compoundName;
this.parent = parent;
this.environment = environment;
this.knownTypes = null; // initialized if used... class counts can be very large 300-600
this.knownPackages = new HashtableOfPackage(3); // sub-package counts are typically 0-3
if (compoundName != CharOperation.NO_CHAR_CHAR)
checkIfNullAnnotationPackage();
if (enclosingModule != null)
this.enclosingModule = enclosingModule;
else if (parent != null)
this.enclosingModule = parent.enclosingModule; // stop-gap for any remaining calls that don't provide an enclosingModule (they should)
if (this.enclosingModule == null)
throw new IllegalStateException("Package should have an enclosing module"); //$NON-NLS-1$
}
public PackageBinding(LookupEnvironment environment) {
this(CharOperation.NO_CHAR_CHAR, null, environment, environment.module);
}
protected void addNotFoundPackage(char[] simpleName) {
if (!this.environment.suppressImportErrors)
this.knownPackages.put(simpleName, LookupEnvironment.TheNotFoundPackage);
}
private void addNotFoundType(char[] simpleName) {
if (this.environment.suppressImportErrors)
return;
if (this.knownTypes == null)
this.knownTypes = new HashtableOfType(25);
this.knownTypes.put(simpleName, LookupEnvironment.TheNotFoundType);
}
/**
* Remembers a sub-package.
* For a split parent package this will include potentially enriching with siblings,
* in which case the enriched (split) binding will be returned.
*/
PackageBinding addPackage(PackageBinding element, ModuleBinding module) {
if ((element.tagBits & TagBits.HasMissingType) == 0) clearMissingTagBit();
this.knownPackages.put(element.compoundName[element.compoundName.length - 1], element);
return element;
}
void addType(ReferenceBinding element) {
if ((element.tagBits & TagBits.HasMissingType) == 0) clearMissingTagBit();
if (this.knownTypes == null)
this.knownTypes = new HashtableOfType(25);
char [] name = element.compoundName[element.compoundName.length - 1];
ReferenceBinding priorType = this.knownTypes.getput(name, element);
if (priorType != null && priorType.isUnresolvedType() && !element.isUnresolvedType()) {
((UnresolvedReferenceBinding) priorType).setResolvedType(element, this.environment);
}
if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled)
if (element.isAnnotationType() || element instanceof UnresolvedReferenceBinding) // unresolved types don't yet have the modifiers set
checkIfNullAnnotationType(element);
if (!element.isUnresolvedType() && this.wrappingSplitPackageBindings != null) {
for (SplitPackageBinding splitPackageBinding : this.wrappingSplitPackageBindings) {
if (splitPackageBinding.knownTypes != null) {
ReferenceBinding prior = splitPackageBinding.knownTypes.get(name);
if (prior != null && prior.isUnresolvedType() && !element.isUnresolvedType()) {
((UnresolvedReferenceBinding) prior).setResolvedType(element, this.environment);
splitPackageBinding.knownTypes.put(name, null); // forces re-checking for conflicts
}
}
}
}
}
ModuleBinding[] getDeclaringModules() {
return new ModuleBinding[] { this.enclosingModule };
}
void clearMissingTagBit() {
PackageBinding current = this;
do {
current.tagBits &= ~TagBits.HasMissingType;
} while ((current = current.parent) != null);
}
/*
* slash separated name
* org.eclipse.jdt.core --> org/eclipse/jdt/core
*/
@Override
public char[] computeUniqueKey(boolean isLeaf) {
return CharOperation.concatWith(this.compoundName, '/');
}
protected PackageBinding findPackage(char[] name, ModuleBinding module) {
// delegate to the module to consider the module graph:
return module.getPackage(this.compoundName, name);
}
/* Answer the subpackage named name; ask the oracle for the package if its not in the cache.
* Answer null if it could not be resolved.
*
* NOTE: This should only be used when we know there is NOT a type with the same name.
*/
PackageBinding getPackage(char[] name, ModuleBinding mod) {
PackageBinding binding = getPackage0(name);
if (binding != null) {
if (binding == LookupEnvironment.TheNotFoundPackage)
return null;
else
return binding;
}
if ((binding = findPackage(name, mod)) != null)
return binding;
// not found so remember a problem package binding in the cache for future lookups
addNotFoundPackage(name);
return null;
}
/** Answer the subpackage 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: The returned package binding is guaranteed to be complete wrt. SplitPackageBinding,
* or, if no complete binding is yet available, we shyly 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);
}
/** Variant (see {@link #getPackage0(char[])}), that may even answer an incompletely
* combined package (in the case of SplitPackageBinding).
*/
PackageBinding getPackage0Any(char[] name) {
return this.knownPackages.get(name);
}
/* Answer the type named name; ask the oracle for the type if its not in the cache.
* Answer a NotVisible problem type if the type is not visible from the invocationPackage.
* Answer null if it could not be resolved.
*
* NOTE: This should only be used by source types/scopes which know there is NOT a
* package with the same name.
*/
ReferenceBinding getType(char[] name, ModuleBinding mod) {
ReferenceBinding referenceBinding = getType0(name);
if (referenceBinding == null) {
if ((referenceBinding = this.environment.askForType(this, name, mod)) == null) {
// not found so remember a problem type binding in the cache for future lookups
addNotFoundType(name);
return null;
}
}
if (referenceBinding == LookupEnvironment.TheNotFoundType)
return null;
referenceBinding = (ReferenceBinding) BinaryTypeBinding.resolveType(referenceBinding, this.environment, false /* no raw conversion for now */);
if (referenceBinding.isNestedType())
return new ProblemReferenceBinding(new char[][]{ name }, referenceBinding, ProblemReasons.InternalNameProvided);
if (!mod.canAccess(this))
return new ProblemReferenceBinding(referenceBinding.compoundName, referenceBinding, ProblemReasons.NotAccessible);
// at this point we have only checked accessibility of the package, accessibility of the type will be checked by callers
return referenceBinding;
}
/* Answer the type named name 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: Senders must convert theNotFoundType into a real problem
* reference type if its to returned.
*/
ReferenceBinding getType0(char[] name) {
if (this.knownTypes == null)
return null;
return this.knownTypes.get(name);
}
/* Answer the package or type named name; ask the oracle if it is not in the cache.
* Answer null if it could not be resolved.
*
* When collisions exist between a type name & a package name, answer the type.
* Treat the package as if it does not exist... a problem was already reported when the type was defined.
*
* NOTE: no visibility checks are performed.
* THIS SHOULD ONLY BE USED BY SOURCE TYPES/SCOPES.
*/
public Binding getTypeOrPackage(char[] name, ModuleBinding mod, boolean splitPackageAllowed) {
ReferenceBinding problemBinding = null;
ReferenceBinding referenceBinding = getType0(name);
lookForType0:
if (referenceBinding != null && referenceBinding != LookupEnvironment.TheNotFoundType) {
referenceBinding = (ReferenceBinding) BinaryTypeBinding.resolveType(referenceBinding, this.environment, false /* no raw conversion for now */);
if (referenceBinding.isNestedType()) {
return new ProblemReferenceBinding(new char[][]{name}, referenceBinding, ProblemReasons.InternalNameProvided);
}
boolean isSameModule = (this instanceof SplitPackageBinding) ? referenceBinding.module() == mod : this.enclosingModule == mod;
if (!isSameModule && referenceBinding.isValidBinding() && !mod.canAccess(referenceBinding.fPackage)) {
problemBinding = new ProblemReferenceBinding(referenceBinding.compoundName, referenceBinding, ProblemReasons.NotAccessible);
break lookForType0;
}
if ((referenceBinding.tagBits & TagBits.HasMissingType) == 0) {
return referenceBinding;
}
// referenceBinding is a MissingType, will return it if no package is found
}
PackageBinding packageBinding = getPackage0(name);
if (packageBinding != null && packageBinding != LookupEnvironment.TheNotFoundPackage) {
if (!splitPackageAllowed && packageBinding instanceof SplitPackageBinding) {
return ((SplitPackageBinding) packageBinding).getVisibleFor(mod, false);
}
return packageBinding;
}
lookForType:
if (referenceBinding == null && problemBinding == null) { // have not looked for it before
if ((referenceBinding = this.environment.askForType(this, name, mod)) != null) {
if (referenceBinding.isNestedType()) {
return new ProblemReferenceBinding(new char[][]{name}, referenceBinding, ProblemReasons.InternalNameProvided);
}
if (referenceBinding.isValidBinding() && !mod.canAccess(referenceBinding.fPackage)) {
problemBinding = new ProblemReferenceBinding(referenceBinding.compoundName, referenceBinding, ProblemReasons.NotAccessible);
break lookForType;
} else {
return referenceBinding;
}
}
// Since name could not be found, add a problem binding
// to the collections so it will be reported as an error next time.
addNotFoundType(name);
}
if (packageBinding == null) { // have not looked for it before
if ((packageBinding = findPackage(name, mod)) != null) {
if (!splitPackageAllowed && packageBinding instanceof SplitPackageBinding) {
return ((SplitPackageBinding) packageBinding).getVisibleFor(mod, false);
}
return packageBinding;
}
if (referenceBinding != null && referenceBinding != LookupEnvironment.TheNotFoundType) {
if (problemBinding != null)
return problemBinding;
return referenceBinding; // found cached missing type - check if package conflict
}
addNotFoundPackage(name);
}
return problemBinding;
}
public final boolean isViewedAsDeprecated() {
if ((this.tagBits & TagBits.DeprecatedAnnotationResolved) == 0) {
this.tagBits |= TagBits.DeprecatedAnnotationResolved;
if (this.compoundName != CharOperation.NO_CHAR_CHAR) {
ReferenceBinding packageInfo = this.getType(TypeConstants.PACKAGE_INFO_NAME, this.enclosingModule);
if (packageInfo != null) {
packageInfo.initializeDeprecatedAnnotationTagBits();
this.tagBits |= packageInfo.tagBits & TagBits.AllStandardAnnotationsMask;
}
}
}
return (this.tagBits & TagBits.AnnotationDeprecated) != 0;
}
public int getDefaultNullness() {
if (this.defaultNullness == NO_NULL_DEFAULT)
return this.enclosingModule.getDefaultNullness();
return this.defaultNullness;
}
public void setDefaultNullness(int nullness) {
this.defaultNullness = nullness;
}
/**
* Find a binding (either this package or its enclosing ModuleBinding)
* where 'defaultNullness' matches the given predicate.
*/
public Binding findDefaultNullnessTarget(Predicate predicate) {
if (predicate.test(this.defaultNullness))
return this;
if (this.defaultNullness == NO_NULL_DEFAULT)
if (predicate.test(this.enclosingModule.getDefaultNullness()))
return this.enclosingModule;
return null;
}
/* API
* Answer the receiver's binding type from Binding.BindingID.
*/
@Override
public final int kind() {
return Binding.PACKAGE;
}
@Override
public int problemId() {
if ((this.tagBits & TagBits.HasMissingType) != 0)
return ProblemReasons.NotFound;
return ProblemReasons.NoError;
}
void checkIfNullAnnotationPackage() {
LookupEnvironment env = this.environment;
if (env.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
if (isPackageOfQualifiedTypeName(this.compoundName, env.getNullableAnnotationName()))
env.nullableAnnotationPackage = this;
if (isPackageOfQualifiedTypeName(this.compoundName, env.getNonNullAnnotationName()))
env.nonnullAnnotationPackage = this;
if (isPackageOfQualifiedTypeName(this.compoundName, env.getNonNullByDefaultAnnotationName()))
env.nonnullByDefaultAnnotationPackage = this;
}
}
private boolean isPackageOfQualifiedTypeName(char[][] packageName, char[][] typeName) {
int length;
if (typeName == null || (length = packageName.length) != typeName.length -1)
return false;
for (int i=0; i();
}
this.wrappingSplitPackageBindings.add(splitPackageBinding);
}
}