From e4c1d89d1afccdc86d186ac7a43eb767c9b88d99 Mon Sep 17 00:00:00 2001 From: Alena Laskavaia Date: Thu, 5 Aug 2010 02:11:18 +0000 Subject: [PATCH] Bug 309607 lots of refactoring and changes to support better marker management - prevent fickering and improve performance --- .../META-INF/MANIFEST.MF | 2 +- .../cdt/codan/core/model/AbstractChecker.java | 75 +++++- .../core/model/AbstractProblemLocation.java | 44 +++- .../core/model/AbstractProblemReporter.java | 2 +- .../cdt/codan/core/model/CodanSeverity.java | 2 +- .../cdt/codan/core/model/IChecker.java | 15 ++ .../core/model/ICheckerInvocationContext.java | 34 +++ .../codan/core/model/ICodanProblemMarker.java | 7 +- .../IProblemReporterSessionPersistent.java | 66 +++++ .../core/CheckerInvocationContext.java | 41 +++ .../cdt/codan/internal/core/CodanBuilder.java | 45 ++-- .../model/CodanMarkerProblemReporter.java | 249 ++++++++++++++---- .../core/model/CodanProblemMarker.java | 31 +++ 13 files changed, 534 insertions(+), 79 deletions(-) create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICheckerInvocationContext.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IProblemReporterSessionPersistent.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckerInvocationContext.java diff --git a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF index ba450f62d85..40d3d8147fe 100644 --- a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.cdt.codan.core;singleton:=true -Bundle-Version: 1.1.0.qualifier +Bundle-Version: 2.0.0.qualifier Bundle-Activator: org.eclipse.cdt.codan.core.CodanCorePlugin Bundle-Vendor: %Bundle-Vendor Require-Bundle: org.eclipse.core.runtime, diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java index 411ba671246..cafdb0455bf 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.codan.core.model; import org.eclipse.cdt.codan.core.CodanRuntime; +import org.eclipse.cdt.codan.internal.core.CheckerInvocationContext; import org.eclipse.cdt.codan.internal.core.CheckersRegistry; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; @@ -22,6 +23,10 @@ import org.eclipse.core.resources.IResource; */ public abstract class AbstractChecker implements IChecker { protected String name; + /** + * @since 2.0 + */ + protected ICheckerInvocationContext context; /** * Default constructor @@ -34,7 +39,7 @@ public abstract class AbstractChecker implements IChecker { * false checker's "processResource" method won't be called */ public boolean enabledInContext(IResource res) { - return true; + return res instanceof IFile; } /** @@ -93,9 +98,14 @@ public abstract class AbstractChecker implements IChecker { /** * @return problem reporter for given checker + * @since 2.0 */ - protected IProblemReporter getProblemReporter() { - return CodanRuntime.getInstance().getProblemReporter(); + public IProblemReporter getProblemReporter() { + try { + return getContext().getProblemReporter(); + } catch (Exception e) { + return CodanRuntime.getInstance().getProblemReporter(); + } } /** @@ -158,4 +168,63 @@ public abstract class AbstractChecker implements IChecker { Object... args) { getProblemReporter().reportProblem(problemId, loc, args); } + + /** + * Get invocation context. + * + * @return checker invocation context + * + * @since 2.0 + */ + public ICheckerInvocationContext getContext() { + return context; + } + + /** + * Set the invocation context. Usually called by codan builder. + * Object that calls this should also synchronize of checker object + * to prevent multi-thread access to a running context + * + * @since 2.0 + */ + public void setContext(ICheckerInvocationContext context) { + this.context = context; + } + + /** + * @since 2.0 + */ + public boolean before(IResource resource) { + IChecker checker = this; + IProblemReporter problemReporter = CodanRuntime.getInstance() + .getProblemReporter(); + IProblemReporter sessionReporter = problemReporter; + if (problemReporter instanceof IProblemReporterSessionPersistent) { + // create session problem reporter + sessionReporter = ((IProblemReporterSessionPersistent) problemReporter) + .createReporter(resource, checker); + ((IProblemReporterSessionPersistent) sessionReporter).start(); + } else if (problemReporter instanceof IProblemReporterPersistent) { + // delete markers if checker can possibly run on this + // resource this way if checker is not enabled markers would be + // deleted too + ((IProblemReporterPersistent) problemReporter).deleteProblems( + resource, checker); + } + ((AbstractChecker) checker).setContext(new CheckerInvocationContext( + resource, sessionReporter)); + return true; + } + + /** + * @since 2.0 + */ + public boolean after(IResource resource) { + if (getContext().getProblemReporter() instanceof IProblemReporterSessionPersistent) { + // delete general markers + ((IProblemReporterSessionPersistent) getContext() + .getProblemReporter()).done(); + } + return true; + } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemLocation.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemLocation.java index 7ce453f8dc0..0f210795c93 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemLocation.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemLocation.java @@ -35,7 +35,7 @@ public abstract class AbstractProblemLocation implements IProblemLocation { } /** - * @since 1.1 + * @since 2.0 */ protected AbstractProblemLocation(IResource file, int line) { this.file = file; @@ -49,7 +49,7 @@ public abstract class AbstractProblemLocation implements IProblemLocation { } /** - * @since 1.1 + * @since 2.0 */ protected AbstractProblemLocation(IResource file, int startChar, int endChar) { this.file = file; @@ -87,7 +87,7 @@ public abstract class AbstractProblemLocation implements IProblemLocation { /** * @return resource for which marker is created - * @since 1.1 + * @since 2.0 */ public IResource getResource() { return file; @@ -124,4 +124,42 @@ public abstract class AbstractProblemLocation implements IProblemLocation { public int getEndingChar() { return posEnd; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((extra == null) ? 0 : extra.hashCode()); + result = prime * result + ((file == null) ? 0 : file.hashCode()); + result = prime * result + line; + result = prime * result + posEnd; + result = prime * result + posStart; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!(obj instanceof AbstractProblemLocation)) + return false; + AbstractProblemLocation other = (AbstractProblemLocation) obj; + if (line != other.line) + return false; + if (posEnd != other.posEnd) + return false; + if (posStart != other.posStart) + return false; + if (extra == null) { + if (other.extra != null) + return false; + } else if (!extra.equals(other.extra)) + return false; + if (file == null) { + if (other.file != null) + return false; + } else if (!file.equals(other.file)) + return false; + return true; + } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemReporter.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemReporter.java index fe1a93e9039..1dc13b027e2 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemReporter.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractProblemReporter.java @@ -17,7 +17,7 @@ import org.eclipse.core.resources.IResource; /** * Abstract implementation of a IProblemReporter * - * @since 1.1 + * @since 2.0 */ public abstract class AbstractProblemReporter implements IProblemReporter { public void reportProblem(String id, IProblemLocation loc, Object... args) { diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CodanSeverity.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CodanSeverity.java index 6f340dc8493..c75d9985cae 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CodanSeverity.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CodanSeverity.java @@ -60,7 +60,7 @@ public enum CodanSeverity { /** * @param intValue * @return value of severity by its integer value - * @since 1.1 + * @since 2.0 */ public static CodanSeverity valueOf(int intValue) { if (intValue == IMarker.SEVERITY_INFO) diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java index f00fea0494b..af32d6eb6af 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java @@ -37,6 +37,21 @@ public interface IChecker { */ boolean processResource(IResource resource); + /** + * @since 2.0 + */ + boolean before(IResource resource); + + /** + * @since 2.0 + */ + boolean after(IResource resource); + + /** + * @since 2.0 + */ + IProblemReporter getProblemReporter(); + /** * Implement this method to trim down type of resource you are interested * in, usually it will be c/c++ files only. This method should be diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICheckerInvocationContext.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICheckerInvocationContext.java new file mode 100644 index 00000000000..057ee6abb88 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICheckerInvocationContext.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009,2010 QNX Software Systems + * 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems (Alena Laskavaia) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.model; + +import org.eclipse.core.resources.IResource; + +/** + * Since there is only one instance of checker available this object keeps + * track of invocation context - which would usually contain resource and some + * other object that checker require + *

+ * EXPERIMENTAL. This class or interface has been added as part + * of a work in progress. There is no guarantee that this API will work or that + * it will remain the same. + *

+ * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * + * @since 2.0 + */ +public interface ICheckerInvocationContext { + IResource getResource(); + + IProblemReporter getProblemReporter(); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICodanProblemMarker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICodanProblemMarker.java index c19cdf9de72..d8021e52805 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICodanProblemMarker.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICodanProblemMarker.java @@ -18,7 +18,7 @@ import org.eclipse.core.runtime.CoreException; * Instance of a problem. Intermediate representation before problem become a * marker. * - * @since 1.1 + * @since 2.0 */ public interface ICodanProblemMarker { /** @@ -56,4 +56,9 @@ public interface ICodanProblemMarker { * @return message */ public String createMessage(); + + /** + * @return problem arguments + */ + public Object[] getArgs(); } \ No newline at end of file diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IProblemReporterSessionPersistent.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IProblemReporterSessionPersistent.java new file mode 100644 index 00000000000..edf7a63bab0 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IProblemReporterSessionPersistent.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.model; + +import org.eclipse.core.resources.IResource; + +/** + * IProblemReporterPersistent - interface to report problems, which are + * persistent, ex. markers. Also this object has context of checker and + * current resource, which allows to manage markers better - i.e. instead of + * deleting replace them when needed, and queue markers for insertion instead + * of add right away. + * + *

+ * EXPERIMENTAL. This class or interface has been added as part + * of a work in progress. There is no guarantee that this API will work or that + * it will remain the same. + *

+ * + * @since 2.0 + */ +public interface IProblemReporterSessionPersistent extends IProblemReporter { + /** + * Delete all problems associated with session resource and session checker. + * If "all" is true also delete all problems associated with workspace (and + * session checker) + * + */ + public void deleteProblems(boolean all); + + /** + * Notify that session is started + */ + public void start(); + + /** + * Notify that session is + * ended + */ + public void done(); + + IChecker getChecker(); + + IResource getResource(); + + /** + * Create an instance of the object.This is a bit ugly since implemented has + * to combine + * object itself and factory to this object. + * + * @param resource + * @param checker + * @return + * @since 2.0 + */ + public IProblemReporterSessionPersistent createReporter(IResource resource, + IChecker checker); +} \ No newline at end of file diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckerInvocationContext.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckerInvocationContext.java new file mode 100644 index 00000000000..69b75bb4056 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckerInvocationContext.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2009,2010 QNX Software Systems + * 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems (Alena Laskavaia) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core; + +import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext; +import org.eclipse.cdt.codan.core.model.IProblemReporter; +import org.eclipse.core.resources.IResource; + +/** + * Implementation of ICheckerInvocationContext + */ +public class CheckerInvocationContext implements ICheckerInvocationContext { + private IResource resource; + private IProblemReporter sessionReporter; + + /** + * @param resource + * @param sessionReporter + */ + public CheckerInvocationContext(IResource resource, + IProblemReporter sessionReporter) { + this.resource = resource; + this.sessionReporter = sessionReporter; + } + + public IResource getResource() { + return resource; + } + + public IProblemReporter getProblemReporter() { + return sessionReporter; + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java index 6685b98f4da..bd3cb6721f1 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java @@ -13,12 +13,9 @@ package org.eclipse.cdt.codan.internal.core; import java.util.Map; import org.eclipse.cdt.codan.core.CodanCorePlugin; -import org.eclipse.cdt.codan.core.CodanRuntime; import org.eclipse.cdt.codan.core.Messages; import org.eclipse.cdt.codan.core.model.IChecker; import org.eclipse.cdt.codan.core.model.ICodanBuilder; -import org.eclipse.cdt.codan.core.model.IProblemReporter; -import org.eclipse.cdt.codan.core.model.IProblemReporterPersistent; import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; @@ -115,31 +112,35 @@ public class CodanBuilder extends IncrementalProjectBuilder implements monitor.beginTask(Messages.CodanBuilder_Code_Analysis_On + resource, checkers + memsize * tick); try { - IProblemReporter problemReporter = CodanRuntime.getInstance() - .getProblemReporter(); for (IChecker checker : chegistry) { try { if (monitor.isCanceled()) return; if (checker.enabledInContext(resource)) { - // delete markers if checker can possibly run on this - // resource - // this way if checker is not enabled markers would be - // deleted too - if (problemReporter instanceof IProblemReporterPersistent) { - // delete general markers - ((IProblemReporterPersistent) problemReporter) - .deleteProblems(resource, checker); - } - if (chegistry.isCheckerEnabled(checker, resource)) { - if (inEditor) { - if (checker.runInEditor() - && checker instanceof IRunnableInEditorChecker) { - ((IRunnableInEditorChecker) checker) - .processModel(model); + synchronized (checker) { + try { + checker.before(resource); + if (chegistry.isCheckerEnabled(checker, + resource)) { + //long time = System.currentTimeMillis(); + if (inEditor) { + if (checker.runInEditor() + && checker instanceof IRunnableInEditorChecker) { + ((IRunnableInEditorChecker) checker) + .processModel(model); + } + } else { + checker.processResource(resource); + } + // System.err + // .println("Checker " + // + checker.getClass() + // + " worked " + // + (System + // .currentTimeMillis() - time)); } - } else { - checker.processResource(resource); + } finally { + checker.after(resource); } } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java index 91f8bbccc6d..eda96e061fc 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.cdt.codan.internal.core.model; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @@ -20,7 +22,9 @@ import org.eclipse.cdt.codan.core.model.IChecker; import org.eclipse.cdt.codan.core.model.ICheckersRegistry; import org.eclipse.cdt.codan.core.model.ICodanProblemMarker; import org.eclipse.cdt.codan.core.model.IProblem; +import org.eclipse.cdt.codan.core.model.IProblemLocation; import org.eclipse.cdt.codan.core.model.IProblemReporterPersistent; +import org.eclipse.cdt.codan.core.model.IProblemReporterSessionPersistent; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; @@ -33,10 +37,45 @@ import org.eclipse.core.runtime.IProgressMonitor; * Problem reported that created eclipse markers */ public class CodanMarkerProblemReporter extends AbstractProblemReporter - implements IProblemReporterPersistent { + implements IProblemReporterPersistent, + IProblemReporterSessionPersistent { + private IResource resource; + private IChecker checker; + private ArrayList toAdd = new ArrayList(); + + /** + * Create instance, which can be use as factory for + * IProblemReporterSessionPersistent or + * as IProblemReporterPersistent. + */ + public CodanMarkerProblemReporter() { + super(); + } + + /** + * @param resource + * @param checker + */ + public CodanMarkerProblemReporter(IResource resource, IChecker checker) { + this.resource = resource; + this.checker = checker; + } + + public IResource getResource() { + return resource; + } + + public IChecker getChecker() { + return checker; + } + @Override protected void reportProblem(ICodanProblemMarker codanProblemMarker) { - createProblem(codanProblemMarker); + if (checker == null) { + createProblem(codanProblemMarker); + } else { + toAdd.add(codanProblemMarker); + } } /** @@ -44,28 +83,6 @@ public class CodanMarkerProblemReporter extends AbstractProblemReporter */ protected IMarker createProblem(ICodanProblemMarker codanProblemMarker) { try { - // Do not put in duplicates - IMarker[] cur = codanProblemMarker.getResource().findMarkers( - codanProblemMarker.getProblem().getMarkerType(), false, - IResource.DEPTH_ZERO); - if (cur != null) { - String message = codanProblemMarker.createMessage(); - for (IMarker element : cur) { - int line = ((Integer) element - .getAttribute(IMarker.LINE_NUMBER)).intValue(); - if (line == codanProblemMarker.getLocation() - .getLineNumber()) { - String mesg = (String) element - .getAttribute(IMarker.MESSAGE); - int sev = ((Integer) element - .getAttribute(IMarker.SEVERITY)).intValue(); - if (sev == codanProblemMarker.getProblem() - .getSeverity().intValue() - && mesg.equals(message)) - return element; - } - } - } return codanProblemMarker.createMarker(); } catch (CoreException e) { CodanCorePlugin.log(e); @@ -94,33 +111,16 @@ public class CodanMarkerProblemReporter extends AbstractProblemReporter } } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.cdt.codan.core.model.IProblemReporterPersistent#deleteProblems - * (org.eclipse.core.resources.IResource, - * org.eclipse.cdt.codan.core.model.IChecker) - */ public void deleteProblems(final IResource file, final IChecker checker) { try { ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { - IMarker[] markers = file.findMarkers( - GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, - IResource.DEPTH_INFINITE); - ICheckersRegistry reg = CodanRuntime.getInstance() - .getCheckersRegistry(); - for (int i = 0; i < markers.length; i++) { - IMarker m = markers[i]; - String id = m.getAttribute(IMarker.PROBLEM, ""); //$NON-NLS-1$ - Collection problems = reg.getRefProblems(checker); - for (Iterator iterator = problems.iterator(); iterator - .hasNext();) { - IProblem iProblem = iterator.next(); - if (iProblem.getId().equals(id)) - m.delete(); - } + Collection markers = findResourceMarkers(file, + checker); + for (Iterator iterator = markers.iterator(); iterator + .hasNext();) { + IMarker iMarker = iterator.next(); + iMarker.delete(); } } }, null, IWorkspace.AVOID_UPDATE, null); @@ -128,4 +128,159 @@ public class CodanMarkerProblemReporter extends AbstractProblemReporter CodanCorePlugin.log(e); } } + + protected Collection findResourceMarkers(IResource resource, + IChecker checker) throws CoreException { + Collection res = new ArrayList(); + IMarker[] markers = resource.findMarkers( + GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, + IResource.DEPTH_INFINITE); + ICheckersRegistry reg = CodanRuntime.getInstance() + .getCheckersRegistry(); + Collection problems = reg.getRefProblems(checker); + for (int i = 0; i < markers.length; i++) { + IMarker m = markers[i]; + String id = m.getAttribute(IMarker.PROBLEM, ""); //$NON-NLS-1$ + for (Iterator iterator = problems.iterator(); iterator + .hasNext();) { + IProblem iProblem = iterator.next(); + if (iProblem.getId().equals(id)) { + res.add(m); + } + } + } + return res; + } + + /** + * @param resource + * @param checker + * @return session aware problem reporter + * @since 1.1 + */ + public IProblemReporterSessionPersistent createReporter(IResource resource, + IChecker checker) { + return new CodanMarkerProblemReporter(resource, checker); + } + + public void start() { + if (checker == null) + deleteProblems(false); + } + + public void done() { + if (checker != null) { + if (toAdd.size() == 0) + deleteProblems(false); + else + reconcileMarkers(); + toAdd.clear(); + } + } + + protected void reconcileMarkers() { + try { + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + Collection markers = findResourceMarkers(resource, + checker); + for (Iterator iterator = markers.iterator(); iterator + .hasNext();) { + IMarker m = iterator.next(); + ICodanProblemMarker cm = similarMarker(m); + if (cm == null) { + m.delete(); + } else { + updateMarker(m, cm); + toAdd.remove(cm); + } + } + for (Iterator iterator = toAdd + .iterator(); iterator.hasNext();) { + ICodanProblemMarker cm = iterator.next(); + cm.createMarker(); + } + } + }, null, IWorkspace.AVOID_UPDATE, null); + } catch (CoreException e) { + CodanCorePlugin.log(e); + } + } + + /** + * @param m + * @param cm + */ + protected void updateMarker(IMarker m, ICodanProblemMarker cm) { + IProblemLocation loc = cm.getLocation(); + try { + if (m.getAttribute(IMarker.LINE_NUMBER, 0) != loc.getLineNumber()) + m.setAttribute(IMarker.LINE_NUMBER, loc.getLineNumber()); + if (m.getAttribute(IMarker.CHAR_START, 0) != loc.getStartingChar()) + m.setAttribute(IMarker.CHAR_START, loc.getStartingChar()); + if (m.getAttribute(IMarker.CHAR_END, 0) != loc.getEndingChar()) + m.setAttribute(IMarker.CHAR_END, loc.getEndingChar()); + } catch (CoreException e) { + try { + m.delete(); + cm.createMarker(); + } catch (CoreException e1) { + CodanCorePlugin.log(e1); + } + } + } + + /** + * @param m + * @return + */ + protected ICodanProblemMarker similarMarker(IMarker m) { + ICodanProblemMarker mcm = CodanProblemMarker + .createCodanProblemMarkerFromResourceMarker(m); + ArrayList cand = new ArrayList(); + for (Iterator iterator = toAdd.iterator(); iterator + .hasNext();) { + ICodanProblemMarker cm = iterator.next(); + if (mcm.equals(cm)) + return cm; + if (similarTo(mcm, cm)) { + cand.add(cm); + } + } + if (cand.size() == 1) + return cand.get(0); + return null; + } + + /** + * @param mcm + * @param cm + * @return + */ + private boolean similarTo(ICodanProblemMarker mcm, ICodanProblemMarker other) { + if (!mcm.getProblem().getId().equals(other.getProblem().getId())) + return false; + if (!Arrays.equals(mcm.getArgs(), other.getArgs())) + return false; + IProblemLocation loc1 = mcm.getLocation(); + IProblemLocation loc2 = other.getLocation(); + if (!loc1.getFile().equals(loc2.getFile())) + return false; + if (Math.abs(loc1.getLineNumber() - loc2.getLineNumber()) > 2) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.IProblemReporterSessionPersistent# + * deleteProblems(boolean) + */ + public void deleteProblems(boolean all) { + if (all == false) + deleteProblems(resource, checker); + else + throw new UnsupportedOperationException(); + } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemMarker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemMarker.java index 5e5891de791..4b61832771d 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemMarker.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemMarker.java @@ -14,6 +14,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.text.MessageFormat; +import java.util.Arrays; import java.util.Properties; import org.eclipse.cdt.codan.core.model.CodanSeverity; @@ -37,6 +38,10 @@ public class CodanProblemMarker implements ICodanProblemMarker { private IProblem problem; private Object args[]; + public Object[] getArgs() { + return args; + } + /** * @param problem * @param loc @@ -266,4 +271,30 @@ public class CodanProblemMarker implements ICodanProblemMarker { String propArgs = serializeArgs(args); marker.setAttribute(PROBLEM_ARGS, propArgs); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(args); + result = prime * result + ((loc == null) ? 0 : loc.hashCode()); + result = prime * result + problem.getId().hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!(obj instanceof ICodanProblemMarker)) + return false; + CodanProblemMarker other = (CodanProblemMarker) obj; + if (!Arrays.equals(args, other.args)) + return false; + if (!loc.equals(other.loc)) + return false; + if (!problem.getId().equals(other.problem.getId())) + return false; + return true; + } }