package org.eclipse.jdt.internal.core;
import java.io.File;
import java.util.*;
import java.util.function.Function;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IInitializer;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.IModule;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.AbstractModule.AutoModule;
import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
@SuppressWarnings({"rawtypes", "unchecked"})
public class NameLookup implements SuffixConstants {
private static IModuleDescription NO_MODULE = new SourceModule(null, "Not a module") { };
public static class Answer {
public IType type;
public IModuleDescription module;
AccessRestriction restriction;
IClasspathEntry entry;
Answer(IType type, AccessRestriction restriction, IClasspathEntry entry) {
this(type, restriction, entry, null);
}
Answer(IType type, AccessRestriction restriction, IClasspathEntry entry, IModuleDescription module) {
this.type = type;
this.restriction = restriction;
this.entry = entry;
this.module = module;
}
Answer(IModuleDescription module) {
this.module = module;
this.restriction = null;
}
public boolean ignoreIfBetter() {
return this.restriction != null && this.restriction.ignoreIfBetter();
}
public boolean isBetter(Answer otherAnswer) {
if (otherAnswer == null) return true;
if (this.restriction == null) return true;
return otherAnswer.restriction != null
&& this.restriction.getProblemId() < otherAnswer.restriction.getProblemId();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(this.type.toString());
builder.append("from ")
.append(this.module);
return builder.toString();
}
}
private class Selector implements IJavaElementRequestor {
public List<IPackageFragment> pkgFragments;
public Selector(String moduleName) {
this.pkgFragments = new ArrayList<>();
}
@Override
public void acceptField(IField field) {
}
@Override
public void acceptInitializer(IInitializer initializer) {
}
@Override
public void acceptMemberType(IType type) {
}
@Override
public void acceptMethod(IMethod method) {
}
@Override
public void acceptPackageFragment(IPackageFragment packageFragment) {
this.pkgFragments.add(packageFragment);
}
@Override
public void acceptType(IType type) {
}
@Override
public void acceptModule(IModuleDescription module) {
}
@Override
public boolean isCanceled() {
return false;
}
}
public static final int ACCEPT_CLASSES = ASTNode.Bit2;
public static final int ACCEPT_INTERFACES = ASTNode.Bit3;
public static final int ACCEPT_ENUMS = ASTNode.Bit4;
public static final int ACCEPT_ANNOTATIONS = ASTNode.Bit5;
public static final int ACCEPT_ALL = ACCEPT_CLASSES | ACCEPT_INTERFACES | ACCEPT_ENUMS | ACCEPT_ANNOTATIONS;
public static boolean VERBOSE = false;
private static final IType[] NO_TYPES = {};
protected IPackageFragmentRoot[] packageFragmentRoots;
protected HashtableOfArrayToObject packageFragments;
protected Map<IPackageFragmentRoot,IClasspathEntry> rootToResolvedEntries;
protected Map<IPackageFragmentRoot,IModuleDescription> rootToModule;
protected HashMap typesInWorkingCopies;
public long timeSpentInSeekTypesInSourcePackage = 0;
public long timeSpentInSeekTypesInBinaryPackage = 0;
private JavaProject rootProject;
public NameLookup(
JavaProject rootProject, IPackageFragmentRoot[] packageFragmentRoots,
HashtableOfArrayToObject packageFragments,
ICompilationUnit[] workingCopies,
Map rootToResolvedEntries) {
this.rootProject = rootProject;
long start = -1;
if (VERBOSE) {
Util.verbose(" BUILDING NameLoopkup");
Util.verbose(" -> pkg roots size: " + (packageFragmentRoots == null ? 0 : packageFragmentRoots.length));
Util.verbose(" -> pkgs size: " + (packageFragments == null ? 0 : packageFragments.size()));
Util.verbose(" -> working copy size: " + (workingCopies == null ? 0 : workingCopies.length));
start = System.currentTimeMillis();
}
this.rootToModule = new HashMap<>();
this.packageFragmentRoots = packageFragmentRoots;
if (workingCopies == null) {
this.packageFragments = packageFragments;
} else {
try {
this.packageFragments = (HashtableOfArrayToObject) packageFragments.clone();
} catch (CloneNotSupportedException e1) {
}
this.typesInWorkingCopies = new HashMap();
HashtableOfObjectToInt rootPositions = new HashtableOfObjectToInt();
for (int i = 0, length = packageFragmentRoots.length; i < length; i++) {
rootPositions.put(packageFragmentRoots[i], i);
}
for (int i = 0, length = workingCopies.length; i < length; i++) {
ICompilationUnit workingCopy = workingCopies[i];
PackageFragment pkg = (PackageFragment) workingCopy.getParent();
IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
int rootPosition = rootPositions.get(root);
if (rootPosition == -1)
continue;
HashMap typeMap = (HashMap) this.typesInWorkingCopies.get(pkg);
if (typeMap == null) {
typeMap = new HashMap();
this.typesInWorkingCopies.put(pkg, typeMap);
}
try {
IType[] types = workingCopy.getTypes();
int typeLength = types.length;
if (typeLength == 0) {
String typeName = Util.getNameWithoutJavaLikeExtension(workingCopy.getElementName());
typeMap.put(typeName, NO_TYPES);
} else {
for (int j = 0; j < typeLength; j++) {
IType type = types[j];
String typeName = type.getElementName();
Object existing = typeMap.get(typeName);
if (existing == null) {
typeMap.put(typeName, type);
} else if (existing instanceof IType) {
typeMap.put(typeName, new IType[] {(IType) existing, type});
} else {
IType[] existingTypes = (IType[]) existing;
int existingTypeLength = existingTypes.length;
System.arraycopy(existingTypes, 0, existingTypes = new IType[existingTypeLength+1], 0, existingTypeLength);
existingTypes[existingTypeLength] = type;
typeMap.put(typeName, existingTypes);
}
}
}
} catch (JavaModelException e) {
}
String[] pkgName = pkg.names;
Object existing = this.packageFragments.get(pkgName);
if (existing == null || existing == JavaProjectElementInfo.NO_ROOTS) {
this.packageFragments.put(pkgName, root);
JavaProjectElementInfo.addSuperPackageNames(pkgName, this.packageFragments);
} else {
if (existing instanceof PackageFragmentRoot) {
int exisitingPosition = rootPositions.get(existing);
if (rootPosition != exisitingPosition) {
this.packageFragments.put(
pkgName,
exisitingPosition < rootPosition ?
new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root} :
new IPackageFragmentRoot[] {root, (PackageFragmentRoot) existing});
}
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) existing;
int rootLength = roots.length;
int insertionIndex = 0;
for (int j = 0; j < rootLength; j++) {
int existingPosition = rootPositions.get(roots[j]);
if (rootPosition > existingPosition) {
insertionIndex = j;
} else if (rootPosition == existingPosition) {
insertionIndex = -1;
break;
} else if (rootPosition < existingPosition) {
break;
}
}
if (insertionIndex != -1) {
IPackageFragmentRoot[] newRoots = new IPackageFragmentRoot[rootLength+1];
System.arraycopy(roots, 0, newRoots, 0, insertionIndex);
newRoots[insertionIndex] = root;
System.arraycopy(roots, insertionIndex, newRoots, insertionIndex+1, rootLength-insertionIndex);
this.packageFragments.put(pkgName, newRoots);
}
}
}
}
}
this.rootToResolvedEntries = rootToResolvedEntries;
if (VERBOSE) {
Util.verbose(" -> spent: " + (System.currentTimeMillis() - start) + "ms");
}
}
protected boolean acceptType(IType type, int acceptFlags, boolean isSourceType) {
if (acceptFlags == 0 || acceptFlags == ACCEPT_ALL)
return true;
try {
int kind = isSourceType
? TypeDeclaration.kind(((SourceTypeElementInfo) ((SourceType) type).getElementInfo()).getModifiers())
: TypeDeclaration.kind(((IBinaryType) ((BinaryType) type).getElementInfo()).getModifiers());
switch (kind) {
case TypeDeclaration.CLASS_DECL :
return (acceptFlags & ACCEPT_CLASSES) != 0;
case TypeDeclaration.INTERFACE_DECL :
return (acceptFlags & ACCEPT_INTERFACES) != 0;
case TypeDeclaration.ENUM_DECL :
return (acceptFlags & ACCEPT_ENUMS) != 0;
default:
return (acceptFlags & ACCEPT_ANNOTATIONS) != 0;
}
} catch (JavaModelException npe) {
return false;
}
}
private void findAllTypes(String prefix, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
int count= this.packageFragmentRoots.length;
for (int i= 0; i < count; i++) {
if (requestor.isCanceled())
return;
IPackageFragmentRoot root= this.packageFragmentRoots[i];
IJavaElement[] packages= null;
try {
packages= root.getChildren();
} catch (JavaModelException npe) {
continue;
}
if (packages != null) {
for (int j= 0, packageCount= packages.length; j < packageCount; j++) {
if (requestor.isCanceled())
return;
seekTypes(prefix, (IPackageFragment) packages[j], partialMatch, acceptFlags, requestor);
}
}
}
}
public ICompilationUnit findCompilationUnit(String qualifiedTypeName) {
String[] pkgName = CharOperation.NO_STRINGS;
String cuName = qualifiedTypeName;
int index= qualifiedTypeName.lastIndexOf('.');
if (index != -1) {
pkgName= Util.splitOn('.', qualifiedTypeName, 0, index);
cuName= qualifiedTypeName.substring(index + 1);
}
index= cuName.indexOf('$');
if (index != -1) {
cuName= cuName.substring(0, index);
}
int pkgIndex = this.packageFragments.getIndex(pkgName);
if (pkgIndex != -1) {
Object value = this.packageFragments.valueTable[pkgIndex];
pkgName = (String[]) this.packageFragments.keyTable[pkgIndex];
if (value instanceof PackageFragmentRoot) {
return findCompilationUnit(pkgName, cuName, (PackageFragmentRoot) value);
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
for (int i= 0; i < roots.length; i++) {
PackageFragmentRoot root= (PackageFragmentRoot) roots[i];
ICompilationUnit cu = findCompilationUnit(pkgName, cuName, root);
if (cu != null)
return cu;
}
}
}
return null;
}
private ICompilationUnit findCompilationUnit(String[] pkgName, String cuName, PackageFragmentRoot root) {
if (!root.isArchive()) {
IPackageFragment pkg = root.getPackageFragment(pkgName);
try {
ICompilationUnit[] cus = pkg.getCompilationUnits();
for (int j = 0, length = cus.length; j < length; j++) {
ICompilationUnit cu = cus[j];
if (Util.equalsIgnoreJavaLikeExtension(cu.getElementName(), cuName))
return cu;
}
} catch (JavaModelException e) {
}
}
return null;
}
public IPackageFragment findPackageFragment(IPath path) {
if (!path.isAbsolute()) {
throw new IllegalArgumentException(Messages.path_mustBeAbsolute);
}
IResource possibleFragment = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
if (possibleFragment == null) {
for (int i = 0; i < this.packageFragmentRoots.length; i++) {
IPackageFragmentRoot root = this.packageFragmentRoots[i];
if (!root.isExternal()) {
continue;
}
IPath rootPath = root.getPath();
if (rootPath.isPrefixOf(path)) {
String name = path.toOSString();
name = name.substring(rootPath.toOSString().length() + 1, name.length());
name = name.replace(File.separatorChar, '.');
IJavaElement[] list = null;
try {
list = root.getChildren();
} catch (JavaModelException npe) {
continue;
}
int elementCount = list.length;
for (int j = 0; j < elementCount; j++) {
IPackageFragment packageFragment = (IPackageFragment) list[j];
if (nameMatches(name, packageFragment, false)) {
return packageFragment;
}
}
}
}
} else {
IJavaElement fromFactory = JavaCore.create(possibleFragment);
if (fromFactory == null) {
return null;
}
switch (fromFactory.getElementType()) {
case IJavaElement.PACKAGE_FRAGMENT:
return (IPackageFragment) fromFactory;
case IJavaElement.JAVA_PROJECT:
JavaProject project = (JavaProject) fromFactory;
try {
IClasspathEntry entry = project.getClasspathEntryFor(path);
if (entry != null) {
IPackageFragmentRoot root =
project.getPackageFragmentRoot(project.getResource());
Object defaultPkgRoot = this.packageFragments.get(CharOperation.NO_STRINGS);
if (defaultPkgRoot == null) {
return null;
}
if (defaultPkgRoot instanceof PackageFragmentRoot && defaultPkgRoot.equals(root))
return ((PackageFragmentRoot) root).getPackageFragment(CharOperation.NO_STRINGS);
else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) defaultPkgRoot;
for (int i = 0; i < roots.length; i++) {
if (roots[i].equals(root)) {
return ((PackageFragmentRoot) root).getPackageFragment(CharOperation.NO_STRINGS);
}
}
}
}
} catch (JavaModelException e) {
return null;
}
return null;
case IJavaElement.PACKAGE_FRAGMENT_ROOT:
return ((PackageFragmentRoot)fromFactory).getPackageFragment(CharOperation.NO_STRINGS);
}
}
return null;
}
public IPackageFragment[] findPackageFragments(String name, boolean partialMatch) {
return findPackageFragments(name, partialMatch, false);
}
public IPackageFragment[] findPackageFragments(String name, boolean partialMatch, boolean patternMatch) {
boolean isStarPattern = name.equals("*");
boolean hasPatternChars = isStarPattern || (patternMatch && (name.indexOf('*') >= 0 || name.indexOf('?') >= 0));
if (partialMatch || hasPatternChars) {
String[] splittedName = Util.splitOn('.', name, 0, name.length());
IPackageFragment[] oneFragment = null;
ArrayList pkgs = null;
char[] lowercaseName = hasPatternChars && !isStarPattern ? name.toLowerCase().toCharArray() : null;
Object[][] keys = this.packageFragments.keyTable;
for (int i = 0, length = keys.length; i < length; i++) {
String[] pkgName = (String[]) keys[i];
if (pkgName != null) {
boolean match = isStarPattern || (hasPatternChars
? CharOperation.match(lowercaseName, Util.concatCompoundNameToCharArray(pkgName), false)
: Util.startsWithIgnoreCase(pkgName, splittedName, partialMatch));
if (match) {
Object value = this.packageFragments.valueTable[i];
if (value instanceof PackageFragmentRoot) {
IPackageFragment pkg = ((PackageFragmentRoot) value).getPackageFragment(pkgName);
if (oneFragment == null) {
oneFragment = new IPackageFragment[] {pkg};
} else {
if (pkgs == null) {
pkgs = new ArrayList();
pkgs.add(oneFragment[0]);
}
pkgs.add(pkg);
}
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
for (int j = 0, length2 = roots.length; j < length2; j++) {
PackageFragmentRoot root = (PackageFragmentRoot) roots[j];
IPackageFragment pkg = root.getPackageFragment(pkgName);
if (oneFragment == null) {
oneFragment = new IPackageFragment[] {pkg};
} else {
if (pkgs == null) {
pkgs = new ArrayList();
pkgs.add(oneFragment[0]);
}
pkgs.add(pkg);
}
}
}
}
}
}
if (pkgs == null) return oneFragment;
int resultLength = pkgs.size();
IPackageFragment[] result = new IPackageFragment[resultLength];
pkgs.toArray(result);
return result;
} else {
String[] splittedName = Util.splitOn('.', name, 0, name.length());
int pkgIndex = this.packageFragments.getIndex(splittedName);
if (pkgIndex == -1)
return null;
Object value = this.packageFragments.valueTable[pkgIndex];
String[] pkgName = (String[]) this.packageFragments.keyTable[pkgIndex];
if (value instanceof PackageFragmentRoot) {
return new IPackageFragment[] {((PackageFragmentRoot) value).getPackageFragment(pkgName)};
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
IPackageFragment[] result = new IPackageFragment[roots.length];
for (int i= 0; i < roots.length; i++) {
result[i] = ((PackageFragmentRoot) roots[i]).getPackageFragment(pkgName);
}
return result;
}
}
}
private IType findSecondaryType(String packageName, String typeName, IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor) {
JavaModelManager manager = JavaModelManager.getJavaModelManager();
try {
IJavaProject javaProject = project;
Map<String, Map<String, IType>> secondaryTypePaths = manager.secondaryTypes(javaProject, waitForIndexes, monitor);
if (secondaryTypePaths.size() > 0) {
Map<String, IType> types = secondaryTypePaths.get(packageName==null?"":packageName);
if (types != null && types.size() > 0) {
IType type = types.get(typeName);
if (type != null) {
if (JavaModelManager.VERBOSE) {
Util.verbose("NameLookup FIND SECONDARY TYPES:");
Util.verbose(" -> pkg name: " + packageName);
Util.verbose(" -> type name: " + typeName);
Util.verbose(" -> project: "+project.getElementName());
Util.verbose(" -> type: " + type.getElementName());
}
return type;
}
}
}
}
catch (JavaModelException jme) {
}
return null;
}
public Answer findType(String typeName, String packageName, boolean partialMatch, int acceptFlags, boolean checkRestrictions, IPackageFragmentRoot[] moduleContext) {
return findType(typeName,
packageName,
partialMatch,
acceptFlags,
true,
false,
checkRestrictions,
null,
moduleContext);
}
public Answer findType(String typeName, String packageName, boolean partialMatch, int acceptFlags, boolean checkRestrictions) {
return findType(typeName,
packageName,
partialMatch,
acceptFlags,
true,
false,
checkRestrictions,
null);
}
public Answer findType(
String typeName,
String packageName,
boolean partialMatch,
int acceptFlags,
boolean considerSecondaryTypes,
boolean waitForIndexes,
boolean checkRestrictions,
IProgressMonitor monitor) {
return findType(typeName,
packageName,
partialMatch,
acceptFlags,
considerSecondaryTypes,
waitForIndexes,
checkRestrictions,
monitor,
null);
}
public Answer findType(
String typeName,
String packageName,
boolean partialMatch,
int acceptFlags,
boolean considerSecondaryTypes,
boolean waitForIndexes,
boolean checkRestrictions,
IProgressMonitor monitor,
IPackageFragmentRoot[] moduleContext) {
if (packageName == null || packageName.length() == 0) {
packageName= IPackageFragment.DEFAULT_PACKAGE_NAME;
} else if (typeName.length() > 0 && ScannerHelper.isLowerCase(typeName.charAt(0))) {
if (findPackageFragments(packageName + "." + typeName, false) != null) return null;
}
JavaElementRequestor elementRequestor = new JavaElementRequestor();
seekPackageFragments(packageName, false, elementRequestor, moduleContext);
IPackageFragment[] packages= elementRequestor.getPackageFragments();
IType type = null;
int length= packages.length;
HashSet projects = null;
IJavaProject javaProject = null;
Answer suggestedAnswer = null;
for (int i= 0; i < length; i++) {
type = findType(typeName, packages[i], partialMatch, acceptFlags, waitForIndexes, considerSecondaryTypes);
if (type != null) {
AccessRestriction accessRestriction = null;
PackageFragmentRoot root = (PackageFragmentRoot) type.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
ClasspathEntry entry = (ClasspathEntry) this.rootToResolvedEntries.get(root);
if (entry != null) {
if (checkRestrictions) {
accessRestriction = getViolatedRestriction(typeName, packageName, entry, accessRestriction);
}
}
Answer answer = new Answer(type, accessRestriction, entry,
getModuleDescription(this.rootProject, root, this.rootToModule, this.rootToResolvedEntries::get));
if (!answer.ignoreIfBetter()) {
if (answer.isBetter(suggestedAnswer))
return answer;
} else if (answer.isBetter(suggestedAnswer))
suggestedAnswer = answer;
}
else if (suggestedAnswer == null && considerSecondaryTypes) {
if (javaProject == null) {
javaProject = packages[i].getJavaProject();
} else if (projects == null) {
if (!javaProject.equals(packages[i].getJavaProject())) {
projects = new HashSet(3);
projects.add(javaProject);
projects.add(packages[i].getJavaProject());
}
} else {
projects.add(packages[i].getJavaProject());
}
}
}
if (suggestedAnswer != null)
return suggestedAnswer;
if (considerSecondaryTypes && javaProject != null) {
if (projects == null) {
type = findSecondaryType(packageName, typeName, javaProject, waitForIndexes, monitor);
} else {
Iterator allProjects = projects.iterator();
while (type == null && allProjects.hasNext()) {
type = findSecondaryType(packageName, typeName, (IJavaProject) allProjects.next(), waitForIndexes, monitor);
}
}
}
if (type != null) {
ICompilationUnit unit = type.getCompilationUnit();
if (unit != null && unit.isWorkingCopy()) {
IType[] types = null;
try {
types = unit.getTypes();
} catch (JavaModelException e) {
return null;
}
boolean typeFound = false;
for (int i = 0, typesLength = types == null ? 0 : types.length; i < typesLength; i++) {
if (types[i].getElementName().equals(typeName)) {
typeFound = true;
break;
}
}
if (!typeFound) type = null;
}
}
return type == null ? null : new Answer(type, null, null);
}
public static IModule getModuleDescriptionInfo(IModuleDescription moduleDesc) {
if (moduleDesc != null) {
try {
if (moduleDesc instanceof AutoModule) {
boolean nameFromManifest = ((AutoModule) moduleDesc).isAutoNameFromManifest();
return IModule.createAutomatic(moduleDesc.getElementName().toCharArray(), nameFromManifest);
} else {
return ((AbstractModule) moduleDesc).getModuleInfo();
}
} catch (JavaModelException e) {
if (!e.isDoesNotExist())
Util.log(e);
}
}
return null;
}
static IModuleDescription getModuleDescription(JavaProject project, IPackageFragmentRoot root, Map<IPackageFragmentRoot,IModuleDescription> cache, Function<IPackageFragmentRoot,IClasspathEntry> rootToEntry) {
IModuleDescription module = cache.get(root);
if (module != null)
return module != NO_MODULE ? module : null;
if (!Objects.equals(project, root.getJavaProject())) {
IClasspathEntry classpathEntry2 = rootToEntry.apply(root);
if (classpathEntry2 instanceof ClasspathEntry) {
if (!((ClasspathEntry) classpathEntry2).isModular()) {
cache.put(root, NO_MODULE);
return null;
}
}
}
try {
if (root.getKind() == IPackageFragmentRoot.K_SOURCE)
module = root.getJavaProject().getModuleDescription();
} catch (JavaModelException e) {
cache.put(root, NO_MODULE);
return null;
}
if (module == null) {
IClasspathEntry classpathEntry = rootToEntry.apply(root);
if (classpathEntry instanceof ClasspathEntry) {
if (((ClasspathEntry) classpathEntry).isModular()) {
module = root.getModuleDescription();
if (module == null) {
module = ((PackageFragmentRoot) root).getAutomaticModuleDescription(classpathEntry);
}
}
} else if (root instanceof JrtPackageFragmentRoot) {
module = root.getModuleDescription();
}
}
cache.put(root, module != null ? module : NO_MODULE);
return module;
}
public IModule getModuleDescriptionInfo(PackageFragmentRoot root) {
IModuleDescription desc = getModuleDescription(this.rootProject, root, this.rootToModule, this.rootToResolvedEntries::get);
if (desc != null) {
return getModuleDescriptionInfo(desc);
}
return null;
}
private AccessRestriction getViolatedRestriction(String typeName, String packageName, ClasspathEntry entry, AccessRestriction accessRestriction) {
AccessRuleSet accessRuleSet = entry.getAccessRuleSet();
if (accessRuleSet != null) {
char[][] packageChars = CharOperation.splitOn('.', packageName.toCharArray());
char[] typeChars = typeName.toCharArray();
accessRestriction = accessRuleSet.getViolatedRestriction(CharOperation.concatWith(packageChars, typeChars, '/'));
}
return accessRestriction;
}
public IType findType(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, boolean waitForIndices, boolean considerSecondaryTypes) {
if (pkg == null)
return null;
SingleTypeRequestor typeRequestor = new SingleTypeRequestor();
seekTypes(name, pkg, partialMatch, acceptFlags, typeRequestor, considerSecondaryTypes);
IType type = typeRequestor.getType();
if (type == null && considerSecondaryTypes) {
type = findSecondaryType(pkg.getElementName(), name, pkg.getJavaProject(), waitForIndices, null);
}
return type;
}
public IType findType(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags) {
if (pkg == null) return null;
SingleTypeRequestor typeRequestor = new SingleTypeRequestor();
seekTypes(name, pkg, partialMatch, acceptFlags, typeRequestor, false);
return typeRequestor.getType();
}
public IType findType(String name, boolean partialMatch, int acceptFlags) {
NameLookup.Answer answer = findType(name, partialMatch, acceptFlags, false);
return answer == null ? null : answer.type;
}
public Answer findType(String name, boolean partialMatch, int acceptFlags, boolean checkRestrictions) {
return findType(name, partialMatch, acceptFlags, true, true, checkRestrictions, null);
}
public Answer findType(String name, boolean partialMatch, int acceptFlags, boolean considerSecondaryTypes, boolean waitForIndexes, boolean checkRestrictions, IProgressMonitor monitor) {
int index= name.lastIndexOf('.');
if (index == 0) {
return null;
}
String className= null, packageName= null;
if (index == -1) {
packageName= IPackageFragment.DEFAULT_PACKAGE_NAME;
className= name;
} else {
packageName= name.substring(0, index);
className= name.substring(index + 1);
}
return findType(className, packageName, partialMatch, acceptFlags, considerSecondaryTypes, waitForIndexes, checkRestrictions, monitor);
}
public Answer findModule(char[] moduleName) {
JavaElementRequestor requestor = new JavaElementRequestor();
seekModule(moduleName, false, requestor);
IModuleDescription[] modules = requestor.getModules();
if (modules.length == 0) {
try {
JavaModelManager.getModulePathManager().seekModule(moduleName, false, requestor);
modules = requestor.getModules();
} catch (JavaModelException e) {
}
}
if (modules.length > 0) {
return new Answer(modules[0]);
}
return null;
}
private IType getMemberType(IType type, String name, int dot) {
while (dot != -1) {
int start = dot+1;
dot = name.indexOf('.', start);
String typeName = name.substring(start, dot == -1 ? name.length() : dot);
type = type.getType(typeName);
}
return type;
}
public boolean isPackage(String[] pkgName) {
return this.packageFragments.get(pkgName) != null;
}
public boolean isPackage(String[] pkgName, IPackageFragmentRoot[] moduleContext) {
if (moduleContext == null)
return isPackage(pkgName);
for (IPackageFragmentRoot moduleRoot : moduleContext) {
if (moduleRoot.getPackageFragment(String.join(".", pkgName)).exists())
return true;
}
return false;
}
private boolean moduleMatches(IPackageFragmentRoot root, IPackageFragmentRoot[] moduleContext) {
for (IPackageFragmentRoot moduleRoot : moduleContext)
if (moduleRoot.equals(root))
return true;
return false;
}
protected boolean nameMatches(String searchName, IJavaElement element, boolean partialMatch) {
if (partialMatch) {
return element.getElementName().toLowerCase().startsWith(searchName);
} else {
return element.getElementName().equals(searchName);
}
}
protected boolean nameMatches(String searchName, ICompilationUnit cu, boolean partialMatch) {
if (partialMatch) {
return cu.getElementName().toLowerCase().startsWith(searchName);
} else {
return Util.equalsIgnoreJavaLikeExtension(cu.getElementName(), searchName);
}
}
public void seekPackageFragments(String name, boolean partialMatch, IJavaElementRequestor requestor, IPackageFragmentRoot[] moduleContext) {
if (moduleContext == null) {
seekPackageFragments(name, partialMatch, requestor);
return;
}
if (partialMatch) {
seekModuleAwarePartialPackageFragments(name, requestor, moduleContext);
return;
}
for (IPackageFragmentRoot moduleRoot : moduleContext) {
IPackageFragment fragment = moduleRoot.getPackageFragment(name);
if (fragment.exists())
requestor.acceptPackageFragment(fragment);
}
}
public void seekTypes(String pkgName, String name, boolean partialMatch, IJavaElementRequestor requestor,
int acceptFlags, IPackageFragmentRoot[] moduleContext, String moduleName) {
Selector selector = new Selector(moduleName);
seekPackageFragments(pkgName, true , selector, moduleContext);
if (selector.pkgFragments.size() == 0) return;
for (IPackageFragment pkg : selector.pkgFragments) {
seekTypes(name, pkg, partialMatch, acceptFlags, requestor);
}
}
private void seekModuleAwarePartialPackageFragments(String name, IJavaElementRequestor requestor, IPackageFragmentRoot[] moduleContext) {
boolean allPrefixMatch = CharOperation.equals(name.toCharArray(), CharOperation.ALL_PREFIX);
String lName = name.toLowerCase();
Arrays.stream(this.packageFragments.keyTable)
.filter(k -> k != null)
.filter(k -> allPrefixMatch || Util.concatWith((String[])k, '.').toLowerCase().startsWith(lName))
.forEach(k -> {
checkModulePackages(requestor, moduleContext, this.packageFragments.getIndex(k));
});
}
private void checkModulePackages(IJavaElementRequestor requestor, IPackageFragmentRoot[] moduleContext, int pkgIndex) {
Object value = this.packageFragments.valueTable[pkgIndex];
String[] pkgName = (String[]) this.packageFragments.keyTable[pkgIndex];
if (value instanceof PackageFragmentRoot) {
PackageFragmentRoot root = (PackageFragmentRoot) value;
if (moduleMatches(root, moduleContext))
requestor.acceptPackageFragment(root.getPackageFragment(pkgName));
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
if (roots != null) {
for (int i = 0, length = roots.length; i < length; i++) {
if (requestor.isCanceled())
return;
PackageFragmentRoot root = (PackageFragmentRoot) roots[i];
if (moduleMatches(root, moduleContext))
requestor.acceptPackageFragment(root.getPackageFragment(pkgName));
}
}
}
}
@FunctionalInterface
interface IPrefixMatcherCharArray {
boolean matches(char[] prefix, char[] name, boolean isCaseSensitive);
}
public void seekPackageFragments(String name, boolean partialMatch, IJavaElementRequestor requestor) {
if (partialMatch) {
String[] splittedName = Util.splitOn('.', name, 0, name.length());
Object[][] keys = this.packageFragments.keyTable;
for (int i = 0, length = keys.length; i < length; i++) {
if (requestor.isCanceled())
return;
String[] pkgName = (String[]) keys[i];
if (pkgName != null && Util.startsWithIgnoreCase(pkgName, splittedName, partialMatch)) {
Object value = this.packageFragments.valueTable[i];
if (value instanceof PackageFragmentRoot) {
PackageFragmentRoot root = (PackageFragmentRoot) value;
requestor.acceptPackageFragment(root.getPackageFragment(pkgName));
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
for (int j = 0, length2 = roots.length; j < length2; j++) {
if (requestor.isCanceled())
return;
PackageFragmentRoot root = (PackageFragmentRoot) roots[j];
requestor.acceptPackageFragment(root.getPackageFragment(pkgName));
}
}
}
}
} else {
String[] splittedName = Util.splitOn('.', name, 0, name.length());
int pkgIndex = this.packageFragments.getIndex(splittedName);
if (pkgIndex != -1) {
Object value = this.packageFragments.valueTable[pkgIndex];
String[] pkgName = (String[]) this.packageFragments.keyTable[pkgIndex];
if (value instanceof PackageFragmentRoot) {
requestor.acceptPackageFragment(((PackageFragmentRoot) value).getPackageFragment(pkgName));
} else {
IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
if (roots != null) {
for (int i = 0, length = roots.length; i < length; i++) {
if (requestor.isCanceled())
return;
PackageFragmentRoot root = (PackageFragmentRoot) roots[i];
requestor.acceptPackageFragment(root.getPackageFragment(pkgName));
}
}
}
}
}
}
public void seekTypes(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
seekTypes(name, pkg, partialMatch, acceptFlags, requestor, true);
}
public void seekModuleReferences(String name, IJavaElementRequestor requestor, IJavaProject javaProject) {
seekModule(name.toCharArray(), true , requestor);
}
public void seekModule(char[] name, boolean prefixMatch, IJavaElementRequestor requestor) {
IPrefixMatcherCharArray prefixMatcher = prefixMatch
? CharOperation.equals(name, CharOperation.ALL_PREFIX)
? (x, y, isCaseSensitive) -> true
: CharOperation::prefixEquals
: CharOperation::equals;
int count= this.packageFragmentRoots.length;
for (int i= 0; i < count; i++) {
if (requestor.isCanceled())
return;
IPackageFragmentRoot root= this.packageFragmentRoots[i];
IModuleDescription module = null;
if (root instanceof JrtPackageFragmentRoot) {
if (!prefixMatcher.matches(name, root.getElementName().toCharArray(), false)) {
continue;
}
}
module = getModuleDescription(this.rootProject, root, this.rootToModule, this.rootToResolvedEntries::get);
if (module != null && prefixMatcher.matches(name, module.getElementName().toCharArray(), false)) {
requestor.acceptModule(module);
}
}
}
public void seekTypes(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor, boolean considerSecondaryTypes) {
String matchName= partialMatch ? name.toLowerCase() : name;
if (pkg == null) {
findAllTypes(matchName, partialMatch, acceptFlags, requestor);
return;
}
PackageFragmentRoot root= (PackageFragmentRoot) pkg.getParent();
try {
int firstDot = -1;
String topLevelTypeName = null;
int packageFlavor= root.internalKind();
if (this.typesInWorkingCopies != null || packageFlavor == IPackageFragmentRoot.K_SOURCE) {
firstDot = matchName.indexOf('.');
if (!partialMatch)
topLevelTypeName = firstDot == -1 ? matchName : matchName.substring(0, firstDot);
}
if (this.typesInWorkingCopies != null) {
if (seekTypesInWorkingCopies(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor, considerSecondaryTypes))
return;
}
switch (packageFlavor) {
case IPackageFragmentRoot.K_BINARY :
matchName= matchName.replace('.', '$');
seekTypesInBinaryPackage(matchName, pkg, partialMatch, acceptFlags, requestor);
break;
case IPackageFragmentRoot.K_SOURCE :
seekTypesInSourcePackage(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor);
if (matchName.indexOf('$') != -1) {
matchName= matchName.replace('$', '.');
firstDot = matchName.indexOf('.');
if (!partialMatch)
topLevelTypeName = firstDot == -1 ? matchName : matchName.substring(0, firstDot);
seekTypesInSourcePackage(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor);
}
break;
default :
return;
}
} catch (JavaModelException e) {
return;
}
}
protected void seekTypesInBinaryPackage(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
long start = -1;
if (VERBOSE)
start = System.currentTimeMillis();
try {
if (!partialMatch) {
if (requestor.isCanceled()) return;
ClassFile classFile = new ClassFile((PackageFragment) pkg, name);
if (classFile.existsUsingJarTypeCache()) {
IType type = classFile.getType();
if (acceptType(type, acceptFlags, false)) {
requestor.acceptType(type);
}
}
} else {
IJavaElement[] classFiles= null;
try {
classFiles= pkg.getChildren();
} catch (JavaModelException npe) {
return;
}
int length= classFiles.length;
String unqualifiedName = name;
int index = name.lastIndexOf('$');
if (index != -1) {
unqualifiedName = Util.localTypeName(name, index, name.length());
}
int matchLength = name.length();
for (int i = 0; i < length; i++) {
if (requestor.isCanceled())
return;
IJavaElement classFile= classFiles[i];
String elementName = classFile.getElementName();
if (elementName.regionMatches(true , 0, name, 0, matchLength)) {
if (classFile instanceof IOrdinaryClassFile) {
IType type = ((IOrdinaryClassFile) classFile).getType();
String typeName = type.getElementName();
if (typeName.length() > 0 && !Character.isDigit(typeName.charAt(0))) {
if (nameMatches(unqualifiedName, type, true) && acceptType(type, acceptFlags, false))
requestor.acceptType(type);
}
}
}
}
}
} finally {
if (VERBOSE)
this.timeSpentInSeekTypesInBinaryPackage += System.currentTimeMillis()-start;
}
}
protected void seekTypesInSourcePackage(
String name,
IPackageFragment pkg,
int firstDot,
boolean partialMatch,
String topLevelTypeName,
int acceptFlags,
IJavaElementRequestor requestor) {
long start = -1;
if (VERBOSE)
start = System.currentTimeMillis();
try {
if (!partialMatch) {
try {
IJavaElement[] compilationUnits = pkg.getChildren();
for (int i = 0, length = compilationUnits.length; i < length; i++) {
if (requestor.isCanceled())
return;
IJavaElement cu = compilationUnits[i];
String cuName = cu.getElementName();
int lastDot = cuName.lastIndexOf('.');
if (lastDot != topLevelTypeName.length() || !topLevelTypeName.regionMatches(0, cuName, 0, lastDot))
continue;
if (!(cu instanceof ICompilationUnit))
continue;
IType type = ((ICompilationUnit) cu).getType(topLevelTypeName);
type = getMemberType(type, name, firstDot);
if (acceptType(type, acceptFlags, true)) {
requestor.acceptType(type);
break;
}
}
} catch (JavaModelException e) {
}
} else {
try {
String cuPrefix = firstDot == -1 ? name : name.substring(0, firstDot);
IJavaElement[] compilationUnits = pkg.getChildren();
for (int i = 0, length = compilationUnits.length; i < length; i++) {
if (requestor.isCanceled())
return;
IJavaElement cu = compilationUnits[i];
if (!cu.getElementName().toLowerCase().startsWith(cuPrefix))
continue;
try {
IType[] types = ((ICompilationUnit) cu).getTypes();
for (int j = 0, typeLength = types.length; j < typeLength; j++)
seekTypesInTopLevelType(name, firstDot, types[j], requestor, acceptFlags);
} catch (JavaModelException e) {
}
}
} catch (JavaModelException e) {
}
}
} finally {
if (VERBOSE)
this.timeSpentInSeekTypesInSourcePackage += System.currentTimeMillis()-start;
}
}
private boolean isPrimaryType(String name, IType type, boolean partialMatch) {
ICompilationUnit cu = (ICompilationUnit) type.getParent();
String cuName = cu.getElementName().substring(0, cu.getElementName().lastIndexOf('.'));
if (!cuName.equals(type.getElementName()))
return false;
if (partialMatch) {
return cuName.regionMatches(0, name, 0, name.length());
} else {
return cuName.equals(name);
}
}
protected boolean seekTypesInType(String prefix, int firstDot, IType type, IJavaElementRequestor requestor, int acceptFlags) {
IType[] types= null;
try {
types= type.getTypes();
} catch (JavaModelException npe) {
return false;
}
int length= types.length;
if (length == 0) return false;
String memberPrefix = prefix;
boolean isMemberTypePrefix = false;
if (firstDot != -1) {
memberPrefix= prefix.substring(0, firstDot);
isMemberTypePrefix = true;
}
for (int i= 0; i < length; i++) {
if (requestor.isCanceled())
return false;
IType memberType= types[i];
if (memberType.getElementName().toLowerCase().startsWith(memberPrefix))
if (isMemberTypePrefix) {
String subPrefix = prefix.substring(firstDot + 1, prefix.length());
return seekTypesInType(subPrefix, subPrefix.indexOf('.'), memberType, requestor, acceptFlags);
} else {
if (acceptType(memberType, acceptFlags, true)) {
requestor.acceptMemberType(memberType);
return true;
}
}
}
return false;
}
protected boolean seekTypesInTopLevelType(String prefix, int firstDot, IType topLevelType, IJavaElementRequestor requestor, int acceptFlags) {
if (!topLevelType.getElementName().toLowerCase().startsWith(prefix))
return false;
if (firstDot == -1) {
if (acceptType(topLevelType, acceptFlags, true)) {
requestor.acceptType(topLevelType);
return true;
}
} else {
return seekTypesInType(prefix, firstDot, topLevelType, requestor, acceptFlags);
}
return false;
}
protected boolean seekTypesInWorkingCopies(
String name,
IPackageFragment pkg,
int firstDot,
boolean partialMatch,
String topLevelTypeName,
int acceptFlags,
IJavaElementRequestor requestor,
boolean considerSecondaryTypes) {
if (!partialMatch) {
HashMap typeMap = (HashMap) (this.typesInWorkingCopies == null ? null : this.typesInWorkingCopies.get(pkg));
if (typeMap != null) {
Object object = typeMap.get(topLevelTypeName);
if (object instanceof IType) {
IType type = getMemberType((IType) object, name, firstDot);
if (!considerSecondaryTypes && !isPrimaryType(name, (IType) object, false))
return false;
if (acceptType(type, acceptFlags, true)) {
requestor.acceptType(type);
return true;
}
} else if (object instanceof IType[]) {
if (object == NO_TYPES) {
String packageInfoName = String.valueOf(TypeConstants.PACKAGE_INFO_NAME);
if (packageInfoName.equals(name))
requestor.acceptType(pkg.getCompilationUnit(packageInfoName.concat(SUFFIX_STRING_java)).getType(name));
return true;
}
IType[] topLevelTypes = (IType[]) object;
for (int i = 0, length = topLevelTypes.length; i < length; i++) {
if (requestor.isCanceled())
return false;
IType type = getMemberType(topLevelTypes[i], name, firstDot);
if (acceptType(type, acceptFlags, true)) {
requestor.acceptType(type);
return true;
}
}
}
}
} else {
HashMap typeMap = (HashMap) (this.typesInWorkingCopies == null ? null : this.typesInWorkingCopies.get(pkg));
if (typeMap != null) {
Iterator iterator = typeMap.values().iterator();
while (iterator.hasNext()) {
if (requestor.isCanceled())
return false;
Object object = iterator.next();
if (object instanceof IType) {
if (!considerSecondaryTypes && !isPrimaryType(name, (IType) object, true))
continue;
seekTypesInTopLevelType(name, firstDot, (IType) object, requestor, acceptFlags);
} else if (object instanceof IType[]) {
IType[] topLevelTypes = (IType[]) object;
for (int i = 0, length = topLevelTypes.length; i < length; i++)
seekTypesInTopLevelType(name, firstDot, topLevelTypes[i], requestor, acceptFlags);
}
}
}
}
return false;
}
public boolean hasCompilationUnit(char[][] pkgName, IPackageFragmentRoot[] moduleContext) {
String packageName = CharOperation.toString(pkgName);
if (packageName == null || packageName.length() == 0) {
packageName= IPackageFragment.DEFAULT_PACKAGE_NAME;
}
JavaElementRequestor elementRequestor = new JavaElementRequestor();
seekPackageFragments(packageName, false, elementRequestor, moduleContext);
IPackageFragment[] packages= elementRequestor.getPackageFragments();
for (IPackageFragment fragment : packages) {
try {
if (fragment.containsJavaResources())
return true;
} catch (JavaModelException e) {
}
}
return false;
}
}