mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-01 06:05:24 +02:00
Bug 309607 lots of refactoring and changes to support better marker management - prevent fickering and improve performance
This commit is contained in:
parent
4fa5682c4d
commit
e4c1d89d1a
13 changed files with 534 additions and 79 deletions
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. 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.
|
||||
* </p>
|
||||
*
|
||||
* @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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. 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.
|
||||
* </p>
|
||||
*
|
||||
* @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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ICodanProblemMarker> toAdd = new ArrayList<ICodanProblemMarker>();
|
||||
|
||||
/**
|
||||
* 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<IProblem> problems = reg.getRefProblems(checker);
|
||||
for (Iterator<IProblem> iterator = problems.iterator(); iterator
|
||||
.hasNext();) {
|
||||
IProblem iProblem = iterator.next();
|
||||
if (iProblem.getId().equals(id))
|
||||
m.delete();
|
||||
}
|
||||
Collection<IMarker> markers = findResourceMarkers(file,
|
||||
checker);
|
||||
for (Iterator<IMarker> 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<IMarker> findResourceMarkers(IResource resource,
|
||||
IChecker checker) throws CoreException {
|
||||
Collection<IMarker> res = new ArrayList<IMarker>();
|
||||
IMarker[] markers = resource.findMarkers(
|
||||
GENERIC_CODE_ANALYSIS_MARKER_TYPE, true,
|
||||
IResource.DEPTH_INFINITE);
|
||||
ICheckersRegistry reg = CodanRuntime.getInstance()
|
||||
.getCheckersRegistry();
|
||||
Collection<IProblem> 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<IProblem> 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<IMarker> markers = findResourceMarkers(resource,
|
||||
checker);
|
||||
for (Iterator<IMarker> 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<ICodanProblemMarker> 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<ICodanProblemMarker> cand = new ArrayList<ICodanProblemMarker>();
|
||||
for (Iterator<ICodanProblemMarker> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue