1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

Bug 383576 - Ability to ignore codan errors using line comments

Change-Id: I806e1787fb6cc3be8865cee1d397d581ae4acd8e
Signed-off-by: Alena Laskavaia <elaskavaia.cdt@gmail.com>
This commit is contained in:
Alena Laskavaia 2016-01-07 23:12:51 -05:00 committed by Elena Laskavaia
parent 12843ef1d7
commit 05daa126a0
10 changed files with 176 additions and 22 deletions

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.cdt.codan.core.cxx;singleton:=true 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 Bundle-Activator: org.eclipse.cdt.codan.core.cxx.Activator
Require-Bundle: org.eclipse.core.runtime, Require-Bundle: org.eclipse.core.runtime,
org.eclipse.cdt.core, org.eclipse.cdt.core,

View file

@ -11,7 +11,7 @@
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<version>3.3.0-SNAPSHOT</version> <version>3.4.0-SNAPSHOT</version>
<artifactId>org.eclipse.cdt.codan.core.cxx</artifactId> <artifactId>org.eclipse.cdt.codan.core.cxx</artifactId>
<packaging>eclipse-plugin</packaging> <packaging>eclipse-plugin</packaging>
</project> </project>

View file

@ -11,6 +11,9 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.codan.core.cxx.model; 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.cxx.Activator;
import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences; import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences;
import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext; 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.IProblemLocation;
import org.eclipse.cdt.codan.core.model.IProblemLocationFactory; import org.eclipse.cdt.codan.core.model.IProblemLocationFactory;
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker; 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.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation; import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
@ -35,7 +39,8 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.OperationCanceledException; 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. * program.
* *
* Clients may extend this class. * Clients may extend this class.
@ -50,7 +55,6 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
return false; return false;
if (!(resource instanceof IFile)) if (!(resource instanceof IFile))
return true; return true;
processFile((IFile) resource); processFile((IFile) resource);
return false; return false;
} }
@ -68,7 +72,6 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
context.add(modelCache); context.add(modelCache);
} }
} }
try { try {
// Run the checker only if the index is fully initialized. Otherwise it may produce // Run the checker only if the index is fully initialized. Otherwise it may produce
// false positives. // 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 @Override
public synchronized void processModel(Object model, ICheckerInvocationContext context) { 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. // Otherwise the checker may produce false positives.
if (ast.isBasedOnIncompleteIndex()) if (ast.isBasedOnIncompleteIndex())
return; return;
setContext(context); setContext(context);
synchronized (context) { synchronized (context) {
modelCache = context.get(CxxModelsCache.class); modelCache = context.get(CxxModelsCache.class);
@ -110,7 +115,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
try { try {
processAst(ast); processAst(ast);
} finally { } finally {
modelCache = null; modelCache = null;
setContext(null); setContext(null);
} }
} }
@ -133,6 +138,49 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
reportProblem(problem, loc, args); 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<IASTComment> lineComments = getLineCommentsForLocation(loc);
for (IASTComment astComment : lineComments) {
if (astComment.getRawSignature().contains(suppressionComment))
return false;
}
return true;
}
protected List<IASTComment> getLineCommentsForLocation(IProblemLocation loc) {
ArrayList<IASTComment> 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) { protected IProblemLocation getProblemLocation(IASTNode astNode) {
IASTFileLocation astLocation = astNode.getFileLocation(); IASTFileLocation astLocation = astNode.getFileLocation();
return getProblemLocation(astNode, astLocation); return getProblemLocation(astNode, astLocation);

View file

@ -107,4 +107,44 @@ public class AssignmentInConditionCheckerTest extends CheckerTestCase {
String arg = CodanProblemMarker.getProblemArgument(marker, 0); String arg = CodanProblemMarker.getProblemArgument(marker, 0);
assertEquals("a=b", arg); //$NON-NLS-1$ 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);
}
} }

View file

@ -50,7 +50,7 @@ public abstract class AbstractChecker implements IChecker {
* internationalization) * internationalization)
*/ */
public void reportProblem(String id, IFile file, int lineNumber, Object... args) { 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 * - line
*/ */
public void reportProblem(String id, IFile file, int lineNumber) { 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);
} }
/** /**

View file

@ -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.ListProblemPreference;
import org.eclipse.cdt.codan.core.param.MapProblemPreference; import org.eclipse.cdt.codan.core.param.MapProblemPreference;
import org.eclipse.cdt.codan.core.param.RootProblemPreference; 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.resources.IResource;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
@ -43,6 +44,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
CheckerLaunchMode.RUN_ON_DEMAND, CheckerLaunchMode.RUN_ON_DEMAND,
CheckerLaunchMode.RUN_ON_FULL_BUILD, CheckerLaunchMode.RUN_ON_FULL_BUILD,
CheckerLaunchMode.RUN_ON_INC_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(); 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 * 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 * 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 * This test uses user "scope" preference for the all problems that this
* checker can produce. * checker can produce.
* *
@ -109,10 +120,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
@Override @Override
public void reportProblem(String problemId, IProblemLocation loc, Object... args) { public void reportProblem(String problemId, IProblemLocation loc, Object... args) {
if (shouldProduceProblem(getProblemById(problemId, loc.getFile()), reportProblem(getProblemById(problemId, loc.getFile()), loc, args);
loc.getFile().getFullPath())) {
super.reportProblem(problemId, loc, args);
}
} }
/** /**
@ -125,10 +133,25 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
* @since 2.0 * @since 2.0
*/ */
public void reportProblem(IProblem pr, IProblemLocation loc, Object... args) { 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); 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 * Adds a parameter
* *

View file

@ -18,6 +18,7 @@ import org.eclipse.osgi.util.NLS;
*/ */
class Messages extends NLS { class Messages extends NLS {
public static String FileScopeProblemPreference_Label; public static String FileScopeProblemPreference_Label;
public static String SuppressionCommentProblemPreference_Label;
static { static {
NLS.initializeMessages(Messages.class.getName(), Messages.class); NLS.initializeMessages(Messages.class.getName(), Messages.class);

View file

@ -10,3 +10,4 @@
# IBM Corporation # IBM Corporation
############################################################################### ###############################################################################
FileScopeProblemPreference_Label=Exclusion and Inclusion FileScopeProblemPreference_Label=Exclusion and Inclusion
SuppressionCommentProblemPreference_Label=Suppression Comment

View file

@ -10,7 +10,6 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.codan.core.param; package org.eclipse.cdt.codan.core.param;
/** /**
* Common problem preference root for most of the codan problems * 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; public static final String KEY = PARAM;
/** /**
* Default constructor * Default constructor
*/ */
public RootProblemPreference() { public RootProblemPreference() {
super(KEY, ""); //$NON-NLS-1$ super(KEY, ""); //$NON-NLS-1$
addChildDescriptor(new FileScopeProblemPreference()); addChildDescriptor(new FileScopeProblemPreference());
addChildDescriptor(new LaunchModeProblemPreference()); addChildDescriptor(new LaunchModeProblemPreference());
addChildDescriptor(new SuppressionCommentProblemPreference());
} }
/** /**
* @return scope preference * @return scope preference
*/ */
public FileScopeProblemPreference getScopePreference() { public FileScopeProblemPreference getScopePreference() {
return (FileScopeProblemPreference) getChildDescriptor( return (FileScopeProblemPreference) getChildDescriptor(FileScopeProblemPreference.KEY);
FileScopeProblemPreference.KEY);
} }
/** /**
* @return launch mode * @return launch mode preference
*/ */
public LaunchModeProblemPreference getLaunchModePreference() { public LaunchModeProblemPreference getLaunchModePreference() {
return (LaunchModeProblemPreference) getChildDescriptor(LaunchModeProblemPreference.KEY); return (LaunchModeProblemPreference) getChildDescriptor(LaunchModeProblemPreference.KEY);
}
/**
* @return suppression comment preference
* @since 4.0
*/
public SuppressionCommentProblemPreference getSuppressionCommentPreference() {
return (SuppressionCommentProblemPreference) getChildDescriptor(SuppressionCommentProblemPreference.KEY);
} }
} }

View file

@ -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);
}
}