blob: 286edf74e2981f93f617f57f66934634016ec67c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 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 - Contribution for
* Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
import static java.util.stream.Collectors.joining;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
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.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IModule;
import org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.JavaElementRequestor;
import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.PackageFragmentRoot;
import org.eclipse.jdt.internal.core.builder.ClasspathLocation;
import org.eclipse.jdt.internal.core.util.Util;
/*
* A name environment based on the classpath of a Java project.
*/
public class JavaSearchNameEnvironment implements IModuleAwareNameEnvironment, SuffixConstants {
protected /* visible for testing only */ LinkedHashSet<ClasspathLocation> locationSet;
Map<String, IModuleDescription> modules;
private boolean modulesComputed = false;
Map<String,ClasspathLocation> moduleLocations;
Map<String,LinkedHashSet<ClasspathLocation>> moduleToClassPathLocations;
/** an index of qualified package names (separated by / not .) to classpath locations */
protected /* visible for testing only */ Map<String,LinkedHashSet<ClasspathLocation>> packageNameToClassPathLocations;
/*
* A map from the fully qualified slash-separated name of the main type (String) to the working copy
*/
Map<String, org.eclipse.jdt.core.ICompilationUnit> workingCopies;
public JavaSearchNameEnvironment(IJavaProject javaProject, org.eclipse.jdt.core.ICompilationUnit[] copies) {
if (isComplianceJava9OrHigher(javaProject)) {
this.moduleLocations = new HashMap<>();
this.moduleToClassPathLocations = new HashMap<>();
}
this.modules = new HashMap<>();
this.packageNameToClassPathLocations = new HashMap<>();
long start = 0;
if (NameLookup.VERBOSE) {
Util.verbose(" BUILDING JavaSearchNameEnvironment"); //$NON-NLS-1$
Util.verbose(" -> project: " + javaProject); //$NON-NLS-1$
Util.verbose(" -> working copy size: " + (copies == null ? 0 : copies.length)); //$NON-NLS-1$
start = System.currentTimeMillis();
}
this.locationSet = computeClasspathLocations((JavaProject) javaProject);
this.workingCopies = getWorkingCopyMap(copies);
// if there are working copies, we need to index their packages too
if(this.workingCopies.size() > 0) {
Optional<ClasspathLocation> firstSrcLocation = this.locationSet.stream().filter(cp -> cp instanceof ClasspathSourceDirectory).findFirst();
if(!firstSrcLocation.isPresent()) {
/*
* Specifying working copies but not providing a project with a source folder is not supported by the current implementation.
* I'm not sure if this is valid use case, though.
*
* However, there is one test that (potentially) relies on this behavior. At lease it expects this constructor to NOT fail.
*
* org.eclipse.jdt.core.tests.model.ClassFileTests.testWorkingCopy11()
*/
//throw new IllegalArgumentException("Missing source folder for searching working copies: " + javaProject); //$NON-NLS-1$
if (NameLookup.VERBOSE) {
Util.verbose(" -> ignoring working copies; no ClasspathSourceDirectory on project classpath "); //$NON-NLS-1$
}
} else {
for (String qualifiedMainTypeName : this.workingCopies.keySet()) {
int typeNameStart = qualifiedMainTypeName.lastIndexOf('/');
if(typeNameStart > 0) {
String pkgName = qualifiedMainTypeName.substring(0, typeNameStart);
addPackageNameToIndex(firstSrcLocation.get(), pkgName);
} else {
addPackageNameToIndex(firstSrcLocation.get(), IPackageFragment.DEFAULT_PACKAGE_NAME);
}
}
}
}
if (NameLookup.VERBOSE) {
Util.verbose(" -> pkg roots size: " + (this.locationSet == null ? 0 : this.locationSet.size())); //$NON-NLS-1$
Util.verbose(" -> pkgs size: " + this.packageNameToClassPathLocations.size()); //$NON-NLS-1$
Util.verbose(" -> spent: " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public static Map<String, org.eclipse.jdt.core.ICompilationUnit> getWorkingCopyMap(
org.eclipse.jdt.core.ICompilationUnit[] copies) {
int length = copies == null ? 0 : copies.length;
HashMap<String, org.eclipse.jdt.core.ICompilationUnit> result = new HashMap<>(length);
try {
if (copies != null) {
for (int i = 0; i < length; i++) {
org.eclipse.jdt.core.ICompilationUnit workingCopy = copies[i];
IPackageDeclaration[] pkgs = workingCopy.getPackageDeclarations();
String pkg = pkgs.length > 0 ? pkgs[0].getElementName() : ""; //$NON-NLS-1$
String cuName = workingCopy.getElementName();
String mainTypeName = Util.getNameWithoutJavaLikeExtension(cuName);
String qualifiedMainTypeName = pkg.length() == 0 ? mainTypeName : pkg.replace('.', '/') + '/' + mainTypeName;
result.put(qualifiedMainTypeName, workingCopy);
// TODO : JAVA 9 - module-info.java has the same name across modules - Any issues here?
}
}
} catch (JavaModelException e) {
// working copy doesn't exist: cannot happen
}
return result;
}
@Override
public void cleanup() {
this.locationSet.clear();
this.packageNameToClassPathLocations.clear();
}
protected /* visible for testing only */ void addProjectClassPath(JavaProject javaProject) {
long start = 0;
if (NameLookup.VERBOSE) {
Util.verbose(" EXTENDING JavaSearchNameEnvironment"); //$NON-NLS-1$
Util.verbose(" -> project: " + javaProject); //$NON-NLS-1$
start = System.currentTimeMillis();
}
LinkedHashSet<ClasspathLocation> locations = computeClasspathLocations(javaProject);
if (locations != null) this.locationSet.addAll(locations);
if (NameLookup.VERBOSE) {
Util.verbose(" -> pkg roots size: " + (this.locationSet == null ? 0 : this.locationSet.size())); //$NON-NLS-1$
Util.verbose(" -> pkgs size: " + this.packageNameToClassPathLocations.size()); //$NON-NLS-1$
Util.verbose(" -> spent: " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
private LinkedHashSet<ClasspathLocation> computeClasspathLocations(JavaProject javaProject) {
IPackageFragmentRoot[] roots = null;
try {
roots = javaProject.getAllPackageFragmentRoots();
} catch (JavaModelException e) {
return null;// project doesn't exist
}
IModuleDescription imd = null;
try {
imd = javaProject.getModuleDescription();
} catch (JavaModelException e) {
// e.printStackTrace(); // ignore
}
LinkedHashSet<ClasspathLocation> locations = new LinkedHashSet<ClasspathLocation>();
int length = roots.length;
JavaModelManager manager = JavaModelManager.getJavaModelManager();
for (int i = 0; i < length; i++) {
ClasspathLocation cp = mapToClassPathLocation(manager, (PackageFragmentRoot) roots[i], imd, locations);
if (cp != null) {
try {
indexPackageNames(cp, roots[i]);
locations.add(cp);
} catch (JavaModelException e) {
Util.log(e, "Error indexing package names!"); //$NON-NLS-1$
}
}
}
return locations;
}
private void indexPackageNames(ClasspathLocation cp, IPackageFragmentRoot root) throws JavaModelException {
for (IJavaElement c : root.getChildren()) {
String qualifiedPackageName = c.getElementName().replace('.', '/');
addPackageNameToIndex(cp, qualifiedPackageName);
}
/* In theory IPackageFragmentRoot#getChildren should contain all. It always returns
* the default package (no matter what). However, for some reason only JarPackageFragmentRoot#getChildren
* really returns all children. PackageFragmentRoot#getChildren returns ONLY the default package for binary class folders.
*
* We therefore also go through listPackages as well
*/
char[][] packages = cp.listPackages();
if(packages != null) {
for (char[] packageName : packages) {
String qualifiedPackageName = CharOperation.charToString(packageName).replace('.', '/');
addPackageNameToIndex(cp, qualifiedPackageName);
}
}
}
private void addPackageNameToIndex(ClasspathLocation cp, String qualifiedPackageName) {
LinkedHashSet<ClasspathLocation> cpl = this.packageNameToClassPathLocations.get(qualifiedPackageName);
if(cpl == null) {
this.packageNameToClassPathLocations.put(qualifiedPackageName, cpl = new LinkedHashSet<>());
}
cpl.add(cp);
}
private void computeModules() {
if (!this.modulesComputed) {
this.modulesComputed = true;
JavaElementRequestor requestor = new JavaElementRequestor();
try {
JavaModelManager.getModulePathManager().seekModule(CharOperation.ALL_PREFIX, true, requestor);
IModuleDescription[] mods = requestor.getModules();
for (IModuleDescription mod : mods) {
this.modules.putIfAbsent(mod.getElementName(), mod);
}
} catch (JavaModelException e) {
// do nothing
}
}
}
private ClasspathLocation mapToClassPathLocation(JavaModelManager manager, PackageFragmentRoot root, IModuleDescription defaultModule, Collection<ClasspathLocation> allLocations) {
ClasspathLocation cp = null;
IPath path = root.getPath();
try {
if (root.isArchive()) {
ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
IJavaProject project = (IJavaProject) root.getParent();
String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
cp = (root instanceof JrtPackageFragmentRoot) ?
ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(),
rawClasspathEntry.getExternalAnnotationPath(project.getProject(), true), compliance) :
ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(),
rawClasspathEntry.getExternalAnnotationPath(((IJavaProject) root.getParent()).getProject(), true),
rawClasspathEntry.isModular(), compliance) ;
} else {
Object target = JavaModel.getTarget(path, true);
if (target != null) {
if (root.getKind() == IPackageFragmentRoot.K_SOURCE) {
cp = new ClasspathSourceDirectory((IContainer)target, root.fullExclusionPatternChars(), root.fullInclusionPatternChars());
} else {
ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
cp = ClasspathLocation.forBinaryFolder((IContainer) target, false, rawClasspathEntry.getAccessRuleSet(),
rawClasspathEntry.getExternalAnnotationPath(((IJavaProject)root.getParent()).getProject(), true),
rawClasspathEntry.isModular());
}
}
}
} catch (CoreException e1) {
// problem opening zip file or getting root kind
// consider root corrupt and ignore
}
JavaProject javaProject = root.getJavaProject();
if (isComplianceJava9OrHigher(javaProject)) {
addModuleClassPathInfo(root, defaultModule, cp);
}
if (allLocations != null && cp != null && JavaCore.ENABLED.equals(javaProject.getOption(JavaCore.CORE_JAVA_BUILD_EXTERNAL_ANNOTATIONS_FROM_ALL_LOCATIONS, true))) {
cp.connectAllLocationsForEEA(allLocations, false/*allLocations is already accumulated by our caller*/);
}
return cp;
}
private void addModuleClassPathInfo(PackageFragmentRoot root, IModuleDescription defaultModule, ClasspathLocation cp) {
IModuleDescription imd = root.getModuleDescription();
if (imd != null) {
String moduleName = addModuleClassPathInfo(cp, imd);
if (moduleName != null)
this.modules.put(moduleName, imd);
if (this.moduleLocations != null)
this.moduleLocations.put(moduleName, cp);
} else if (defaultModule != null) {
addModuleClassPathInfo(cp, defaultModule);
}
}
private String addModuleClassPathInfo(ClasspathLocation cp, IModuleDescription imd) {
IModule mod = NameLookup.getModuleDescriptionInfo(imd);
String moduleName = null;
if (mod != null && cp != null) {
char[] name = mod.name();
if (name != null) {
moduleName = new String(name);
cp.setModule(mod);
addClassPathToModule(moduleName, cp);
}
}
return moduleName;
}
private void addClassPathToModule(String moduleName, ClasspathLocation cp) {
if (this.moduleToClassPathLocations != null) {
LinkedHashSet<ClasspathLocation> l = this.moduleToClassPathLocations.get(moduleName);
if (l == null) {
l = new LinkedHashSet<>();
this.moduleToClassPathLocations.put(moduleName, l);
}
l.add(cp);
}
}
private NameEnvironmentAnswer findClass(String qualifiedTypeName, char[] typeName, LookupStrategy strategy, /*@Nullable*/String moduleName) {
String
binaryFileName = null, qBinaryFileName = null,
sourceFileName = null, qSourceFileName = null;
final String qPackageName;
final int typeNameStart;
if (qualifiedTypeName.length() > typeName.length) {
typeNameStart = qualifiedTypeName.length() - typeName.length;
qPackageName = qualifiedTypeName.substring(0, typeNameStart - 1);
} else {
typeNameStart = 0;
qPackageName = ""; //$NON-NLS-1$
}
NameEnvironmentAnswer suggestedAnswer = null;
for (ClasspathLocation location : getLocationsFor(moduleName, qPackageName)) {
if (!strategy.matches(location, ClasspathLocation::hasModule))
continue;
NameEnvironmentAnswer answer;
if (location instanceof ClasspathSourceDirectory) {
if (sourceFileName == null) {
qSourceFileName = qualifiedTypeName; // doesn't include the file extension
sourceFileName = qSourceFileName;
if (typeNameStart > 0) {
sourceFileName = qSourceFileName.substring(typeNameStart);
}
}
ICompilationUnit workingCopy = (ICompilationUnit) this.workingCopies.get(qualifiedTypeName);
if (workingCopy != null) {
answer = new NameEnvironmentAnswer(workingCopy, null /*no access restriction*/);
} else {
answer = location.findClass(
sourceFileName, // doesn't include the file extension
qPackageName,
moduleName,
qSourceFileName, // doesn't include the file extension
false,
null /*no module filtering on source dir*/);
}
} else {
if (binaryFileName == null) {
qBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class;
binaryFileName = qBinaryFileName;
if (typeNameStart > 0) {
binaryFileName = qBinaryFileName.substring(typeNameStart);
}
}
answer =
location.findClass(
binaryFileName,
qPackageName,
moduleName,
qBinaryFileName,
false,
this.moduleLocations != null ? this.moduleLocations::containsKey : null);
}
if (answer != null) {
if (!answer.ignoreIfBetter()) {
if (answer.isBetter(suggestedAnswer)) {
if(NameLookup.VERBOSE) {
Util.verbose(" Result for JavaSearchNameEnvironment#findClass( " + qualifiedTypeName + ", " + CharOperation.charToString(typeName) + ", " + strategy + ", " + moduleName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
Util.verbose(" -> answer: " + answer); //$NON-NLS-1$
Util.verbose(" -> location: " + location); //$NON-NLS-1$
}
return answer;
}
} else if (answer.isBetter(suggestedAnswer)) {
// remember suggestion and keep looking
suggestedAnswer = answer;
if(NameLookup.VERBOSE) {
Util.verbose(" Potential answer for JavaSearchNameEnvironment#findClass( " + qualifiedTypeName + ", " + CharOperation.charToString(typeName) + ", " + strategy + ", " + moduleName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
Util.verbose(" -> answer: " + answer); //$NON-NLS-1$
Util.verbose(" -> location: " + location); //$NON-NLS-1$
}
}
}
}
if (suggestedAnswer != null)
// no better answer was found
return suggestedAnswer;
if(NameLookup.VERBOSE) {
Util.verbose(" NO result for JavaSearchNameEnvironment#findClass( " + qualifiedTypeName + ", " + CharOperation.charToString(typeName) + ", " + strategy + ", " + moduleName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
}
return null;
}
protected /* visible for testing only */ Iterable<ClasspathLocation> getLocationsFor(/*@Nullable*/String moduleName, String qualifiedPackageName) {
if (moduleName != null) {
LinkedHashSet<ClasspathLocation> l = this.moduleToClassPathLocations.get(moduleName);
if (l != null)
return l;
// FIXME: this seems bogus ... if we are searching with a module name and there is NONE, an empty set should be returned, shouldn't it?
}
if(qualifiedPackageName != null) {
LinkedHashSet<ClasspathLocation> cpls = this.packageNameToClassPathLocations.get(qualifiedPackageName);
if(cpls == null) {
if(NameLookup.VERBOSE) {
Util.verbose(" No result for JavaSearchNameEnvironment#getLocationsFor( " + moduleName + ", " + qualifiedPackageName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
return Collections.emptySet();
}
if(NameLookup.VERBOSE) {
Util.verbose(" Result for JavaSearchNameEnvironment#getLocationsFor( " + moduleName + ", " + qualifiedPackageName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Util.verbose(" -> " + cpls.stream().map(Object::toString).collect(joining(" | "))); //$NON-NLS-1$ //$NON-NLS-2$
}
return cpls;
}
if(NameLookup.VERBOSE) {
Util.verbose(" Potentially expensive search in JavaSearchNameEnvironment#getLocationsFor( " + moduleName + ", " + qualifiedPackageName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
return this.locationSet;
}
@Override
public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, char[] moduleName) {
if (typeName != null)
return findClass(
new String(CharOperation.concatWith(packageName, typeName, '/')),
typeName,
LookupStrategy.get(moduleName),
LookupStrategy.getStringName(moduleName));
return null;
}
@Override
public NameEnvironmentAnswer findType(char[][] compoundName, char[] moduleName) {
if (compoundName != null)
return findClass(
new String(CharOperation.concatWith(compoundName, '/')),
compoundName[compoundName.length - 1],
LookupStrategy.get(moduleName),
LookupStrategy.getStringName(moduleName));
return null;
}
@Override
public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) {
String qualifiedPackageName = String.valueOf(CharOperation.concatWith(packageName, '/'));
LookupStrategy strategy = LookupStrategy.get(moduleName);
if (strategy == LookupStrategy.Named) {
if (this.moduleToClassPathLocations != null) {
String moduleNameString = String.valueOf(moduleName);
LinkedHashSet<ClasspathLocation> cpl = this.moduleToClassPathLocations.get(moduleNameString);
if (cpl != null) {
for (ClasspathLocation cp : cpl) {
if (cp.isPackage(qualifiedPackageName, moduleNameString))
return new char[][] { moduleName };
}
}
}
return null;
}
char[][] moduleNames = CharOperation.NO_CHAR_CHAR;
for (ClasspathLocation location : getLocationsFor(null /* ignore module */, qualifiedPackageName)) {
if (strategy.matches(location, ClasspathLocation::hasModule) ) {
if (location.isPackage(qualifiedPackageName, null)) {
char[][] mNames = location.getModulesDeclaringPackage(qualifiedPackageName, null);
if (mNames == null || mNames.length == 0) continue;
moduleNames = CharOperation.arrayConcat(moduleNames, mNames);
}
}
}
if(NameLookup.VERBOSE) {
Util.verbose(" Result for JavaSearchNameEnvironment#getModulesDeclaringPackage( " + qualifiedPackageName + ", " + CharOperation.charToString(moduleName) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Util.verbose(" -> " + CharOperation.toString(moduleNames)); //$NON-NLS-1$
}
return moduleNames == CharOperation.NO_CHAR_CHAR ? null : moduleNames;
}
@Override
public char[][] listPackages(char[] moduleName) { LookupStrategy strategy = LookupStrategy.get(moduleName);
switch (strategy) {
case Named:
if (this.moduleLocations != null) {
ClasspathLocation location = this.moduleLocations.get(String.valueOf(moduleName));
if (location == null)
return CharOperation.NO_CHAR_CHAR;
return location.listPackages();
}
return CharOperation.NO_CHAR_CHAR;
default:
throw new UnsupportedOperationException("can list packages only of a named module"); //$NON-NLS-1$
}
}
@Override
public boolean hasCompilationUnit(char[][] qualifiedPackageName, char[] moduleName, boolean checkCUs) {
String qualifiedPackageNameString = String.valueOf(CharOperation.concatWith(qualifiedPackageName, '/'));
LookupStrategy strategy = LookupStrategy.get(moduleName);
String moduleNameString = LookupStrategy.getStringName(moduleName);
if (strategy == LookupStrategy.Named) {
if (this.moduleLocations != null) {
ClasspathLocation location = this.moduleLocations.get(moduleNameString);
if (location != null)
return location.hasCompilationUnit(qualifiedPackageNameString, moduleNameString);
}
} else {
for (ClasspathLocation location : getLocationsFor(null /* ignore module */, qualifiedPackageNameString)) {
if (strategy.matches(location, ClasspathLocation::hasModule) )
if (location.hasCompilationUnit(qualifiedPackageNameString, moduleNameString)) {
if(NameLookup.VERBOSE) {
Util.verbose(" Result for JavaSearchNameEnvironment#hasCompilationUnit( " + qualifiedPackageNameString + ", " + moduleNameString + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Util.verbose(" -> " + location); //$NON-NLS-1$
}
return true;
}
}
}
return false;
}
@Override
public IModule getModule(char[] moduleName) {
computeModules();
IModuleDescription moduleDesc = this.modules.get(new String(moduleName));
IModule module = null;
try {
if (moduleDesc != null)
module = (IModule)((JavaElement) moduleDesc).getElementInfo();
} catch (JavaModelException e) {
// do nothing
}
return module;
}
@Override
public char[][] getAllAutomaticModules() {
if (this.moduleLocations == null || this.moduleLocations.size() == 0)
return CharOperation.NO_CHAR_CHAR;
Set<char[]> set = this.moduleLocations.values().stream().map(e -> e.getModule()).filter(m -> m != null && m.isAutomatic())
.map(m -> m.name()).collect(Collectors.toSet());
return set.toArray(new char[set.size()][]);
}
private static boolean isComplianceJava9OrHigher(IJavaProject javaProject) {
if (javaProject == null) {
return false;
}
return CompilerOptions.versionToJdkLevel(javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true)) >= ClassFileConstants.JDK9;
}
}