/******************************************************************************* * 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 * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.codan.core.model; import java.util.ArrayList; import java.util.List; import org.eclipse.cdt.codan.core.CodanRuntime; import org.eclipse.cdt.codan.internal.core.CheckersRegistry; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.OperationCanceledException; /** * Convenience implementation of IChecker interface. Has a default * implementation for common methods. */ public abstract class AbstractChecker implements IChecker { /** * @since 2.0 */ private ICheckerInvocationContext context; private IProblemReporter problemReporter; /** * Default constructor */ public AbstractChecker() { } /** * @return true if checker is enabled in context of resource, if returns * false checker's "processResource" method won't be called */ public boolean enabledInContext(IResource res) { return res instanceof IFile; } /** * Reports a simple problem for given file and line * * @param id * - problem id * @param file * - file * @param lineNumber * - line * @param args * - problem arguments, if problem does not define error message * it will be error message (not recommended because of * internationalization) */ public void reportProblem(String id, IFile file, int lineNumber, Object... args) { getProblemReporter().reportProblem(id, createProblemLocation(file, lineNumber), args); } /** * Finds an instance of problem by given id, in user profile registered for * specific file * * @param id * - problem id * @param file * - file in scope * @return problem instance */ public IProblem getProblemById(String id, IResource file) { IProblem problem = CheckersRegistry.getInstance().getResourceProfile(file).findProblem(id); if (problem == null) throw new IllegalArgumentException("Id is not registered"); //$NON-NLS-1$ return problem; } /** * @param id - main problem id * @param file - checked resource * @return - list of problems matching with this id, including duplicates * @since 2.0 */ public List<IProblem> getProblemsByMainId(String id, IResource file) { ArrayList<IProblem> list = new ArrayList<IProblem>(); IProblemProfile resourceProfile = CheckersRegistry.getInstance().getResourceProfile(file); IProblem[] problems = resourceProfile.getProblems(); for (int i = 0; i < problems.length; i++) { IProblem p = problems[i]; if (p.getId().equals(id)) { list.add(p); } else if (p.getId().startsWith(id + CheckersRegistry.CLONE_SUFFIX)) { list.add(p); } } return list; } /** * Reports a simple problem for given file and line, error message comes * from problem definition * * @param id * - problem id * @param file * - file * @param lineNumber * - line */ public void reportProblem(String id, IFile file, int lineNumber) { getProblemReporter().reportProblem(id, createProblemLocation(file, lineNumber), new Object[] {}); } /** * @return problem reporter for given checker * @since 2.0 */ public IProblemReporter getProblemReporter() { return problemReporter; } /** * Convenience method to return codan runtime * * @return */ protected CodanRuntime getRuntime() { return CodanRuntime.getInstance(); } /** * Convenience method to create and return instance of IProblemLocation * * @param file * - file where problem is found * @param line * - line number 1-relative * @return instance of IProblemLocation */ protected IProblemLocation createProblemLocation(IFile file, int line) { return getRuntime().getProblemLocationFactory().createProblemLocation(file, line); } /** * Convenience method to create and return instance of IProblemLocation * * @param file * - file where problem is found * @param startChar * - start char of the problem in the file, is zero-relative * @param endChar * - end char of the problem in the file, is zero-relative and * exclusive. * @return instance of IProblemLocation */ protected IProblemLocation createProblemLocation(IFile file, int startChar, int endChar) { return getRuntime().getProblemLocationFactory().createProblemLocation(file, startChar, endChar); } /** * Defines if checker should be run as user type in editor. Override this * method is checker is too heavy for that (runs too long) */ public boolean runInEditor() { return this instanceof IRunnableInEditorChecker; } /** * report a problem * * @param problemId - id of a problem * @param loc - problem location * @param args - extra problem arguments */ public void reportProblem(String problemId, IProblemLocation loc, Object... args) { getProblemReporter().reportProblem(problemId, loc, args); } /** * Returns the invocation context. * * @return checker invocation context * * @since 2.0 */ protected ICheckerInvocationContext getContext() { return context; } /** * @since 2.0 */ protected void setContext(ICheckerInvocationContext context) { this.context = context; } /** * @since 2.0 */ public void before(IResource resource) { IProblemReporter problemReporter = CodanRuntime.getInstance().getProblemReporter(); this.problemReporter = problemReporter; if (problemReporter instanceof IProblemReporterSessionPersistent) { // create session problem reporter this.problemReporter = ((IProblemReporterSessionPersistent) problemReporter).createReporter(resource, this); ((IProblemReporterSessionPersistent) this.problemReporter).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, this); } } /** * @since 2.0 */ public void after(IResource resource) { if (problemReporter instanceof IProblemReporterSessionPersistent) { // Delete general markers ((IProblemReporterSessionPersistent) problemReporter).done(); } problemReporter = null; } /** * @param resource the resource to process. * @return true if framework should traverse children of the resource and * run this checkers on them again. * @throws OperationCanceledException if the checker was interrupted. * @since 2.0 */ public abstract boolean processResource(IResource resource) throws OperationCanceledException; /** * @see IChecker#processResource(IResource, ICheckerInvocationContext) * @since 2.0 */ public synchronized boolean processResource(IResource resource, ICheckerInvocationContext context) throws OperationCanceledException { this.setContext(context); try { return processResource(resource); } finally { this.setContext(null); } } }