Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageFragmentRoot;
Expand All @@ -47,6 +50,9 @@
import com.sun.jdi.Type;

public class JdtUtils {
private static final String TEST_SCOPE = "test";
private static final String MAVEN_SCOPE_ATTRIBUTE = "maven.scope";
private static final String GRADLE_SCOPE_ATTRIBUTE = "gradle_scope";

/**
* Returns the module this project represents or null if the Java project doesn't represent any named module.
Expand Down Expand Up @@ -117,6 +123,50 @@ public static IProject getProject(String projectName) {
return root.getProject(projectName);
}

/**
* Compute the fragment roots for each test source folders.
*
* @param project the java project.
* @return the fragment roots for each test source folders.
*/
public static IPackageFragmentRoot[] getTestPackageFragmentRoots(IJavaProject project) {
try {
IPackageFragmentRoot[] packageFragmentRoot = project.getPackageFragmentRoots();
List<IPackageFragmentRoot> sources = new ArrayList<>();
for (int i = 0; i < packageFragmentRoot.length; i++) {
if (packageFragmentRoot[i].getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT
&& packageFragmentRoot[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
IClasspathEntry cpe = packageFragmentRoot[i].getResolvedClasspathEntry();

if (isTest(cpe)) {
sources.add(packageFragmentRoot[i]);
}
}
}
return sources.toArray(new IPackageFragmentRoot[0]);
} catch (JavaModelException e) {
// ignore
return new IPackageFragmentRoot[0];
}
}

/**
* There is an issue on IClasspathEntry#isTest: it will return true if the scope is runtime, so we will this method for testing whether
* the classpath entry is for test only.
*
* @param classpathEntry classpath entry
* @return whether this classpath entry is only used in test
*/
public static boolean isTest(final IClasspathEntry classpathEntry) {
for (IClasspathAttribute attribute : classpathEntry.getExtraAttributes()) {
if (GRADLE_SCOPE_ATTRIBUTE.equals(attribute.getName()) || MAVEN_SCOPE_ATTRIBUTE.equals(attribute.getName())) {
return TEST_SCOPE.equals(attribute.getValue());
}
}
return classpathEntry.isTest();
}


/**
* Compute the possible source containers that the specified project could be associated with.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
Expand All @@ -40,7 +38,7 @@

public class ResolveClasspathsHandler {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
private static final String SCOPE_ATTRIBUTE = "maven.scope";


/**
* Resolves class path for a java project.
Expand Down Expand Up @@ -150,7 +148,8 @@ private static String[][] computeClassPath(String mainClass, String projectName)
}
project = projects.get(0);
}
return computeClassPath(project);

return computeClassPath(project, isMainClassInTestFolder(project, mainClass));
}

/**
Expand All @@ -162,31 +161,34 @@ private static String[][] computeClassPath(String mainClass, String projectName)
* @throws CoreException
* CoreException
*/
private static String[][] computeClassPath(IJavaProject javaProject) throws CoreException {
private static String[][] computeClassPath(IJavaProject javaProject, boolean includeTestScope)
throws CoreException {
if (javaProject == null) {
throw new IllegalArgumentException("javaProject is null");
}
String[][] result = new String[2][];
if (JavaRuntime.isModularProject(javaProject)) {
result[0] = computeDefaultRuntimeClassPath(javaProject);
result[0] = computeDefaultRuntimeClassPath(javaProject, includeTestScope);
result[1] = new String[0];
} else {
result[0] = new String[0];
result[1] = computeDefaultRuntimeClassPath(javaProject);
result[1] = computeDefaultRuntimeClassPath(javaProject, includeTestScope);
}
return result;
}

private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject) throws CoreException {
private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject, boolean includeTestScope)
throws CoreException {
IRuntimeClasspathEntry[] unresolved = JavaRuntime.computeUnresolvedRuntimeClasspath(jproject);
Set<String> resolved = new LinkedHashSet<String>();
for (int i = 0; i < unresolved.length; i++) {
IRuntimeClasspathEntry entry = unresolved[i];
if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {
IRuntimeClasspathEntry[] entries = JavaRuntime.resolveRuntimeClasspathEntry(entry, jproject, true);
IRuntimeClasspathEntry[] entries = JavaRuntime.resolveRuntimeClasspathEntry(entry, jproject,
!includeTestScope);
for (int j = 0; j < entries.length; j++) {

if (entries[j].getClasspathEntry().isTest() && !isRuntime(entries[j].getClasspathEntry())) {
if (!includeTestScope && JdtUtils.isTest(entries[j].getClasspathEntry())) {
continue;
}
String location = entries[j].getLocation();
Expand All @@ -200,10 +202,43 @@ private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject) th
return resolved.toArray(new String[resolved.size()]);
}

private static boolean isRuntime(final IClasspathEntry classpathEntry) {
for (IClasspathAttribute attribute : classpathEntry.getExtraAttributes()) {
if (SCOPE_ATTRIBUTE.equals(attribute.getName()) && "runtime".equals(attribute.getValue())) {
return true;

/**
* Test whether the main class is located in test folders.
* @param project the java project containing the main class
* @param mainClass the main class name
* @return whether the main class is located in test folders
*/
private static boolean isMainClassInTestFolder(IJavaProject project, String mainClass) {
// get a list of test folders and check whether main class is here
int constraints = IJavaSearchScope.SOURCES;
IJavaElement[] testFolders = JdtUtils.getTestPackageFragmentRoots(project);
if (testFolders.length > 0) {
try {

List<Object> mainClassesInTestFolder = new ArrayList<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boolean isFound = false;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot change the value isFound at the callback

SearchPattern pattern = SearchPattern.createPattern(mainClass, IJavaSearchConstants.CLASS,
IJavaSearchConstants.DECLARATIONS,
SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH);
SearchEngine searchEngine = new SearchEngine();
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(testFolders, constraints);
SearchRequestor requestor = new SearchRequestor() {
@Override
public void acceptSearchMatch(SearchMatch match) {
Object element = match.getElement();
if (element instanceof IJavaElement) {
mainClassesInTestFolder.add(element);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isFound = true;

}
}
};

searchEngine.search(pattern, new SearchParticipant[] {
SearchEngine.getDefaultSearchParticipant()
}, scope, requestor, null /* progress monitor */);

return !mainClassesInTestFolder.isEmpty();
} catch (Exception e) {
logger.log(Level.SEVERE, String.format("Searching the main class failure: %s", e.toString()), e);
}
}
return false;
Expand Down