blob: 57a81ec32b1d9061b15bcae8f9f52abb98d457f5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.Collection;
import java.util.stream.Stream;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.IModuleContext;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.INameEnvironmentExtension;
import org.eclipse.jdt.internal.compiler.util.JRTUtil;
/**
* Represents the unnamed module
*
*/
public class UnNamedModuleBinding extends ModuleBinding {
UnNamedModuleBinding(LookupEnvironment env) {
super(env);
}
public ModuleBinding[] getAllRequiredModules() {
// Not caching required modules here, because some more modules may have been
// added to the list of known modules, and we need to check all of them as well
Collection<ModuleBinding> allRequires = dependencyCollector().get();
ModuleBinding javaBase = this.environment.getModule(JRTUtil.JAVA_BASE_CHAR);
if (!CharOperation.equals(this.moduleName, TypeConstants.JAVA_BASE) && javaBase != null) {
allRequires.add(javaBase);
}
return allRequires.size() > 0 ? allRequires.toArray(new ModuleBinding[allRequires.size()]) : NO_REQUIRES;
}
protected Stream<ModuleBinding> getRequiredModules(boolean transitiveOnly) {
return Stream.of(this.environment.knownModules.valueTable).filter(m -> m != null);
}
public IModuleContext getDependencyClosureContext() {
return IModuleContext.UNNAMED_MODULE_CONTEXT;
}
public IModuleContext getModuleGraphContext() {
return IModuleContext.UNNAMED_MODULE_CONTEXT;
}
PackageBinding getTopLevelPackage(char[] name) {
PackageBinding packageBinding = this.declaredPackages.get(name);
if (packageBinding != null) {
if (packageBinding == LookupEnvironment.TheNotFoundPackage)
return null;
return packageBinding;
}
if (declaresPackage(new char[][] {name})) {
packageBinding = new PackageBinding(name, this.environment);
}
if (packageBinding != null) {
//if (this.nameEnvironment.isPackage(null, name, mod)) {
this.declaredPackages.put(name, packageBinding);
return packageBinding;
}
this.declaredPackages.put(name, LookupEnvironment.TheNotFoundPackage); // saves asking the oracle next time
return null;
}
public PackageBinding getDeclaredPackage(char[][] name) {
// return package binding if there exists a package named name in this module
if (name == null || name.length == 0) {
return this.environment.getDefaultPackage(this.moduleName);
}
// char[] qualifiedName = CharOperation.concatWith(name, '.');
PackageBinding packageBinding = getTopLevelPackage(name[0]);
if (packageBinding == null || packageBinding == LookupEnvironment.TheNotFoundPackage)
return null;
int length = name.length, index = 1;
while (index < length) {
char[] simpleName = name[index++];
PackageBinding binding = packageBinding.getPackage0(simpleName);
if (binding != null) {
if (binding == LookupEnvironment.TheNotFoundPackage) {
return null;
}
} else {
if (declaresPackage(packageBinding.compoundName, simpleName)) {
char[][] subPkgCompoundName = CharOperation.arrayConcat(packageBinding.compoundName, simpleName);
binding = new PackageBinding(subPkgCompoundName, packageBinding, this.environment);
packageBinding.addPackage(binding);
} else {
packageBinding.addNotFoundPackage(simpleName);
return null;
}
}
packageBinding = binding;
}
return packageBinding;
}
public PackageBinding createPackage(char[][] compoundName) {
PackageBinding packageBinding = this.declaredPackages.get(compoundName[0]);
if (packageBinding == null || packageBinding == LookupEnvironment.TheNotFoundPackage) {
packageBinding = new PackageBinding(compoundName[0], this.environment);
this.declaredPackages.put(compoundName[0], packageBinding);
}
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
ReferenceBinding type = packageBinding.getType0(compoundName[i]);
if (type != null && type != LookupEnvironment.TheNotFoundType
&& !(type instanceof UnresolvedReferenceBinding))
return null;
PackageBinding parent = packageBinding;
if ((packageBinding = parent.getPackage0(compoundName[i])) == null
|| packageBinding == LookupEnvironment.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
INameEnvironment nameEnvironment = this.environment.nameEnvironment;
if (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) nameEnvironment).findType(compoundName[i], parent.compoundName,
false, getDependencyClosureContext()) != null) {
return null;
}
} else {
if (nameEnvironment.findType(compoundName[i], parent.compoundName) != null) {
return null;
}
}
packageBinding = new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent,
this.environment);
parent.addPackage(packageBinding);
}
}
return packageBinding;
}
public PackageBinding computePackageFrom(char[][] constantPoolName, boolean isMissing) {
if (constantPoolName.length == 1)
return this.environment.getDefaultPackage(this.moduleName);
PackageBinding packageBinding = getPackage(CharOperation.subarray(constantPoolName, 0, constantPoolName.length - 1));//this.declaredPackages.get(constantPoolName[0]);
// if (packageBinding != null && packageBinding.isValidBinding())
// return packageBinding;
if (packageBinding == null || packageBinding == LookupEnvironment.TheNotFoundPackage) {
packageBinding = new PackageBinding(constantPoolName[0], this.environment);
if (isMissing) packageBinding.tagBits |= TagBits.HasMissingType;
this.declaredPackages.put(constantPoolName[0], packageBinding);
for (int i = 1, length = constantPoolName.length - 1; i < length; i++) {
PackageBinding parent = packageBinding;
if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null || packageBinding == LookupEnvironment.TheNotFoundPackage) {
packageBinding = new PackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this.environment);
if (isMissing) {
packageBinding.tagBits |= TagBits.HasMissingType;
}
parent.addPackage(packageBinding);
}
}
}
return packageBinding;
}
}