/******************************************************************************* * Copyright (c) 2009, 2014 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.internal.core.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import org.eclipse.cdt.codan.core.CodanCorePlugin; import org.eclipse.cdt.codan.core.CodanRuntime; import org.eclipse.cdt.codan.core.model.AbstractProblemReporter; 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; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; /** * Problem reported that created eclipse markers */ public class CodanMarkerProblemReporter extends AbstractProblemReporter implements IProblemReporterPersistent, IProblemReporterSessionPersistent { private IResource resource; private IChecker checker; private ArrayList<ICodanProblemMarker> 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; } @Override public IResource getResource() { return resource; } @Override public IChecker getChecker() { return checker; } @Override protected void reportProblem(ICodanProblemMarker codanProblemMarker) { if (checker == null) { createProblem(codanProblemMarker); } else { toAdd.add(codanProblemMarker); } } /** * @param codanProblemMarker */ protected IMarker createProblem(ICodanProblemMarker codanProblemMarker) { try { return codanProblemMarker.createMarker(); } catch (CoreException e) { CodanCorePlugin.log(e); return null; } } @Override public void deleteProblems(IResource file) { try { file.deleteMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, IResource.DEPTH_ZERO); } catch (CoreException ce) { CodanCorePlugin.log(ce); } } @Override public void deleteAllProblems() { try { ResourcesPlugin.getWorkspace().getRoot().deleteMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, IResource.DEPTH_INFINITE); } catch (CoreException e) { CodanCorePlugin.log(e); } } @Override public void deleteProblems(final IResource file, final IChecker checker) { try { ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { Collection<IMarker> markers = findResourceMarkers(file, checker); for (IMarker marker : markers) { marker.delete(); } } }, null, IWorkspace.AVOID_UPDATE, null); } catch (CoreException e) { CodanCorePlugin.log(e); } } protected Collection<IMarker> findResourceMarkers(IResource resource, IChecker checker) throws CoreException { Collection<IMarker> res = new ArrayList<>(); IMarker[] markers; if (resource.exists()) { markers = resource.findMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, IResource.DEPTH_INFINITE); } else { if (resource.getProject() == null || !resource.getProject().isAccessible()) return res; // non resource markers attached to a project itself markers = resource.getProject().findMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, IResource.DEPTH_ZERO); } ICheckersRegistry reg = CodanRuntime.getInstance().getCheckersRegistry(); Collection<IProblem> problems = reg.getRefProblems(checker); for (IMarker m : markers) { String id = m.getAttribute(ICodanProblemMarker.ID, ""); //$NON-NLS-1$ for (IProblem problem : problems) { if (problem.getId().equals(id)) { res.add(m); } } } return res; } /** * @param resource * @param checker * @return session aware problem reporter * @since 1.1 */ @Override public IProblemReporterSessionPersistent createReporter(IResource resource, IChecker checker) { return new CodanMarkerProblemReporter(resource, checker); } @Override public void start() { if (checker == null) deleteProblems(false); } @Override public void done() { if (checker != null) { if (toAdd.isEmpty()) { deleteProblems(false); } else { reconcileMarkers(); } toAdd.clear(); } } protected void reconcileMarkers() { try { ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { Collection<IMarker> markers = findResourceMarkers(resource, checker); for (IMarker m : markers) { ICodanProblemMarker cm = similarMarker(m); if (cm == null) { m.delete(); } else { updateMarker(m, cm); toAdd.remove(cm); } } for (ICodanProblemMarker cm : toAdd) { 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()); int severity = cm.getProblem().getSeverity().intValue(); if (m.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO) != severity) m.setAttribute(IMarker.SEVERITY, severity); } 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<>(); for (ICodanProblemMarker cm : toAdd) { if (mcm.equals(cm)) return cm; if (markersAreSimilar(mcm, cm)) { cand.add(cm); } } if (cand.size() == 1) return cand.get(0); return null; } /** * @param marker1 * @param marker2 * @return */ private boolean markersAreSimilar(ICodanProblemMarker marker1, ICodanProblemMarker marker2) { if (!marker1.getProblem().getId().equals(marker2.getProblem().getId())) return false; if (!Arrays.equals(marker1.getArgs(), marker2.getArgs())) return false; IProblemLocation loc1 = marker1.getLocation(); IProblemLocation loc2 = marker2.getLocation(); if (!loc1.getFile().equals(loc2.getFile())) return false; if (Math.abs(loc1.getLineNumber() - loc2.getLineNumber()) > 2) return false; return true; } @Override public void deleteProblems(boolean all) { if (all) throw new UnsupportedOperationException(); deleteProblems(resource, checker); } }