Skip to content

Commit f35b9a5

Browse files
committed
JavaBuilder.getRequiredProjects() path matching fix
Before this change, full build could be triggered instead of incremental one for projects with external libraries on classpath, if the first segment of the external library path matches some workspace project name. In such case, instead of the expected external folders project that hosts the library, some fully unrelated project is returned as required by the builder. With that, no delta is found for the actually required external folders project during incremental build. No delta for some project on classpath means full rebuild for the project. The patch tries to improve the way the corresponding projects found for the binary classpath entries, checking first to match existing external folders and only after that the (possibly wrong) workspace match on first path segment. Additionally binaryLocationsPerProject map, which used in the delta handling, changed to linked one (code iterates over this map few times), to have more reproducible builder behavior in general. See eclipse-pde/eclipse.pde#2244 (comment) Fix eclipse-jdt#4921
1 parent c9cb9ed commit f35b9a5

1 file changed

Lines changed: 32 additions & 10 deletions

File tree

  • org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder

org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Date;
2424
import java.util.HashMap;
2525
import java.util.HashSet;
26+
import java.util.LinkedHashMap;
2627
import java.util.LinkedHashSet;
2728
import java.util.Map;
2829
import java.util.Map.Entry;
@@ -74,8 +75,8 @@ public class JavaBuilder extends IncrementalProjectBuilder {
7475
String[] extraResourceFolderFilters;
7576
public static final String SOURCE_ID = "JDT"; //$NON-NLS-1$
7677

77-
public static boolean DEBUG = false;
78-
public static boolean SHOW_STATS = false;
78+
public static boolean DEBUG;
79+
public static boolean SHOW_STATS;
7980

8081
/**
8182
* Bug 549457: In case auto-building on a JDT core settings change (e.g. compiler compliance) is not desired,
@@ -487,7 +488,7 @@ private Map<IProject, IResourceDelta> findDeltas() {
487488
}
488489
} else {
489490
if (DEBUG) {
490-
trace("JavaBuilder: Missing delta for: " + p.getName()); //$NON-NLS-1$
491+
trace("JavaBuilder: Missing delta for: " + p.getName()); //$NON-NLS-1$
491492
}
492493
this.notifier.subTask(""); //$NON-NLS-1$
493494
return null;
@@ -527,13 +528,34 @@ private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
527528
case IClasspathEntry.CPE_LIBRARY :
528529
if (includeBinaryPrerequisites && path.segmentCount() > 0) {
529530
// some binary resources on the class path can come from projects that are not included in the project references
530-
IResource resource = this.workspaceRoot.findMember(path.segment(0));
531-
if (resource instanceof IProject) {
532-
p = (IProject) resource;
531+
IResource resource = null;
532+
533+
// Try to check first if the full binary entry path exactly matches an external folder,
534+
// before assuming its first segment matches some project name in the workspace
535+
resource = externalFoldersManager.getFolder(path);
536+
if (DEBUG && resource != null && !path.lastSegment().contains("jrt-fs.jar")) { //$NON-NLS-1$
537+
trace("JavaBuilder: found resource containing binary classpath entry: \nExternal: " + this.currentProject.getName() + " -> " + path); //$NON-NLS-1$ //$NON-NLS-2$
538+
}
539+
540+
// Second try: it could be a full workspace path, where first segment is the project name.
541+
// Note, the path may not exist physically yet, it is allowed to reference not (yet) existing resources.
542+
// Unfortunately this can also match fully unrelated projects in the workspace on Linux/Mac,
543+
// current .classpath format does not provide possibilities to ensure that
544+
// "<classpathentry kind="lib" path="/some/folder/name"/>"
545+
// specifies an absolute OS path or full workspace path, both may not exist yet.
546+
if (resource == null && path.isAbsolute() && path.getDevice() == null) {
547+
resource = this.workspaceRoot.findMember(path.segment(0));
548+
}
549+
550+
if (resource != null) {
551+
p = resource.getProject();
552+
if (DEBUG && !path.lastSegment().contains("jrt-fs.jar")) { //$NON-NLS-1$
553+
trace("JavaBuilder: found workspace project containing binary classpath entry: \nExternal: " + this.currentProject.getName() + " -> " + path); //$NON-NLS-1$ //$NON-NLS-2$
554+
}
533555
} else {
534-
resource = externalFoldersManager.getFolder(path);
535-
if (resource != null)
536-
p = resource.getProject();
556+
if (DEBUG && !path.lastSegment().contains("jrt-fs.jar")) { //$NON-NLS-1$
557+
trace("JavaBuilder: Could not find resource containing binary classpath entry: \n" + this.currentProject.getName() + " -> " + path); //$NON-NLS-1$ //$NON-NLS-2$
558+
}
537559
}
538560
}
539561
}
@@ -695,7 +717,7 @@ private int initializeBuilder(int kind, boolean forBuild) throws CoreException {
695717
}
696718
}
697719

698-
this.binaryLocationsPerProject = new HashMap<>(3);
720+
this.binaryLocationsPerProject = new LinkedHashMap<>(3);
699721
this.nameEnvironment = new NameEnvironment(this.workspaceRoot, this.javaProject, this.binaryLocationsPerProject, this.notifier, CompilationGroup.MAIN, JavaProject.NO_RELEASE);
700722
this.testNameEnvironment = new NameEnvironment(this.workspaceRoot, this.javaProject, this.binaryLocationsPerProject, this.notifier, CompilationGroup.TEST, JavaProject.NO_RELEASE);
701723

0 commit comments

Comments
 (0)