1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-05 08:46:02 +02:00

started adding support for multiple instance problems

This commit is contained in:
Alena Laskavaia 2011-03-20 01:53:23 +00:00
parent 2122fc3c99
commit 527ee4ff5a
13 changed files with 265 additions and 90 deletions

View file

@ -84,6 +84,7 @@
description="%problem.description.NamingConventionFunction"
id="org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker"
messagePattern="%problem.messagePattern.NamingConventionFunction"
multiple="true"
name="%problem.name.NamingConventionFunction">
</problem>
</checker>

View file

@ -22,6 +22,7 @@ public class CheckersMessages extends NLS {
public static String CaseBreakChecker_LastCaseDescription;
public static String CatchByReference_ReportForUnknownType;
public static String NamingConventionFunctionChecker_LabelNamePattern;
public static String NamingConventionFunctionChecker_ParameterMethods;
public static String ReturnChecker_Param0;
public static String GenericParameter_ParameterExceptions;
public static String GenericParameter_ParameterExceptionsItem;

View file

@ -10,6 +10,8 @@
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.cdt.codan.checkers.CodanCheckersActivator;
@ -36,7 +38,7 @@ public class NamingConventionFunctionChecker extends AbstractIndexAstChecker imp
public static final String PARAM_EXCEPT_ARG_LIST = "exceptions"; //$NON-NLS-1$
public void processAst(IASTTranslationUnit ast) {
final IProblem pt = getProblemById(ER_ID, getFile());
final List<IProblem> pts = getProblemsByMainId(ER_ID, getFile());
try {
ast.accept(new ASTVisitor() {
{
@ -45,33 +47,55 @@ public class NamingConventionFunctionChecker extends AbstractIndexAstChecker imp
public int visit(IASTDeclaration element) {
if (element instanceof IASTFunctionDefinition) {
String parameter = (String) getPreference(pt, PARAM_KEY);
Pattern pattern = Pattern.compile(parameter);
IASTName astName = ((IASTFunctionDefinition) element).getDeclarator().getName();
String name = astName.toString();
if (astName instanceof ICPPASTQualifiedName) {
if (!shouldReportCppMethods())
return PROCESS_SKIP;
ICPPASTQualifiedName cppAstName = (ICPPASTQualifiedName) astName;
if (cppAstName.isConversionOrOperator())
return PROCESS_SKIP;
name = cppAstName.getLastName().toString();
if (name.startsWith("~")) // destructor //$NON-NLS-1$
return PROCESS_SKIP;
IASTName[] names = cppAstName.getNames();
if (names.length >= 2) {
if (names[names.length - 1].toString().equals(names[names.length - 2].toString())) {
// constructor
String name = getSearchibleName(astName);
if (name != null) {
for (Iterator<IProblem> iterator = pts.iterator(); iterator.hasNext();) {
IProblem pt = iterator.next();
if (!shouldReport(astName, pt))
return PROCESS_SKIP;
String parameter = (String) getPreference(pt, PARAM_KEY);
Pattern pattern = Pattern.compile(parameter);
if (!pattern.matcher(name).find() && !isFilteredArg(name, pt)) {
reportProblem(pt, astName, name, parameter);
}
}
}
if (!pattern.matcher(name).find() && !isFilteredArg(name)) {
reportProblem(ER_ID, astName, name, parameter);
}
}
return PROCESS_SKIP;
}
public boolean shouldReport(IASTName astName, IProblem pt) {
if (astName instanceof ICPPASTQualifiedName) {
return shouldReportCppMethods(pt);
}
return true;
}
/**
* @param astName
* @return
*/
public String getSearchibleName(IASTName astName) {
String name = astName.toString();
if (astName instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName cppAstName = (ICPPASTQualifiedName) astName;
if (cppAstName.isConversionOrOperator())
return null;
name = cppAstName.getLastName().toString();
if (name.startsWith("~")) // destructor //$NON-NLS-1$
return null;
IASTName[] names = cppAstName.getNames();
if (names.length >= 2) {
if (names[names.length - 1].toString().equals(names[names.length - 2].toString())) {
// constructor
return null;
}
}
}
return name;
}
});
} catch (Exception e) {
CodanCheckersActivator.log(e);
@ -88,17 +112,17 @@ public class NamingConventionFunctionChecker extends AbstractIndexAstChecker imp
public void initPreferences(IProblemWorkingCopy problem) {
super.initPreferences(problem);
addPreference(problem, PARAM_KEY, CheckersMessages.NamingConventionFunctionChecker_LabelNamePattern, "^[a-z]"); //$NON-NLS-1$
addPreference(problem, PARAM_METHODS, "Also check C++ method names", Boolean.TRUE);
addPreference(problem, PARAM_METHODS, CheckersMessages.NamingConventionFunctionChecker_ParameterMethods, Boolean.TRUE);
addListPreference(problem, PARAM_EXCEPT_ARG_LIST, CheckersMessages.GenericParameter_ParameterExceptions,
CheckersMessages.GenericParameter_ParameterExceptionsItem);
}
public boolean shouldReportCppMethods() {
return (Boolean) getPreference(getProblemById(ER_ID, getFile()), PARAM_METHODS);
public boolean shouldReportCppMethods(IProblem pt) {
return (Boolean) getPreference(pt, PARAM_METHODS);
}
public boolean isFilteredArg(String arg) {
return isFilteredArg(arg, getProblemById(ER_ID, getFile()), PARAM_EXCEPT_ARG_LIST);
public boolean isFilteredArg(String arg, IProblem pt) {
return isFilteredArg(arg, pt, PARAM_EXCEPT_ARG_LIST);
}
@Override

View file

@ -13,6 +13,7 @@ CaseBreakChecker_EmptyCaseDescription=Check also empty case statement (except if
CaseBreakChecker_LastCaseDescription=Check also the last case statement
CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved
NamingConventionFunctionChecker_LabelNamePattern=Name Pattern
NamingConventionFunctionChecker_ParameterMethods=Also check C++ method names
ReturnChecker_Param0=Also check functions with implicit return value
GenericParameter_ParameterExceptions=Exceptions (value of the problem argument)
GenericParameter_ParameterExceptionsItem=Value of the argument

View file

@ -13,6 +13,7 @@ package org.eclipse.cdt.codan.core.cxx.model;
import org.eclipse.cdt.codan.core.CodanCorePlugin;
import org.eclipse.cdt.codan.core.cxx.Activator;
import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemLocation;
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
@ -81,8 +82,22 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
return true;
}
@SuppressWarnings("restriction")
public void reportProblem(String id, IASTNode astNode, Object... args) {
IProblemLocation loc = getProblemLocation(astNode);
if (loc!=null) reportProblem(id, loc, args);
}
public void reportProblem(IProblem problem, IASTNode astNode, Object... args) {
IProblemLocation loc = getProblemLocation(astNode);
if (loc!=null) reportProblem(problem, loc, args);
}
/**
* @param astNode
* @return
*/
@SuppressWarnings("restriction")
protected IProblemLocation getProblemLocation(IASTNode astNode) {
IASTFileLocation astLocation = astNode.getFileLocation();
IPath location = new Path(astLocation.getFileName());
IFile astFile = ResourceLookup.selectFileForLocation(location, getProject());
@ -91,7 +106,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
}
if (astFile == null) {
Activator.log("Cannot resolve location: " + location); //$NON-NLS-1$
return;
return null;
}
IProblemLocation loc;
int line = astLocation.getStartingLineNumber();
@ -100,7 +115,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
astLocation.getNodeOffset() + astLocation.getNodeLength(), line);
else
loc = getRuntime().getProblemLocationFactory().createProblemLocation(astFile, line);
reportProblem(id, loc, args);
return loc;
}
@Override

View file

@ -188,6 +188,13 @@ where xxx what checker would post as an argument for the problem.
</appinfo>
</annotation>
</attribute>
<attribute name="multiple" type="boolean">
<annotation>
<documentation>
Can user duplicate this problem to have multiple instances (each instance can have diffrent scope, arguments, severity, etc.
</documentation>
</annotation>
</attribute>
</complexType>
</element>

View file

@ -10,6 +10,9 @@
*******************************************************************************/
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.CheckerInvocationContext;
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
@ -77,6 +80,27 @@ public abstract class AbstractChecker implements IChecker {
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

View file

@ -41,7 +41,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
/**
* Scope preference - special preference that all file checkers should have,
* it allows user to include/exclude files for this specific problem.
*
*
* @param problem - problem for which scope preference is need
* @return scope problem preference, null if not defined
*/
@ -50,7 +50,6 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
return scope;
}
/**
* @param problem - problem for which preference is extracted
* @return launch mode preference
@ -67,7 +66,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
* be done within processResource method not in enabledInContext.
* This test uses user "scope" preference for the all problems that this
* checker can produce.
*
*
* @param res - resource to test on
* @return true if checker should report problems, fails otherwise.
*/
@ -89,10 +88,10 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
* before printing of a problem.
* This test uses user "scope" preference for the given problem. If scope is
* not defined preference it returns true.
*
*
* @param problem - problem to test for
* @param resource - resource to test on
*
*
* @return true if problem should be report for given resource, fails
* otherwise.
*/
@ -109,9 +108,23 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
super.reportProblem(problemId, loc, args);
}
/**
* report a problem
*
* @param pr - problem (kind) instance
* @param loc - problem location
* @param args - extra problem arguments
*
* @since 2.0
*/
public void reportProblem(IProblem pr, IProblemLocation loc, Object... args) {
if (shouldProduceProblem(pr, loc.getFile().getLocation()))
super.reportProblem(pr.getId(), loc, args);
}
/**
* Add a parameter
*
*
* @param problem
* - problem that has parameter
* @param key
@ -133,7 +146,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
/**
* Add preference of type list of strings, list is empty by
* default
*
*
* @param problem
* - problem
* @param key
@ -143,7 +156,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
* @param itemLabel
* @return preference instance of of the list, can be used to add default
* values or set different element type
*
*
*/
public ListProblemPreference addListPreference(IProblemWorkingCopy problem, String key, String label, String itemLabel) {
MapProblemPreference map = getTopLevelPreference(problem);
@ -155,7 +168,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
/**
* Add preference for the given problem with default value
*
*
* @param problem
* @param pref - preference
* @param defaultValue - default value of the preference
@ -172,7 +185,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
/**
* Convenience method for setting default preference value for checker that
* uses "map" as top level problem preference.
*
*
* @param problem - problem for which to set default value for a prefence
* @param key - preference key
* @param defaultValue - value of preference to be set
@ -189,7 +202,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
* If top level preference does not exist create a map preference with name
* "params"
* and return it.
*
*
* @param problem
* @return top level preference if it is a map
* @since 2.0
@ -208,7 +221,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
/**
* Returns value of the preference for the key in the top level
* preference map for the given problem
*
*
* @param problem - problem for which to get the preference
* @param key - preference key
* @return value of the preference

View file

@ -23,10 +23,8 @@ public interface IProblemElement extends Cloneable {
*
* @see {@link Object#clone}
* @return new object which is copy of this one
* @throws CloneNotSupportedException - it is declared with this exception
* but it should NOT throw it
*/
Object clone() throws CloneNotSupportedException;
Object clone();
/**
* @return problem profile where element belongs, can return null if profile

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* 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;
/**
* Additional interface to the problem kind to quiry either it supports multiple
* instances or not
*
* @since 2.0
*/
public interface IProblemMultiple {
/**
*
* @return true if problem can be replicated by the user, i.e. multiple is
* true in the extension
*/
public boolean isMultiple();
/**
* @return true if this is original problem, false if it replica
*/
public boolean isOriginal();
}

View file

@ -51,6 +51,7 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
private static final String PROBLEM_ELEMENT = "problem"; //$NON-NLS-1$
private static final String CATEGORY_ELEMENT = "category"; //$NON-NLS-1$
private static final Object DEFAULT = "DEFAULT"; //$NON-NLS-1$
public static final String CLONE_SUFFIX = ".COPY"; //$NON-NLS-1$
private Collection<IChecker> checkers = new ArrayList<IChecker>();
private static CheckersRegistry instance;
private static boolean initialized = false;
@ -190,6 +191,7 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
String patt = getAtt(configurationElement, "messagePattern", false); //$NON-NLS-1$
String desc = getAtt(configurationElement, "description", false); //$NON-NLS-1$
String markerType = getAtt(configurationElement, "markerType", false); //$NON-NLS-1$
String smultiple = getAtt(configurationElement, "multiple", false); //$NON-NLS-1$
if (enab != null) {
p.setEnabled(Boolean.valueOf(enab));
}
@ -205,6 +207,9 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
p.setMarkerType(markerType);
}
p.setDescription(desc);
if (smultiple != null) {
p.setMultiple(Boolean.valueOf(smultiple));
}
addProblem(p, category);
return p;
}
@ -329,15 +334,11 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
public IProblemProfile getWorkspaceProfile() {
IProblemProfile wp = profiles.get(ResourcesPlugin.getWorkspace());
if (wp == null) {
try {
wp = (IProblemProfile) getDefaultProfile().clone();
((ProblemProfile) wp).setResource(ResourcesPlugin.getWorkspace());
// load default values
CodanPreferencesLoader loader = new CodanPreferencesLoader(wp);
loader.load(CodanPreferencesLoader.getWorkspaceNode());
} catch (CloneNotSupportedException e) {
wp = getDefaultProfile();
}
wp = (IProblemProfile) getDefaultProfile().clone();
((ProblemProfile) wp).setResource(ResourcesPlugin.getWorkspace());
// load default values
CodanPreferencesLoader loader = new CodanPreferencesLoader(wp);
loader.load(CodanPreferencesLoader.getWorkspaceNode());
profiles.put(ResourcesPlugin.getWorkspace(), wp);
}
return wp;
@ -363,20 +364,16 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
IProblemProfile prof = profiles.get(element);
if (prof == null) {
if (element instanceof IProject) {
try {
prof = (IProblemProfile) getWorkspaceProfile().clone();
((ProblemProfile) prof).setResource(element);
// load default values
CodanPreferencesLoader loader = new CodanPreferencesLoader(prof);
Preferences projectNode = CodanPreferencesLoader.getProjectNode((IProject) element);
boolean useWorkspace = projectNode.getBoolean(PreferenceConstants.P_USE_PARENT, false);
if (!useWorkspace) {
loader.load(projectNode);
}
profiles.put(element, prof);
} catch (CloneNotSupportedException e) {
// can't
prof = (IProblemProfile) getWorkspaceProfile().clone();
((ProblemProfile) prof).setResource(element);
// load default values
CodanPreferencesLoader loader = new CodanPreferencesLoader(prof);
Preferences projectNode = CodanPreferencesLoader.getProjectNode((IProject) element);
boolean useWorkspace = projectNode.getBoolean(PreferenceConstants.P_USE_PARENT, false);
if (!useWorkspace) {
loader.load(projectNode);
}
profiles.put(element, prof);
} else if (element.getParent() != null) {
prof = getResourceProfile(element.getParent());
} else {
@ -394,13 +391,8 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
* getResourceProfileWorkingCopy(org.eclipse.core.resources.IResource)
*/
public IProblemProfile getResourceProfileWorkingCopy(IResource element) {
try {
IProblemProfile prof = (IProblemProfile) getResourceProfile(element).clone();
return prof;
} catch (CloneNotSupportedException e) {
// can't
return null;
}
IProblemProfile prof = (IProblemProfile) getResourceProfile(element).clone();
return prof;
}
/**
@ -463,4 +455,43 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
public int getCheckersSize() {
return checkers.size();
}
/**
* Create a replicated problem - it has same check and same initial values
* as original but user can modify it further
*
* @param problem
* @param profile
*/
public void replicateProblem(IProblem problem, IProblemProfile profile) {
CodanProblem x = (CodanProblem) problem.clone();
x.setId(getNextCloneId(problem, profile));
((ProblemProfile) profile).addProblem(x, problem.getParentCategory());
}
/**
* @param problem
* @param profile
* @return
*/
private String getNextCloneId(IProblem problem, IProblemProfile profile) {
IProblem[] problems = profile.getProblems();
String prefix = problem.getId() + CLONE_SUFFIX;
int max = 0;
for (int i = 0; i < problems.length; i++) {
IProblem x = problems[i];
if (x.getId().startsWith(prefix)) {
int num = 0;
try {
num = Integer.parseInt(x.getId().substring(prefix.length()));
} catch (Exception e) {
// well...
}
if (max < num)
max = num;
}
}
max++;
return prefix + max;
}
}

View file

@ -11,15 +11,17 @@
package org.eclipse.cdt.codan.internal.core.model;
import org.eclipse.cdt.codan.core.model.CodanSeverity;
import org.eclipse.cdt.codan.core.model.IProblemMultiple;
import org.eclipse.cdt.codan.core.model.IProblemReporter;
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
import org.eclipse.cdt.codan.core.model.ProblemProfileChangeEvent;
import org.eclipse.cdt.codan.core.param.IProblemPreference;
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
/**
* A type of problems reported by Codan.
*/
public class CodanProblem extends CodanProblemElement implements IProblemWorkingCopy, Cloneable {
public class CodanProblem extends CodanProblemElement implements IProblemWorkingCopy, Cloneable, IProblemMultiple {
private String id;
private String name;
private String messagePattern;
@ -28,6 +30,11 @@ public class CodanProblem extends CodanProblemElement implements IProblemWorking
private IProblemPreference rootPreference;
private String description;
private String markerType = IProblemReporter.GENERIC_CODE_ANALYSIS_MARKER_TYPE;
private boolean multiple;
public void setMultiple(boolean multiple) {
this.multiple = multiple;
}
public CodanSeverity getSeverity() {
return severity;
@ -50,6 +57,14 @@ public class CodanProblem extends CodanProblemElement implements IProblemWorking
return id;
}
/**
* @param id
* @noreference This method is not intended to be referenced by clients.
*/
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return name;
@ -156,4 +171,22 @@ public class CodanProblem extends CodanProblemElement implements IProblemWorking
checkSet();
this.markerType = markerType;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.IProblemMultiple#isMultiple()
*/
public boolean isMultiple() {
return multiple;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.IProblemMultiple#isOriginal()
*/
public boolean isOriginal() {
return !id.contains(CheckersRegistry.CLONE_SUFFIX);
}
}

View file

@ -124,25 +124,21 @@ public class CodanProblemCategory extends CodanProblemElement implements IProble
*/
@Override
public Object clone() {
try {
CodanProblemCategory catClone = (CodanProblemCategory) super.clone();
catClone.list = new ArrayList<IProblemElement>();
for (Iterator<IProblemElement> iterator = this.list.iterator(); iterator.hasNext();) {
IProblemElement child = iterator.next();
IProblemElement childClone = (IProblemElement) child.clone();
if (childClone instanceof CodanProblemElement) {
CodanProblemElement cce = (CodanProblemElement) childClone;
boolean fro = cce.isFrozen();
cce.setFrozen(false);
cce.setParentCategory(catClone);
cce.setFrozen(fro);
}
catClone.list.add(childClone);
CodanProblemCategory catClone = (CodanProblemCategory) super.clone();
catClone.list = new ArrayList<IProblemElement>();
for (Iterator<IProblemElement> iterator = this.list.iterator(); iterator.hasNext();) {
IProblemElement child = iterator.next();
IProblemElement childClone = (IProblemElement) child.clone();
if (childClone instanceof CodanProblemElement) {
CodanProblemElement cce = (CodanProblemElement) childClone;
boolean fro = cce.isFrozen();
cce.setFrozen(false);
cce.setParentCategory(catClone);
cce.setFrozen(fro);
}
return catClone;
} catch (CloneNotSupportedException e) {
return this;
catClone.list.add(childClone);
}
return catClone;
}
/*