diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java index 41dab02d436..2e1a8067913 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2016 Wind River Systems and others. + * Copyright (c) 2010, 2017 Wind River Systems 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 @@ -125,7 +125,14 @@ public class ExternalBuildRunner extends AbstractBuildRunner { buildRunnerHelper.removeOldMarkers(project, new SubProgressMonitor(monitor, TICKS_DELETE_MARKERS, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); buildRunnerHelper.greeting(kind, cfgName, toolchainName, isSupported); - int state = buildRunnerHelper.build(new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + + int state; + epm.deferDeDuplication(); + try { + state = buildRunnerHelper.build(new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + } finally { + epm.deDuplicate(); + } buildRunnerHelper.close(); buildRunnerHelper.goodbye(); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java index 78542b5a6a6..564d231f7e9 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Wind River Systems and others. + * Copyright (c) 2010, 2017 Wind River Systems 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 @@ -124,21 +124,26 @@ public class InternalBuildRunner extends AbstractBuildRunner { OutputStream stderr = buildRunnerHelper.getErrorStream(); int status; - if (dBuilder != null) { - status = dBuilder.build(stdout, stderr, new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); - } else { - status = ParallelBuilder.build(des, null, null, stdout, stderr, new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK), resumeOnErr, buildIncrementaly); - // Bug 403670: - // Make sure the build configuration's rebuild status is updated with the result of - // this successful build. In the non-parallel case this happens within dBuilder.build - // (the cBS is passed as an instance of IResourceRebuildStateContainer). - if (status == ParallelBuilder.STATUS_OK) - cBS.setState(0); - buildRunnerHelper.printLine(ManagedMakeMessages.getFormattedString("CommonBuilder.7", Integer.toString(ParallelBuilder.lastThreadsUsed))); //$NON-NLS-1$ + epm.deferDeDuplication(); + try { + + if (dBuilder != null) { + status = dBuilder.build(stdout, stderr, new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + } else { + status = ParallelBuilder.build(des, null, null, stdout, stderr, new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK), resumeOnErr, buildIncrementaly); + // Bug 403670: + // Make sure the build configuration's rebuild status is updated with the result of + // this successful build. In the non-parallel case this happens within dBuilder.build + // (the cBS is passed as an instance of IResourceRebuildStateContainer). + if (status == ParallelBuilder.STATUS_OK) + cBS.setState(0); + buildRunnerHelper.printLine(ManagedMakeMessages.getFormattedString("CommonBuilder.7", Integer.toString(ParallelBuilder.lastThreadsUsed))); //$NON-NLS-1$ + } + } finally { + epm.deDuplicate(); } - + bsMngr.setProjectBuildState(project, pBS); - buildRunnerHelper.close(); buildRunnerHelper.goodbye(); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java index 8a0c7cc465c..9385c8a2e81 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2016 IBM Corporation and others. + * Copyright (c) 2005, 2017 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 @@ -101,6 +101,8 @@ public class ErrorParserManager extends OutputStream implements IConsoleParser, private URI cachedWorkingDirectory = null; private IFile cachedFile = null; + private boolean deferDeDuplication = false; + private static boolean isCygwin = true; /** @@ -599,6 +601,7 @@ outer: if ( ! ProblemMarkerFilterManager.getInstance().acceptMarker(problemMarkerInfo) ) return; fErrors.add(problemMarkerInfo); + problemMarkerInfo.setDeferDeDuplication(deferDeDuplication); fMarkerGenerator.addMarker(problemMarkerInfo); if (problemMarkerInfo.severity == IMarkerGenerator.SEVERITY_ERROR_RESOURCE) { hasErrors = true; @@ -897,4 +900,29 @@ outer: } } } + + /** + * Flag the marker generator to defer the de-duplication of error markers + * until {@link #deDuplicate()} is called + * + * @since 6.3 + */ + public void deferDeDuplication() { + if (fMarkerGenerator instanceof ACBuilder) { + deferDeDuplication = true; + } + } + + /** + * De-duplicate error markers on resource that have had error markers added + * since {@link #deferDeDuplication()} was called. + * + * @since 6.3 + */ + public void deDuplicate() { + if (deferDeDuplication) { + deferDeDuplication = false; + ((ACBuilder) fMarkerGenerator).deDuplicate(); + } + } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java index f4da6190707..286ec76c3c8 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2015 Siemens AG and others. + * Copyright (c) 2006, 2017 Siemens AG and others. * All rights reserved. This content 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 @@ -50,6 +50,12 @@ public class ProblemMarkerInfo { private Map attributes; private String type; + /** + * Flag marker for potential deferred de-duplication. See + * {@link ACBuilder#deDuplicate()} + */ + private boolean deferDeDuplication; + /** * Create a new {@link ProblemMarkerInfo} object. * @@ -161,4 +167,26 @@ public class ProblemMarkerInfo { public void setType(String type){ this.type = type; } -} \ No newline at end of file + + /** + * Flag marker for potential deferred de-duplication. See + * {@link ACBuilder#deDuplicate()} + * + * @return the deferDeDuplication + * @since 6.3 + */ + public boolean isDeferDeDuplication() { + return deferDeDuplication; + } + + /** + * Flag marker for potential deferred de-duplication. See + * {@link ACBuilder#deDuplicate()} + * + * @param deferDeDuplication the deferDeDuplication to set + * @since 6.3 + */ + public void setDeferDeDuplication(boolean deferDeDuplication) { + this.deferDeDuplication = deferDeDuplication; + } +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ACBuilder.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ACBuilder.java index 50a7fc2de47..92eb57e4522 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ACBuilder.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/ACBuilder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2016 QNX Software Systems and others. + * Copyright (c) 2000, 2017 QNX Software Systems 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 @@ -9,13 +9,19 @@ * QNX Software Systems - Initial API and implementation * IBM Corporation * James Blackburn (Broadcom Corp.) + * Jonah Graham (Kichwa Coders) - Bug 314428: New implementation for removing duplicate error markers *******************************************************************************/ package org.eclipse.cdt.core.resources; import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CCorePreferenceConstants; @@ -44,6 +50,7 @@ public abstract class ACBuilder extends IncrementalProjectBuilder implements IMa protected static final boolean DEBUG_EVENTS = false; private IProject currentProject; + private Set resourcesToDeduplicate = new HashSet<>(); /** * Constructor for ACBuilder @@ -54,7 +61,7 @@ public abstract class ACBuilder extends IncrementalProjectBuilder implements IMa /** * Set the current project that this builder is running. - * + * * @since 5.11 */ protected void setCurrentProject(IProject project) { @@ -63,7 +70,7 @@ public abstract class ACBuilder extends IncrementalProjectBuilder implements IMa /** * Returns the current project that this builder is running. - * + * * @return the project * @since 5.11 */ @@ -80,6 +87,79 @@ public abstract class ACBuilder extends IncrementalProjectBuilder implements IMa addMarker(problemMarkerInfo); } + private static class MarkerWithInfo { + private static final String[] ATTRIBUTE_NAMES = new String[] { IMarker.LINE_NUMBER, IMarker.SEVERITY, + IMarker.MESSAGE, ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION, IMarker.SOURCE_ID }; + private Object[] attributes; + + MarkerWithInfo(IMarker marker) throws CoreException { + attributes = marker.getAttributes(ATTRIBUTE_NAMES); + } + + @Override + public int hashCode() { + return Arrays.hashCode(attributes); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MarkerWithInfo otherInfo = (MarkerWithInfo)obj; + return Arrays.equals(attributes, otherInfo.attributes); + } + } + + /** + * Remove duplicate error markers that may have been created by + * {@link ACBuilder#addMarker(ProblemMarkerInfo)} with the + * {@link ProblemMarkerInfo#isDeferDeDuplication()} flag set. + * + * This method will also remove other duplicate + * ICModelMarker.C_MODEL_PROBLEM_MARKER markers on the resources referred to + * by ProblemMarkerInfo. + * + * @since 6.3 + */ + public void deDuplicate() { + /* + * In practice it is actually faster to create all the markers and then + * remove duplicates than try to search on each marker creation if the + * marker already exists. This code is faster because it makes one pass + * through the markers, instead of one pass for each new marker. As + * getting attributes for makers is very expensive, only having to fetch + * marker attributes once per marker speeds things up considerably. + */ + for (IResource resource : resourcesToDeduplicate) { + try { + IMarker[] markers = resource.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, + IResource.DEPTH_ZERO); + List dups = new ArrayList<>(markers.length); + Set unique = new HashSet<>(markers.length); + for (IMarker marker : markers) { + MarkerWithInfo info = new MarkerWithInfo(marker); + if (!unique.add(info)) { + dups.add(marker); + } + } + for (IMarker marker : dups) { + marker.delete(); + } + } catch (CoreException e) { + CCorePlugin.log(e.getStatus()); + } + } + + resourcesToDeduplicate = new HashSet<>(); + } + /** * Callback from Output Parser */ @@ -96,24 +176,28 @@ public abstract class ACBuilder extends IncrementalProjectBuilder implements IMa externalLocation = problemMarkerInfo.externalPath.toOSString(); } - // Try to find matching markers and don't put in duplicates - IMarker[] markers = markerResource.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_ONE); - for (IMarker m : markers) { - int line = m.getAttribute(IMarker.LINE_NUMBER, -1); - int sev = m.getAttribute(IMarker.SEVERITY, -1); - String msg = (String) m.getAttribute(IMarker.MESSAGE); - if (line == problemMarkerInfo.lineNumber && sev == mapMarkerSeverity(problemMarkerInfo.severity) && msg.equals(problemMarkerInfo.description)) { - String extloc = (String) m.getAttribute(ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION); - if (extloc == externalLocation || (extloc != null && extloc.equals(externalLocation))) { - if (project == null || project.equals(markerResource.getProject())) { - return; - } - String source = (String) m.getAttribute(IMarker.SOURCE_ID); - if (project.getName().equals(source)) { - return; + if (!problemMarkerInfo.isDeferDeDuplication()) { + // Try to find matching markers and don't put in duplicates + IMarker[] markers = markerResource.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_ONE); + for (IMarker m : markers) { + int line = m.getAttribute(IMarker.LINE_NUMBER, -1); + int sev = m.getAttribute(IMarker.SEVERITY, -1); + String msg = (String) m.getAttribute(IMarker.MESSAGE); + if (line == problemMarkerInfo.lineNumber && sev == mapMarkerSeverity(problemMarkerInfo.severity) && msg.equals(problemMarkerInfo.description)) { + String extloc = (String) m.getAttribute(ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION); + if (extloc == externalLocation || (extloc != null && extloc.equals(externalLocation))) { + if (project == null || project.equals(markerResource.getProject())) { + return; + } + String source = (String) m.getAttribute(IMarker.SOURCE_ID); + if (project.getName().equals(source)) { + return; + } } } } + } else { + resourcesToDeduplicate.add(markerResource); } String type = problemMarkerInfo.getType();