blob: f7c9e6a1c37f6f5df46d317d9d1826ce1ff91113 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 IBM Corporation.
*
* 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
*******************************************************************************/
package org.eclipse.jdt.internal.core.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.core.BasicCompilationUnit;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.CompilationGroup;
import org.eclipse.jdt.internal.core.builder.NameEnvironment;
import org.eclipse.jdt.internal.core.builder.ProblemFactory;
public class ModuleUtil {
static class ModuleAccumulatorEnvironment extends NameEnvironment {
public ModuleAccumulatorEnvironment(IJavaProject javaProject) {
super(javaProject, CompilationGroup.MAIN);
}
Set<String> modules = new HashSet<>();
public String[] getModules() {
this.modules.remove(String.valueOf(TypeConstants.JAVA_BASE));
String[] mods = new String[this.modules.size()];
return this.modules.toArray(mods);
}
@Override
protected boolean isOnModulePath(ClasspathEntry entry) {
return true; // try to interpret all dependencies as modules from now on
}
@Override
public void cleanup() {
this.modules.clear();
}
@Override
public NameEnvironmentAnswer findType(char[][] compoundTypeName, char[] moduleName) {
NameEnvironmentAnswer answer = super.findType(compoundTypeName, moduleName);
if (answer != null && answer.moduleName() != null) {
this.modules.add(String.valueOf(answer.moduleName()));
}
return answer;
}
@Override
public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, char[] moduleName) {
NameEnvironmentAnswer answer = super.findType(typeName, packageName, moduleName);
if (answer != null && answer.moduleName() != null) {
this.modules.add(String.valueOf(answer.moduleName()));
}
return answer;
}
}
private static Compiler newCompiler(ModuleAccumulatorEnvironment environment, IJavaProject javaProject) {
Map<String, String> projectOptions = javaProject.getOptions(true);
CompilerOptions compilerOptions = new CompilerOptions(projectOptions);
compilerOptions.performMethodsFullRecovery = true;
compilerOptions.performStatementsRecovery = true;
ICompilerRequestor requestor = new ICompilerRequestor() {
@Override
public void acceptResult(CompilationResult result) {
// Nothing to do here
}
};
Compiler newCompiler = new Compiler(
environment,
DefaultErrorHandlingPolicies.proceedWithAllProblems(),
compilerOptions,
requestor,
ProblemFactory.getProblemFactory(Locale.getDefault()));
return newCompiler;
}
public static String[] getReferencedModules(IJavaProject project) throws CoreException {
ModuleAccumulatorEnvironment environment = new ModuleAccumulatorEnvironment(project);
Compiler compiler = newCompiler(environment, project);
// First go over the binary roots and see if any of them are modules
List<String> required = new ArrayList<>();
Set<org.eclipse.jdt.internal.compiler.env.ICompilationUnit> toCompile = new HashSet<>();
IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
for (IPackageFragmentRoot root : roots) {
if (root.getKind() == IPackageFragmentRoot.K_SOURCE) {
IJavaElement[] children = root.getChildren();
for (IJavaElement child : children) {
if (child instanceof IPackageFragment) {
IPackageFragment fragment = (IPackageFragment) child;
if (fragment.isDefaultPackage()) continue;
ICompilationUnit[] units = fragment.getCompilationUnits();
if (units.length != 0) {
String pack = fragment.getElementName();
for (ICompilationUnit iUnit : units) {
org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceFile =
new BasicCompilationUnit(iUnit.getSource().toCharArray(),
CharOperation.splitOn('.', pack.toCharArray()),
iUnit.getPath().toOSString(),
iUnit);
toCompile.add(sourceFile);
}
}
}
}
}
}
org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sources = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[toCompile.size()];
toCompile.toArray(sources);
compiler.compile(sources);
String[] mods = environment.getModules();
for (String string : mods) {
required.add(string);
}
Collections.sort(required, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
return required.toArray(new String[required.size()]);
}
}