diff options
author | Stephan Herrmann | 2019-09-22 18:31:24 +0000 |
---|---|---|
committer | Stephan Herrmann | 2019-09-24 13:39:24 +0000 |
commit | bd56845ca277b92292b685d59ebbddf51541f702 (patch) | |
tree | 1e4cbe4c334f3dec20b8383386338b5fd571b98c | |
parent | 212e6b23af942ca28f9a8eed4ca33c2053dc2108 (diff) | |
download | eclipse.jdt.core-bd56845ca277b92292b685d59ebbddf51541f702.tar.gz eclipse.jdt.core-bd56845ca277b92292b685d59ebbddf51541f702.tar.xz eclipse.jdt.core-bd56845ca277b92292b685d59ebbddf51541f702.zip |
Bug 551284 - build path cycle message lists too many projects to be
useful
Change-Id: If7e73ab2b889b63061c0e76805f85f23098227c4
5 files changed, 368 insertions, 80 deletions
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java index 73d5448c58..5f5ab47847 100644 --- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java +++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -315,20 +315,22 @@ public class MultiProjectTests extends BuilderTests { printProblems(); expectingOnlySpecificProblemsFor(p1, new Problem[] { new Problem("p1", - "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2}", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_ERROR), new Problem("p1", "The project cannot be built until build path errors are resolved", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_ERROR) - });//$NON-NLS-1$ //$NON-NLS-2$ + }); expectingOnlySpecificProblemsFor(p2, new Problem[] { new Problem("p2", - "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2}", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_ERROR), new Problem("p2", "The project cannot be built until build path errors are resolved", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_ERROR) - });//$NON-NLS-1$ //$NON-NLS-2$ + }); env.removeRequiredProject(p1, p2); @@ -429,9 +431,22 @@ public class MultiProjectTests extends BuilderTests { expectingCompilingOrder(new String[] { "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java" }); - expectingOnlySpecificProblemFor(p1, new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ - expectingOnlySpecificProblemFor(p2,new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ - expectingOnlySpecificProblemFor(p3,new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p1, new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); + expectingOnlySpecificProblemFor(p2,new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); + expectingOnlySpecificProblemFor(p3,new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); JavaCore.setOptions(options); } finally { @@ -528,12 +543,24 @@ public class MultiProjectTests extends BuilderTests { env.waitForAutoBuild(); expectingCompilingOrder(new String[] { "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java" }); - expectingOnlySpecificProblemFor(p1,new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p1,new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); expectingOnlySpecificProblemsFor(p2,new Problem[]{ new Problem("p2", "The method bar(Y, int) in the type X is not applicable for the arguments (Y)", c2, 106, 109, CategorizedProblem.CAT_MEMBER, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ - new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); - expectingOnlySpecificProblemFor(p3,new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p3,new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); JavaCore.setOptions(options); } finally { @@ -631,9 +658,22 @@ public class MultiProjectTests extends BuilderTests { expectingCompilingOrder(new String[] { "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java" }); - expectingOnlySpecificProblemFor(p1,new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ - expectingOnlySpecificProblemFor(p2,new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ - expectingOnlySpecificProblemFor(p3,new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p1,new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); + expectingOnlySpecificProblemFor(p2,new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); + expectingOnlySpecificProblemFor(p3,new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); env.addClass(root1, "p1", "X", //$NON-NLS-1$ //$NON-NLS-2$ "package p1;\n"+ //$NON-NLS-1$ @@ -647,12 +687,25 @@ public class MultiProjectTests extends BuilderTests { incrementalBuild(); env.waitForAutoBuild(); expectingCompilingOrder(new String[] { "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java" }); - expectingOnlySpecificProblemFor(p1,new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p1,new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); expectingOnlySpecificProblemsFor(p2,new Problem[]{ new Problem("p2", "The method bar(Y, int) in the type X is not applicable for the arguments (Y)", c2, 106, 109, CategorizedProblem.CAT_MEMBER, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ - new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); - expectingOnlySpecificProblemFor(p3,new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p3,new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); JavaCore.setOptions(options); } finally { @@ -738,18 +791,31 @@ public class MultiProjectTests extends BuilderTests { env.waitForAutoBuild(); expectingCompilingOrder(new String[] { "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P2/src/p2/Y.java" }); - expectingOnlySpecificProblemFor(p1,new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p1,new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); expectingOnlySpecificProblemsFor(p2,new Problem[]{ new Problem("p2", "X cannot be resolved to a type", c2, 87, 88, CategorizedProblem.CAT_TYPE, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ new Problem("p2", "The method foo() from the type Z refers to the missing type X", c2, 93, 96, CategorizedProblem.CAT_MEMBER, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ new Problem("p2", "The import p1 cannot be resolved", c2, 19, 21, CategorizedProblem.CAT_IMPORT, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ new Problem("p2", "X cannot be resolved to a type", c2, 73, 74, CategorizedProblem.CAT_TYPE, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ - new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p3,new Problem[]{ new Problem("p3", "X cannot be resolved to a type", c3, 51, 52, CategorizedProblem.CAT_TYPE, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ new Problem("p3", "The import p1 cannot be resolved", c3, 19, 21, CategorizedProblem.CAT_IMPORT, IMarker.SEVERITY_ERROR),//$NON-NLS-1$ //$NON-NLS-2$ - new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); env.addClass(root1, "p1", "X", //$NON-NLS-1$ //$NON-NLS-2$ @@ -765,9 +831,22 @@ public class MultiProjectTests extends BuilderTests { env.waitForAutoBuild(); expectingCompilingOrder(new String[] { "/P1/src/p1/X.java", "/P2/src/p2/Y.java", "/P3/src/p3/Z.java", "/P1/src/p1/X.java", "/P2/src/p2/Y.java" }); - expectingOnlySpecificProblemFor(p1,new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ - expectingOnlySpecificProblemFor(p2,new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ - expectingOnlySpecificProblemFor(p3,new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING));//$NON-NLS-1$ //$NON-NLS-2$ + expectingOnlySpecificProblemFor(p1,new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); + expectingOnlySpecificProblemFor(p2,new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); + expectingOnlySpecificProblemFor(p3,new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)); JavaCore.setOptions(options); } finally { @@ -838,13 +917,15 @@ public class MultiProjectTests extends BuilderTests { "/P2/src/p2/Y.java" }); expectingOnlySpecificProblemsFor(p1, new Problem[] { new Problem("p1", "The import p22 cannot be resolved", c1, 32, 35, CategorizedProblem.CAT_IMPORT, //$NON-NLS-1$ //$NON-NLS-2$ - IMarker.SEVERITY_ERROR), new Problem("p1", //$NON-NLS-1$ - "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2}", //$NON-NLS-1$ + IMarker.SEVERITY_ERROR), new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p2, new Problem[] { new Problem("p2", "The import p11 cannot be resolved", c2, 32, 35, CategorizedProblem.CAT_IMPORT, //$NON-NLS-1$ //$NON-NLS-2$ - IMarker.SEVERITY_ERROR), new Problem("p2", //$NON-NLS-1$ - "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2}", //$NON-NLS-1$ + IMarker.SEVERITY_ERROR), new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); env.addClass(root1, "p11", "XX", //$NON-NLS-1$ //$NON-NLS-2$ @@ -865,12 +946,14 @@ public class MultiProjectTests extends BuilderTests { expectingOnlySpecificProblemsFor(p1, new Problem[] { new Problem("p1", "The import p22 is never used", c1, 32, 35, //$NON-NLS-1$ //$NON-NLS-2$ CategorizedProblem.CAT_UNNECESSARY_CODE, IMarker.SEVERITY_WARNING), new Problem("p1", //$NON-NLS-1$ - "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2}", //$NON-NLS-1$ + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p2, new Problem[] { new Problem("p2", "The import p11 is never used", c2, 32, 35, //$NON-NLS-1$ //$NON-NLS-2$ CategorizedProblem.CAT_UNNECESSARY_CODE, IMarker.SEVERITY_WARNING), new Problem("p2", //$NON-NLS-1$ - "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2}", //$NON-NLS-1$ + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); JavaCore.setOptions(options); @@ -954,13 +1037,29 @@ public void testCycle6() throws JavaModelException { fullBuild(); env.waitForAutoBuild(); expectingOnlySpecificProblemsFor(p1,new Problem[]{ - new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "P1->{P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p2,new Problem[]{ - new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p3,new Problem[]{ - new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); } finally { @@ -1044,13 +1143,29 @@ public void testCycle7() throws JavaModelException { fullBuild(); env.waitForAutoBuild(); expectingOnlySpecificProblemsFor(p1,new Problem[]{ - new Problem("p1", "A cycle was detected in the build path of project 'P1'. The cycle consists of projects {P1, P2, P3}", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "P1->{P2, P3}\n" + + "->{P1, P3}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p2,new Problem[]{ - new Problem("p2", "A cycle was detected in the build path of project 'P2'. The cycle consists of projects {P1, P2, P3}", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2}\n" + + "->{P1, P2, P3}\n" + + "->{P2, P3}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); expectingOnlySpecificProblemsFor(p3,new Problem[]{ - new Problem("p3", "A cycle was detected in the build path of project 'P3'. The cycle consists of projects {P1, P2, P3}", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING)//$NON-NLS-1$ //$NON-NLS-2$ + new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P1, P2, P3}\n" + + "->{P2, P3}\n" + + "->{P1, P3}", + p3, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) }); } finally { @@ -1060,6 +1175,58 @@ public void testCycle7() throws JavaModelException { env.removeProject(p3); } } + public void testCycle8() throws JavaModelException { + // specifically tests projects with (transitive) dependencies on a cycle, i.e., error messages with a non-empty prefix + Hashtable options = JavaCore.getOptions(); + Hashtable newOptions = JavaCore.getOptions(); + newOptions.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.WARNING); + + JavaCore.setOptions(newOptions); + + IPath p1 = env.addProject("P1"); + IPath p2 = env.addProject("P2"); + IPath p3 = env.addProject("P3"); + IPath p4 = env.addProject("P4"); + + // Dependencies + IPath[] accessiblePaths = new IPath[] {new Path("java/lang/*")}; + IPath[] forbiddenPaths = new IPath[] {new Path("**/*")}; + env.addRequiredProject(p1, p2, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p2, p3, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p3, p4, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p4, p3, accessiblePaths, forbiddenPaths, false); + + try { + env.waitForManualRefresh(); + fullBuild(); + env.waitForAutoBuild(); + expectingOnlySpecificProblemsFor(p1,new Problem[]{ + new Problem("p1", + "One or more cycles were detected in the build path of project 'P1'. The paths towards the cycle and cycle are:\n" + + "P1, P2->{P3, P4}", + p1, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) + }); + expectingOnlySpecificProblemsFor(p2,new Problem[]{ + new Problem("p2", + "One or more cycles were detected in the build path of project 'P2'. The paths towards the cycle and cycle are:\n" + + "P2->{P3, P4}", + p2, -1, -1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING), + }); + expectingOnlySpecificProblemsFor(p3,new Problem[]{ + new Problem("p3", + "One or more cycles were detected in the build path of project 'P3'. The paths towards the cycle and cycle are:\n" + + "->{P3, P4}", + p3, -1,-1, CategorizedProblem.CAT_BUILDPATH, IMarker.SEVERITY_WARNING) + }); + + } finally { + JavaCore.setOptions(options); + env.removeProject(p1); + env.removeProject(p2); + env.removeProject(p3); + env.removeProject(p4); + } + } /* * Full buid case diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java index 1ebb8cb05d..5bcb24cc3d 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java @@ -118,21 +118,22 @@ public void setUpSuite() throws Exception { setupExternalJCL("jclMin"); setupExternalJCL("jclMin1.5"); } -protected void assertCycleMarkers(IJavaProject project, IJavaProject[] p, int[] expectedCycleParticipants) throws CoreException { +protected void assertCycleMarkers(IJavaProject project, IJavaProject[] p, int[] expectedCycleParticipants, boolean includeAffected) throws CoreException { waitForAutoBuild(); StringBuffer expected = new StringBuffer("{"); int expectedCount = 0; StringBuffer computed = new StringBuffer("{"); int computedCount = 0; + int mask = includeAffected ? 3 : 1; for (int j = 0; j < p.length; j++){ - int markerCount = numberOfCycleMarkers(p[j]); - if (markerCount > 0){ + int markerFlags = cycleMarkerFlags(p[j]); + if ((markerFlags & mask) > 0){ if (computedCount++ > 0) computed.append(", "); computed.append(p[j].getElementName()); //computed.append(" (" + markerCount + ")"); } - markerCount = expectedCycleParticipants[j]; - if (markerCount > 0){ + markerFlags = expectedCycleParticipants[j]; + if ((markerFlags & mask) > 0){ if (expectedCount++ > 0) expected.append(", "); expected.append(p[j].getElementName()); //expected.append(" (" + markerCount + ")"); @@ -169,14 +170,20 @@ protected File createFile(File parent, String name, String content) throws IOExc file.setLastModified(System.currentTimeMillis() + 2000); return file; } -protected int numberOfCycleMarkers(IJavaProject javaProject) throws CoreException { +/** @return 1: participates in cycle, 2: affected by cycle (depends on) */ +protected int cycleMarkerFlags(IJavaProject javaProject) throws CoreException { IMarker[] markers = javaProject.getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); int result = 0; for (int i = 0, length = markers.length; i < length; i++) { IMarker marker = markers[i]; String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED); if (cycleAttr != null && cycleAttr.equals("true")){ //$NON-NLS-1$ - result++; + String message = marker.getAttribute(IMarker.MESSAGE, ""); + boolean isCycleMember = message.indexOf("\n->{") != -1; // cycle with no prefix + if (isCycleMember) + result |= 1; + else + result |= 2; } } return result; @@ -2572,7 +2579,7 @@ public void testCycleReport() throws CoreException { IJavaProject[] projects = { p1, p2, p3 }; int cycleMarkerCount = 0; for (int i = 0; i < projects.length; i++){ - cycleMarkerCount += numberOfCycleMarkers(projects[i]); + cycleMarkerCount += (cycleMarkerFlags(projects[i]) & 1); } assertTrue("Should have no cycle markers", cycleMarkerCount == 0); @@ -2597,7 +2604,7 @@ public void testCycleReport() throws CoreException { waitForAutoBuild(); // wait for cycle markers to be created cycleMarkerCount = 0; for (int i = 0; i < projects.length; i++){ - cycleMarkerCount += numberOfCycleMarkers(projects[i]); + cycleMarkerCount += (cycleMarkerFlags(projects[i]) & 1); } assertEquals("Unexpected number of projects involved in a classpath cycle", 3, cycleMarkerCount); @@ -4183,11 +4190,13 @@ public void testMissingPrereq4() throws CoreException { ""); this.assertMarkers( "Unexpected markers for project A", - "A cycle was detected in the build path of project 'A'. The cycle consists of projects {A, B}", + "One or more cycles were detected in the build path of project 'A'. The paths towards the cycle and cycle are:\n" + + "->{A, B}", projectA); this.assertMarkers( "Unexpected markers for project B", - "A cycle was detected in the build path of project 'B'. The cycle consists of projects {A, B}", + "One or more cycles were detected in the build path of project 'B'. The paths towards the cycle and cycle are:\n" + + "->{A, B}", projectB); // delete project B @@ -4207,11 +4216,13 @@ public void testMissingPrereq4() throws CoreException { ""); this.assertMarkers( "Unexpected markers for project A after adding project B back", - "A cycle was detected in the build path of project 'A'. The cycle consists of projects {A, B}", + "One or more cycles were detected in the build path of project 'A'. The paths towards the cycle and cycle are:\n" + + "->{A, B}", projectA); this.assertMarkers( "Unexpected markers for project B after adding project B back", - "A cycle was detected in the build path of project 'B'. The cycle consists of projects {A, B}", + "One or more cycles were detected in the build path of project 'B'. The paths towards the cycle and cycle are:\n" + + "->{A, B}", projectB); } finally { @@ -4458,6 +4469,14 @@ public void testCycleDetection() throws CoreException { { 1, 1, 1, 1, 1 }, // after setting CP p[4] }; + int[][] expectedAffectedProjects = new int[][] { + { 0, 0, 0, 0, 0 }, // after setting CP p[0] + { 0, 0, 0, 0, 0 }, // after setting CP p[1] + { 1, 1, 1, 0, 0 }, // after setting CP p[2] + { 1, 1, 1, 0, 0 }, // after setting CP p[3] + { 1, 1, 1, 1, 1 }, // after setting CP p[4] + }; + for (int i = 0; i < p.length; i++){ // append project references @@ -4471,7 +4490,8 @@ public void testCycleDetection() throws CoreException { p[i].setRawClasspath(newClasspath, null); // check cycle markers - assertCycleMarkers(p[i], p, expectedCycleParticipants[i]); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false); + assertCycleMarkers(p[i], p, expectedAffectedProjects[i], true); } //this.startDeltas(); @@ -4533,7 +4553,7 @@ public void testCycleDetectionThroughVariables() throws CoreException { JavaCore.setClasspathVariables(var, variableValues[i], null); // check cycle markers - assertCycleMarkers(p[i], p, expectedCycleParticipants[i]); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false); } //this.startDeltas(); @@ -4616,7 +4636,7 @@ public void testCycleDetectionThroughContainers() throws CoreException { } // check cycle markers - assertCycleMarkers(p[i], p, expectedCycleParticipants[i]); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false); } //this.startDeltas(); @@ -4699,7 +4719,7 @@ public void testCycleDetectionThroughContainerVariants() throws CoreException { } // check cycle markers - assertCycleMarkers(p[i], p, expectedCycleParticipants[i]); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false); } //this.startDeltas(); @@ -4748,7 +4768,8 @@ public void testCycleDetection2() throws CoreException { p[i].setRawClasspath(newClasspath, null); // check cycle markers - assertCycleMarkers(p[i], p, expectedCycleParticipants[i]); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], true); } //this.startDeltas(); @@ -4784,7 +4805,7 @@ public void testCycleDetection3() throws CoreException { { 0, 0, 0, 0, 0, 0 }, // after setting CP p[2] { 1, 1, 1, 1, 0, 0 }, // after setting CP p[3] { 1, 1, 1, 1, 0, 0 }, // after setting CP p[4] - { 1, 1, 1, 1, 1 , 1}, // after setting CP p[5] + { 1, 1, 1, 1, 1 ,1 }, // after setting CP p[5] }; for (int i = 0; i < p.length; i++){ @@ -4800,8 +4821,17 @@ public void testCycleDetection3() throws CoreException { p[i].setRawClasspath(newClasspath, null); // check cycle markers - assertCycleMarkers(p[i], p, expectedCycleParticipants[i]); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false); + assertCycleMarkers(p[i], p, expectedCycleParticipants[i], true); } + + IMarker[] markers = p[0].getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); + // additionally see that we actually have 2 cycles for P0! + assertMarkers("Markers of P0", + "One or more cycles were detected in the build path of project 'P0'. The paths towards the cycle and cycle are:\n" + + "->{P0, P2, P3, P1}\n" + + "->{P0, P4, P5, P1}", + markers); //this.startDeltas(); } finally { @@ -4840,7 +4870,7 @@ public void testCycleDetection4() throws CoreException { waitForAutoBuild(); getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE); createFile("/P1/test.txt", ""); - assertCycleMarkers(p1, new IJavaProject[] {p1, p2}, new int[] {1, 1}); + assertCycleMarkers(p1, new IJavaProject[] {p1, p2}, new int[] {1, 1}, false); } finally { getWorkspace().removeResourceChangeListener(listener); deleteProjects(new String[] {"P1", "P2"}); @@ -5134,7 +5164,7 @@ private void denseCycleDetection(final int numberOfParticipants) throws CoreExce for (int i = 0; i < numberOfParticipants; i++){ // check cycle markers - assertCycleMarkers(projects[i], projects, allProjectsInCycle); + assertCycleMarkers(projects[i], projects, allProjectsInCycle, false); } } finally { @@ -5207,7 +5237,7 @@ private void noCycleDetection(final int numberOfParticipants, final boolean useF for (int i = 0; i < numberOfParticipants; i++){ // check cycle markers - assertCycleMarkers(projects[i], projects, allProjectsInCycle); + assertCycleMarkers(projects[i], projects, allProjectsInCycle, false); } } finally { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java index 223f78da3e..9f573c98a1 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java @@ -22,6 +22,7 @@ import java.nio.file.FileVisitResult; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -30,6 +31,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.jar.Manifest; @@ -399,30 +401,35 @@ public class JavaProject HashSet traversed = new HashSet(); // compute cycle participants - ArrayList prereqChain = new ArrayList(); + List<IPath> prereqChain = new ArrayList<>(); + Map<IPath,List<CycleInfo>> cyclesPerProject = new HashMap<>(); for (int i = 0; i < length; i++){ if (hasJavaNature(rscProjects[i])) { JavaProject project = (projects[i] = (JavaProject)JavaCore.create(rscProjects[i])); if (!traversed.contains(project.getPath())){ prereqChain.clear(); - project.updateCycleParticipants(prereqChain, cycleParticipants, workspaceRoot, traversed, preferredClasspaths); + project.updateCycleParticipants(prereqChain, cycleParticipants, cyclesPerProject, workspaceRoot, traversed, preferredClasspaths); } } } //System.out.println("updateAllCycleMarkers: " + (System.currentTimeMillis() - start) + " ms"); - String cycleString = cycleParticipants.stream() - .map(path -> workspaceRoot.findMember(path)) - .filter(r -> r != null) - .map(r -> JavaCore.create((IProject)r)) - .filter(p -> p != null) - .map(p -> p.getElementName()) - .collect(Collectors.joining(", ")); //$NON-NLS-1$ - for (int i = 0; i < length; i++){ JavaProject project = projects[i]; if (project != null) { - if (cycleParticipants.contains(project.getPath())) { + List<CycleInfo> cycles = cyclesPerProject.get(project.getPath()); + if (cycles != null) { + StringBuilder cycleString = new StringBuilder(); + boolean first = true; + for (CycleInfo cycleInfo : cycles) { + if (!first) cycleString.append('\n'); + cycleString.append(cycleInfo.pathToCycleAsString()); + cycleString.append("->{"); //$NON-NLS-1$ + cycleString.append(cycleInfo.cycleAsString()); + cycleString.append('}'); + first = false; + } + IMarker cycleMarker = project.getCycleMarker(); String circularCPOption = project.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true); int circularCPSeverity = JavaCore.ERROR.equals(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING; @@ -435,7 +442,7 @@ public class JavaProject } String existingMessage = cycleMarker.getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$ String newMessage = new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, - project, cycleString).getMessage(); + project, cycleString.toString()).getMessage(); if (!newMessage.equals(existingMessage)) { cycleMarker.setAttribute(IMarker.MESSAGE, newMessage); } @@ -445,7 +452,7 @@ public class JavaProject } else { // create new marker project.createClasspathProblemMarker( - new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project, cycleString)); + new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project, cycleString.toString())); } } else { project.flushClasspathProblemMarkers(true, false, false); @@ -2554,7 +2561,7 @@ public class JavaProject LinkedHashSet cycleParticipants = new LinkedHashSet(); HashMap preferredClasspaths = new HashMap(1); preferredClasspaths.put(this, preferredClasspath); - updateCycleParticipants(new ArrayList(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2), preferredClasspaths); + updateCycleParticipants(new ArrayList(2), cycleParticipants, new HashMap<>(), ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2), preferredClasspaths); return !cycleParticipants.isEmpty(); } @@ -3625,6 +3632,48 @@ public class JavaProject } } + /** internal structure for detected build path cycles. */ + static class CycleInfo { + + private List<IPath> pathToCycle; + public final List<IPath> cycle; + + public CycleInfo(List<IPath> pathToCycle, List<IPath> cycle) { + this.pathToCycle = new ArrayList<>(pathToCycle); + this.cycle = new ArrayList<>(cycle); + } + + public static Optional<CycleInfo> findCycleContaining(Collection<List<CycleInfo>> infos, IPath path) { + return infos.stream().flatMap(l -> l.stream()).filter(c -> c.cycle.contains(path)).findAny(); + } + + public static void add(IPath project, List<IPath> prefix, List<IPath> cycle, Map<IPath, List<CycleInfo>> cyclesPerProject) { + List<CycleInfo> list = cyclesPerProject.get(project); + if (list == null) { + cyclesPerProject.put(project, list = new ArrayList<>()); + } else { + for (CycleInfo cycleInfo: list) { + if (cycleInfo.cycle.equals(cycle)) { + // same cycle: use the shorter prefix: + if (cycleInfo.pathToCycle.size() > prefix.size()) { + cycleInfo.pathToCycle.clear(); + cycleInfo.pathToCycle.addAll(prefix); + } + return; + } + } + } + list.add(new CycleInfo(prefix, cycle)); + } + + public String pathToCycleAsString() { + return this.pathToCycle.stream().map(IPath::lastSegment).collect(Collectors.joining(", ")); //$NON-NLS-1$ + } + + public String cycleAsString() { + return this.cycle.stream().map(IPath::lastSegment).collect(Collectors.joining(", ")); //$NON-NLS-1$ + } + } /** * If a cycle is detected, then cycleParticipants contains all the paths of projects involved in this cycle (directly and indirectly), * no cycle if the set is empty (and started empty) @@ -3635,8 +3684,9 @@ public class JavaProject * @param preferredClasspaths Map */ public void updateCycleParticipants( - ArrayList prereqChain, + List<IPath> prereqChain, LinkedHashSet cycleParticipants, + Map<IPath,List<CycleInfo>> cyclesPerProject, IWorkspaceRoot workspaceRoot, HashSet traversed, Map preferredClasspaths){ @@ -3653,19 +3703,60 @@ public class JavaProject if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){ IPath prereqProjectPath = entry.getPath(); - int index = cycleParticipants.contains(prereqProjectPath) ? 0 : prereqChain.indexOf(prereqProjectPath); - if (index >= 0) { // refer to cycle, or in cycle itself - for (int size = prereqChain.size(); index < size; index++) { - cycleParticipants.add(prereqChain.get(index)); + int prereqIndex = prereqChain.indexOf(prereqProjectPath); + if (prereqIndex > -1) { + // record a new cycle: + List<IPath> cycle = prereqChain.subList(prereqIndex, prereqChain.size()); + // empty-prefix CycleInfo for all members of the cycle: + List<IPath> prefix = Collections.emptyList(); + for (IPath prjInCycle : cycle) { + CycleInfo.add(prjInCycle, prefix, cycle, cyclesPerProject); + } + // also record with all members of the prereqChain with transitive dependency on the cycle: + for (int j = 0; j < prereqIndex; j++) { + CycleInfo.add(prereqChain.get(j), prereqChain.subList(j, prereqIndex), cycle, cyclesPerProject); } + } else if (cycleParticipants.contains(prereqProjectPath)) { + // record existing cycle as dependency of each project in prereqChain: + Optional<CycleInfo> cycle = CycleInfo.findCycleContaining(cyclesPerProject.values(), prereqProjectPath); + if (cycle.isPresent()) { + List<IPath> theCycle = cycle.get().cycle; + for (int j = 0; j < prereqChain.size(); j++) { + IPath prereq = prereqChain.get(j); + List<IPath> prereqSubList = prereqChain.subList(j, prereqChain.size()); + int joinIndex1 = theCycle.indexOf(prereq); + if (joinIndex1 != -1) { + // prereqSubList -> prereqProjectPath + theCycle create a new cycle + List<IPath> newCycle = new ArrayList<>(prereqSubList); + int joinIndex2 = theCycle.indexOf(prereqProjectPath); // always != -1 since that's how we found 'cycle' + while (joinIndex2 != joinIndex1) { + newCycle.add(theCycle.get(joinIndex2++)); + if (joinIndex2 == theCycle.size()) + joinIndex2 = 0; // it's a cycle :) + } + for (IPath newMember : newCycle) { + CycleInfo.add(newMember, Collections.emptyList(), newCycle, cyclesPerProject); + } + break; // the rest of prereqChain is already included via newCycle + } else { + CycleInfo.add(prereq, prereqSubList, theCycle, cyclesPerProject); + } + } + } + prereqIndex = 0; } else { if (!traversed.contains(prereqProjectPath)) { IResource member = workspaceRoot.findMember(prereqProjectPath); if (member != null && member.getType() == IResource.PROJECT){ JavaProject javaProject = (JavaProject)JavaCore.create((IProject)member); - javaProject.updateCycleParticipants(prereqChain, cycleParticipants, workspaceRoot, traversed, preferredClasspaths); + javaProject.updateCycleParticipants(prereqChain, cycleParticipants, cyclesPerProject, workspaceRoot, traversed, preferredClasspaths); } } + continue; + } + // fall through from both positive branches above + for (int index = prereqIndex, size = prereqChain.size(); index < size; index++) { + cycleParticipants.add(prereqChain.get(index)); } } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java index 8ff8ad0464..a59c563916 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java @@ -778,7 +778,7 @@ private boolean isWorthBuilding() throws CoreException { */ void mustPropagateStructuralChanges() { LinkedHashSet cycleParticipants = new LinkedHashSet(3); - this.javaProject.updateCycleParticipants(new ArrayList(), cycleParticipants, this.workspaceRoot, new HashSet(3), null); + this.javaProject.updateCycleParticipants(new ArrayList(), cycleParticipants, new HashMap<>(), this.workspaceRoot, new HashSet(3), null); IPath currentPath = this.javaProject.getPath(); Iterator i= cycleParticipants.iterator(); while (i.hasNext()) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties index ec02740544..725a1ccb5f 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties @@ -150,7 +150,7 @@ classpath_cannotUseDistinctSourceFolderAsOutput = Source folder ''{0}'' in proje classpath_cannotUseLibraryAsOutput = Source folder ''{0}'' in project ''{2}'' cannot output to library ''{1}'' classpath_closedProject = Required project ''{0}'' needs to be open classpath_couldNotWriteClasspathFile = Could not write ''.classpath'' file of project ''{0}'': {1} -classpath_cycle = A cycle was detected in the build path of project ''{0}''. The cycle consists of projects '{'{1}'}' +classpath_cycle = One or more cycles were detected in the build path of project ''{0}''. The paths towards the cycle and cycle are:\n{1} classpath_duplicateEntryPath = Build path contains duplicate entry: ''{0}'' for project ''{1}'' classpath_illegalContainerPath = Illegal classpath container path: ''{0}'' in project ''{1}'', must have at least one segment (containerID+hints) classpath_illegalEntryInClasspathFile = Illegal entry in ''.classpath'' of project ''{0}'' file: {1} |