diff --git a/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF index 880142e5045..dcabf55fa1a 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.core.cxx/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.cxx;singleton:=true -Bundle-Version: 3.3.0.qualifier +Bundle-Version: 3.4.0.qualifier Bundle-Activator: org.eclipse.cdt.codan.core.cxx.Activator Require-Bundle: org.eclipse.core.runtime, org.eclipse.cdt.core, diff --git a/codan/org.eclipse.cdt.codan.core.cxx/pom.xml b/codan/org.eclipse.cdt.codan.core.cxx/pom.xml index 869b140852b..f5159870bd5 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/pom.xml +++ b/codan/org.eclipse.cdt.codan.core.cxx/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml - 3.3.0-SNAPSHOT + 3.4.0-SNAPSHOT org.eclipse.cdt.codan.core.cxx eclipse-plugin diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java index 64b5fcc8ddd..9fe1930d64d 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java @@ -11,6 +11,9 @@ *******************************************************************************/ package org.eclipse.cdt.codan.core.cxx.model; +import java.util.ArrayList; +import java.util.List; + import org.eclipse.cdt.codan.core.cxx.Activator; import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences; import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext; @@ -18,6 +21,7 @@ import org.eclipse.cdt.codan.core.model.IProblem; import org.eclipse.cdt.codan.core.model.IProblemLocation; import org.eclipse.cdt.codan.core.model.IProblemLocationFactory; import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker; +import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTImageLocation; import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; @@ -35,7 +39,8 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.OperationCanceledException; /** - * Convenience implementation of checker that works on index-based AST of a C/C++ + * Convenience implementation of checker that works on index-based AST of a + * C/C++ * program. * * Clients may extend this class. @@ -50,7 +55,6 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem return false; if (!(resource instanceof IFile)) return true; - processFile((IFile) resource); return false; } @@ -68,7 +72,6 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem context.add(modelCache); } } - try { // Run the checker only if the index is fully initialized. Otherwise it may produce // false positives. @@ -87,8 +90,11 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem } } - /* (non-Javadoc) - * @see IRunnableInEditorChecker#processModel(Object, ICheckerInvocationContext) + /* + * (non-Javadoc) + * + * @see IRunnableInEditorChecker#processModel(Object, + * ICheckerInvocationContext) */ @Override public synchronized void processModel(Object model, ICheckerInvocationContext context) { @@ -98,7 +104,6 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem // Otherwise the checker may produce false positives. if (ast.isBasedOnIncompleteIndex()) return; - setContext(context); synchronized (context) { modelCache = context.get(CxxModelsCache.class); @@ -110,7 +115,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem try { processAst(ast); } finally { - modelCache = null; + modelCache = null; setContext(null); } } @@ -133,6 +138,49 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem reportProblem(problem, loc, args); } + /** + * Checks if problem should be reported, in this case it will check line + * comments, later can add filters or what not. + * + * @param problem - problem kind + * @param loc - location + * @param args - arguments + * @since 3.4 + */ + @Override + protected boolean shouldProduceProblem(IProblem problem, IProblemLocation loc, Object... args) { + String suppressionComment = (String) getSuppressionCommentPreference(problem).getValue(); + if (suppressionComment.isEmpty()) + return true; + List lineComments = getLineCommentsForLocation(loc); + for (IASTComment astComment : lineComments) { + if (astComment.getRawSignature().contains(suppressionComment)) + return false; + } + return true; + } + + protected List getLineCommentsForLocation(IProblemLocation loc) { + ArrayList lineComments = new ArrayList<>(); + try { + IASTComment[] commentsArray = modelCache.getAST().getComments(); + for (IASTComment comm : commentsArray) { + IASTFileLocation fileLocation = comm.getFileLocation(); + if (fileLocation.getStartingLineNumber() == loc.getLineNumber()) { + //XXX check on windows portable or os? + String problemFile = loc.getFile().getLocation().toPortableString(); + String commentFile = fileLocation.getFileName(); + if (problemFile.equals(commentFile)) { + lineComments.add(comm); + } + } + } + } catch (OperationCanceledException | CoreException e) { + Activator.log(e); + } + return lineComments; + } + protected IProblemLocation getProblemLocation(IASTNode astNode) { IASTFileLocation astLocation = astNode.getFileLocation(); return getProblemLocation(astNode, astLocation); diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AssignmentInConditionCheckerTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AssignmentInConditionCheckerTest.java index 8b7be0ecb62..f3efc03bc2b 100644 --- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AssignmentInConditionCheckerTest.java +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/internal/checkers/AssignmentInConditionCheckerTest.java @@ -107,4 +107,44 @@ public class AssignmentInConditionCheckerTest extends CheckerTestCase { String arg = CodanProblemMarker.getProblemArgument(marker, 0); assertEquals("a=b", arg); //$NON-NLS-1$ } + + // main() { + // int i; + // while (i=b()) { // @suppress("Assignment in condition") + // } + // } + public void test_while2supp() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // main() { + // int i; + // while (i=b()) { /* @suppress("Assignment in condition") */ + // } + // } + public void test_while3supp() { + loadCodeAndRun(getAboveComment()); + checkNoErrors(); + } + + // #define LOOP() while (i=b() /* @suppress("Assignment in condition") */ ) { } + // main() { + // int i; + // LOOP(); + // } + public void test_whileMacroSupp() { + loadCodeAndRun(getAboveComment()); + checkErrorLine(4); // TODO: suppression does not work in macro body now + } + + // #define LOOP() while (i=b()) { } + // main() { + // int i; + // LOOP(); // err + // } + public void test_whileMacro() { + loadCodeAndRun(getAboveComment()); + checkErrorLine(4); + } } 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 871611809bb..eaf81ce1a2e 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 @@ -50,7 +50,7 @@ public abstract class AbstractChecker implements IChecker { * internationalization) */ public void reportProblem(String id, IFile file, int lineNumber, Object... args) { - getProblemReporter().reportProblem(id, createProblemLocation(file, lineNumber), args); + reportProblem(id, createProblemLocation(file, lineNumber), args); } /** @@ -103,7 +103,7 @@ public abstract class AbstractChecker implements IChecker { * - line */ public void reportProblem(String id, IFile file, int lineNumber) { - getProblemReporter().reportProblem(id, createProblemLocation(file, lineNumber), EMPTY_OBJECT_ARRAY); + reportProblem(id, createProblemLocation(file, lineNumber), EMPTY_OBJECT_ARRAY); } /** diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java index c18a124ade3..7518bb52b3e 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java @@ -22,6 +22,7 @@ import org.eclipse.cdt.codan.core.param.LaunchModeProblemPreference; import org.eclipse.cdt.codan.core.param.ListProblemPreference; import org.eclipse.cdt.codan.core.param.MapProblemPreference; import org.eclipse.cdt.codan.core.param.RootProblemPreference; +import org.eclipse.cdt.codan.core.param.SuppressionCommentProblemPreference; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; @@ -43,6 +44,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec CheckerLaunchMode.RUN_ON_DEMAND, CheckerLaunchMode.RUN_ON_FULL_BUILD, CheckerLaunchMode.RUN_ON_INC_BUILD); + getSuppressionCommentPreference(problem).setValue(SuppressionCommentProblemPreference.generateDefaultComment(problem)); } /** @@ -65,10 +67,19 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec return getTopLevelPreference(problem).getLaunchModePreference(); } + /** + * @param problem - problem for which preference is extracted + * @return suppression comment preference + * @since 4.0 + */ + public SuppressionCommentProblemPreference getSuppressionCommentPreference(IProblem problem) { + return getTopLevelPreference(problem).getSuppressionCommentPreference(); + } + /** * User can scope out some resources for this checker. Checker can use this * call to test if it should run on this resource at all or not. Test should - * be done within processResource method not in enabledInContext. + * be done within processResource method. * This test uses user "scope" preference for the all problems that this * checker can produce. * @@ -109,10 +120,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec @Override public void reportProblem(String problemId, IProblemLocation loc, Object... args) { - if (shouldProduceProblem(getProblemById(problemId, loc.getFile()), - loc.getFile().getFullPath())) { - super.reportProblem(problemId, loc, args); - } + reportProblem(getProblemById(problemId, loc.getFile()), loc, args); } /** @@ -125,10 +133,25 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec * @since 2.0 */ public void reportProblem(IProblem pr, IProblemLocation loc, Object... args) { - if (shouldProduceProblem(pr, loc.getFile().getFullPath())) + if (shouldProduceProblem(pr, loc, args)) super.reportProblem(pr.getId(), loc, args); } + /** + * Checks if problem should be reported, this implementation only checks + * suppression by scope, but subclass should override, + * to implement any other filtering, such as suppression by filter or by comment. + * Call super to check for scope suppression as well. + * + * @param problem - problem kind + * @param loc - location + * @param args - arguments + * @since 4.0 + */ + protected boolean shouldProduceProblem(IProblem problem, IProblemLocation loc, Object... args) { + return shouldProduceProblem(problem, loc.getFile().getFullPath()); + } + /** * Adds a parameter * diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.java index 4591d288546..bf8a1982f18 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.java @@ -18,6 +18,7 @@ import org.eclipse.osgi.util.NLS; */ class Messages extends NLS { public static String FileScopeProblemPreference_Label; + public static String SuppressionCommentProblemPreference_Label; static { NLS.initializeMessages(Messages.class.getName(), Messages.class); diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.properties b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.properties index 04c64faf740..c6675dda2b5 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.properties +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/Messages.properties @@ -10,3 +10,4 @@ # IBM Corporation ############################################################################### FileScopeProblemPreference_Label=Exclusion and Inclusion +SuppressionCommentProblemPreference_Label=Suppression Comment diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/RootProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/RootProblemPreference.java index 7dcf2965135..bab72b6ce74 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/RootProblemPreference.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/RootProblemPreference.java @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.cdt.codan.core.param; - /** * Common problem preference root for most of the codan problems * @@ -24,26 +23,34 @@ public class RootProblemPreference extends MapProblemPreference { public static final String KEY = PARAM; /** - * Default constructor + * Default constructor */ public RootProblemPreference() { super(KEY, ""); //$NON-NLS-1$ addChildDescriptor(new FileScopeProblemPreference()); addChildDescriptor(new LaunchModeProblemPreference()); + addChildDescriptor(new SuppressionCommentProblemPreference()); } /** * @return scope preference */ public FileScopeProblemPreference getScopePreference() { - return (FileScopeProblemPreference) getChildDescriptor( - FileScopeProblemPreference.KEY); + return (FileScopeProblemPreference) getChildDescriptor(FileScopeProblemPreference.KEY); } + /** - * @return launch mode + * @return launch mode preference */ public LaunchModeProblemPreference getLaunchModePreference() { return (LaunchModeProblemPreference) getChildDescriptor(LaunchModeProblemPreference.KEY); + } + /** + * @return suppression comment preference + * @since 4.0 + */ + public SuppressionCommentProblemPreference getSuppressionCommentPreference() { + return (SuppressionCommentProblemPreference) getChildDescriptor(SuppressionCommentProblemPreference.KEY); } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SuppressionCommentProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SuppressionCommentProblemPreference.java new file mode 100644 index 00000000000..8506b974cdd --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SuppressionCommentProblemPreference.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 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.param; + +import java.text.MessageFormat; + +import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy; + +/** + * Preference for suppressing a problem using code comments. Automatically added to all problems. + * @since 4.0 + */ +public class SuppressionCommentProblemPreference extends BasicProblemPreference implements IProblemPreference { + public static final String KEY = "suppression_comment"; //$NON-NLS-1$; + // Even if using English name it is really a keyword, so no externalizable. + public static final String KEYWORD = "@suppress(\"{0}\")"; //$NON-NLS-1$; + + public SuppressionCommentProblemPreference() { + super(KEY, Messages.SuppressionCommentProblemPreference_Label, PreferenceType.TYPE_STRING); + } + + public static String generateDefaultComment(IProblemWorkingCopy problem) { + String name = problem.getName(); + return MessageFormat.format(KEYWORD, name); + } +}