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 4166cb2..a573f6a 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 @@ -2018,8 +2018,10 @@ * 33207 - Reject output folder that coincidate with distinct source folder */ public void testClasspathValidation22() throws CoreException { + Hashtable options = JavaCore.getOptions(); try { IJavaProject proj = this.createJavaProject("P", new String[] {}, ""); + proj.setOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.ERROR); IClasspathEntry[] originalCP = proj.getRawClasspath(); IClasspathEntry[] newCP = new IClasspathEntry[originalCP.length+2]; @@ -2027,12 +2029,18 @@ newCP[originalCP.length] = JavaCore.newSourceEntry(new Path("/P/src"), new IPath[0], new Path("/P/src2")); newCP[originalCP.length+1] = JavaCore.newSourceEntry(new Path("/P/src2"), new IPath[0], new Path("/P/src")); - IJavaModelStatus status = JavaConventions.validateClasspath(proj, newCP, proj.getOutputLocation()); + //IJavaModelStatus status = JavaConventions.validateClasspath(proj, newCP, proj.getOutputLocation()); + proj.setRawClasspath(newCP, proj.getOutputLocation(), null); - assertStatus( - "Source folder \'src\' in project 'P' cannot output to distinct source folder \'src2\'", - status); + assertMarkers( + "Expected markers", + "Project \'P\' is missing required source folder: \'src\'\n" + + "Project \'P\' is missing required source folder: \'src2\'\n" + + "Source folder \'src\' in project \'P\' cannot output to distinct source folder \'src2\'\n" + + "Source folder \'src2\' in project \'P\' cannot output to distinct source folder \'src\'", + proj); } finally { + JavaCore.setOptions(options); this.deleteProject("P"); } } @@ -2043,8 +2051,10 @@ * default output scenarii is still tolerated */ public void testClasspathValidation23() throws CoreException { + Hashtable options = JavaCore.getOptions(); try { IJavaProject proj = this.createJavaProject("P", new String[] {}, ""); + proj.setOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.IGNORE); IClasspathEntry[] originalCP = proj.getRawClasspath(); IClasspathEntry[] newCP = new IClasspathEntry[originalCP.length+2]; @@ -2061,6 +2071,7 @@ // "Source folder 'P/src' cannot output to distinct source folder 'P/'.", // status); } finally { + JavaCore.setOptions(options); this.deleteProject("P"); } } @@ -2305,11 +2316,15 @@ newCP[originalCP.length] = JavaCore.newSourceEntry(new Path("/P/src1"), new IPath[]{new Path("src2/")}, new Path("/P/src1/src2")); newCP[originalCP.length+1] = JavaCore.newSourceEntry(new Path("/P/src1/src2")); - IJavaModelStatus status = JavaConventions.validateClasspath(proj, newCP, proj.getOutputLocation()); + //IJavaModelStatus status = JavaConventions.validateClasspath(proj, newCP, proj.getOutputLocation()); + proj.setRawClasspath(newCP, proj.getOutputLocation(), null); - assertStatus( - "Source folder \'src1\' in project 'P' cannot output to distinct source folder \'src1/src2\'", - status); + assertMarkers( + "Unexpected markers", + "Project \'P\' is missing required source folder: \'src1\'\n" + + "Project \'P\' is missing required source folder: \'src1/src2\'\n" + + "Source folder \'src1\' in project \'P\' cannot output to distinct source folder \'src1/src2\'", + proj); } finally { this.deleteProject("P"); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java index dbc6e55..e25a8cb 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -114,4 +114,13 @@ * @since 2.0 */ String CLASSPATH_FILE_FORMAT = "classpathFileFormat"; //$NON-NLS-1$ + + /** + * Output overlapping another source attribute (value "outputOverlappingSource"Status constant indicating that the default or specific output folder is overlapping + * with another source location.

+ * @since 3.8 + */ + public static final int OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = 1013; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index eb37a96..a63d948 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -1879,6 +1879,18 @@ */ public static final String CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS = PLUGIN_ID + ".classpath.multipleOutputLocations"; //$NON-NLS-1$ /** + * Core option ID: Allowing specific output to overlap anther source location + *

When disabled, no specific output location can overlap another source entry. + * This ensures that source files are not mixed up with derived resources.

+ *
+ *
Option id:
"org.eclipse.jdt.core.classpath.allowOutputToOverlap"
+ *
Possible values:
{ "error", "warning", "ignore" }
+ *
Default:
"warning"
+ *
+ * @since 3.8 + */ + public static final String CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = PLUGIN_ID + ".classpath.outputOverlapingAnotherSource"; //$NON-NLS-1$ + /** * Core option ID: Set the timeout value for retrieving the method's parameter names from javadoc. *

Timeout in milliseconds to retrieve the method's parameter names from javadoc. *

If the value is 0, the parameter names are not fetched and the raw names are returned. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java index d8086ff..776ff3b 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java @@ -1575,7 +1575,7 @@ boolean hasSource = false; boolean hasLibFolder = false; - + ((JavaProject)javaProject).flushClasspathProblemMarkers(false, false, true); // tolerate null path, it will be reset to default if (rawClasspath == null) return JavaModelStatus.VERIFIED_OK; @@ -1788,24 +1788,30 @@ if (kind == IClasspathEntry.CPE_SOURCE) { IPath output = entry.getOutputLocation(); - if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate) - // if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output) + if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output) for (int j = 0; j < length; j++) { IClasspathEntry otherEntry = classpath[j]; if (otherEntry == entry) continue; - // Build some common strings for status message - boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0)); - String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString(); - switch (otherEntry.getEntryKind()) { case IClasspathEntry.CPE_SOURCE : - if (otherEntry.getPath().equals(output)) { - return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName})); + // Bug 287164 : Report errors of overlapping output locations only if the user sets the corresponding preference. + // The check is required for backward compatibility with bug-fix 36465. + String option = javaProject.getOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, true); + if (otherEntry.getPath().equals(output) + && !JavaCore.IGNORE.equals(option)) { + boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0)); + String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString(); + int severity = JavaCore.ERROR.equals(option) ? IStatus.ERROR : IStatus.WARNING; + return new JavaModelStatus(severity, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, + Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] { + entryPathMsg, otherPathMsg, projectName })); } break; case IClasspathEntry.CPE_LIBRARY : - if (otherEntry.getPath().equals(output)) { + if (output != projectOutputLocation && otherEntry.getPath().equals(output)) { + boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0)); + String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString(); return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseLibraryAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName})); } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java index ea310a3..07a8c82 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -37,7 +37,7 @@ // project doesn't exist IProject resource = this.project.getProject(); if (resource.isAccessible()) { - this.project.flushClasspathProblemMarkers(true/*flush cycle markers*/, true/*flush classpath format markers*/); + this.project.flushClasspathProblemMarkers(true/*flush cycle markers*/, true/*flush classpath format markers*/, true); // remove problems and tasks created by the builder JavaBuilder.removeProblemsAndTasksFor(resource); @@ -56,12 +56,12 @@ } // update classpath format problems - this.project.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/); + this.project.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/, false); if (!status.isOK()) this.project.createClasspathProblemMarker(status); // update resolved classpath problems - this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/); + this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/, false); if (rawClasspath != JavaProject.INVALID_CLASSPATH && outputLocation != null) { for (int i = 0; i < rawClasspath.length; i++) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java index 532ed94..835d1d6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java @@ -58,6 +58,7 @@ defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); + defaultOptionsMap.put(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.WARNING); // encoding setting comes from resource plug-in optionNames.add(JavaCore.CORE_ENCODING); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java index cdead40..fba912d 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java @@ -1481,7 +1481,8 @@ propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) || propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) || propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || - propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) { + propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL) || + propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE)) { JavaModelManager manager = JavaModelManager.getJavaModelManager(); IJavaModel model = manager.getJavaModel(); IJavaProject[] projects; @@ -2248,7 +2249,8 @@ defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER, JavaCore.IGNORE); defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.ERROR); - defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); + defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); + defaultOptionsMap.put(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.WARNING); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); 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 42b1890..22cc082 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 @@ -433,7 +433,7 @@ new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project, cycleString)); } } else { - project.flushClasspathProblemMarkers(true, false); + project.flushClasspathProblemMarkers(true, false, false); } } } @@ -803,7 +803,7 @@ IMarker marker = null; int severity; String[] arguments = CharOperation.NO_STRINGS; - boolean isCycleProblem = false, isClasspathFileFormatProblem = false; + boolean isCycleProblem = false, isClasspathFileFormatProblem = false, isOutputOverlapping = false; switch (status.getCode()) { case IJavaModelStatusConstants.CLASSPATH_CYCLE : @@ -830,7 +830,17 @@ return; // setting == IGNORE } break; - + case IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE : + isOutputOverlapping = true; + setting = getOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, true); + if (JavaCore.ERROR.equals(setting)) { + severity = IMarker.SEVERITY_ERROR; + } else if (JavaCore.WARNING.equals(setting)) { + severity = IMarker.SEVERITY_WARNING; + } else { + return; // setting == IGNORE + } + break; default: IPath path = status.getPath(); if (path != null) arguments = new String[] { path.toString() }; @@ -852,6 +862,7 @@ IMarker.LOCATION, IJavaModelMarker.CYCLE_DETECTED, IJavaModelMarker.CLASSPATH_FILE_FORMAT, + IJavaModelMarker.OUTPUT_OVERLAPPING_SOURCE, IJavaModelMarker.ID, IJavaModelMarker.ARGUMENTS , IJavaModelMarker.CATEGORY_ID, @@ -863,6 +874,7 @@ Messages.classpath_buildPath, isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$ isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$ + isOutputOverlapping ? "true" : "false", //$NON-NLS-1$ //$NON-NLS-2$ new Integer(status.getCode()), Util.getProblemArgumentsForMarker(arguments) , new Integer(CategorizedProblem.CAT_BUILDPATH), @@ -1356,18 +1368,20 @@ /** * Remove all markers denoting classpath problems */ //TODO (philippe) should improve to use a bitmask instead of booleans (CYCLE, FORMAT, VALID) - protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers) { + protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers, boolean flushOverlappingOutputMarkers) { try { if (this.project.isAccessible()) { IMarker[] markers = this.project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); for (int i = 0, length = markers.length; i < length; i++) { IMarker marker = markers[i]; - if (flushCycleMarkers && flushClasspathFormatMarkers) { + if (flushCycleMarkers && flushClasspathFormatMarkers && flushOverlappingOutputMarkers) { marker.delete(); } else { String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED); String classpathFileFormatAttr = (String)marker.getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT); + String overlappingOutputAttr = (String) marker.getAttribute(IJavaModelMarker.OUTPUT_OVERLAPPING_SOURCE); if ((flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))) //$NON-NLS-1$ + && (flushOverlappingOutputMarkers == (overlappingOutputAttr != null && overlappingOutputAttr.equals("true"))) //$NON-NLS-1$ && (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr.equals("true")))){ //$NON-NLS-1$ marker.delete(); } @@ -1513,6 +1527,7 @@ propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) || propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) || propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || + propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE) || propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) { manager.deltaState.addClasspathValidation(JavaProject.this);