mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-06 17:26:01 +02:00
started adding support for multiple instance problems
This commit is contained in:
parent
2122fc3c99
commit
527ee4ff5a
13 changed files with 265 additions and 90 deletions
|
@ -84,6 +84,7 @@
|
||||||
description="%problem.description.NamingConventionFunction"
|
description="%problem.description.NamingConventionFunction"
|
||||||
id="org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker"
|
id="org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker"
|
||||||
messagePattern="%problem.messagePattern.NamingConventionFunction"
|
messagePattern="%problem.messagePattern.NamingConventionFunction"
|
||||||
|
multiple="true"
|
||||||
name="%problem.name.NamingConventionFunction">
|
name="%problem.name.NamingConventionFunction">
|
||||||
</problem>
|
</problem>
|
||||||
</checker>
|
</checker>
|
||||||
|
|
|
@ -22,6 +22,7 @@ public class CheckersMessages extends NLS {
|
||||||
public static String CaseBreakChecker_LastCaseDescription;
|
public static String CaseBreakChecker_LastCaseDescription;
|
||||||
public static String CatchByReference_ReportForUnknownType;
|
public static String CatchByReference_ReportForUnknownType;
|
||||||
public static String NamingConventionFunctionChecker_LabelNamePattern;
|
public static String NamingConventionFunctionChecker_LabelNamePattern;
|
||||||
|
public static String NamingConventionFunctionChecker_ParameterMethods;
|
||||||
public static String ReturnChecker_Param0;
|
public static String ReturnChecker_Param0;
|
||||||
public static String GenericParameter_ParameterExceptions;
|
public static String GenericParameter_ParameterExceptions;
|
||||||
public static String GenericParameter_ParameterExceptionsItem;
|
public static String GenericParameter_ParameterExceptionsItem;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.codan.internal.checkers;
|
package org.eclipse.cdt.codan.internal.checkers;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.checkers.CodanCheckersActivator;
|
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 static final String PARAM_EXCEPT_ARG_LIST = "exceptions"; //$NON-NLS-1$
|
||||||
|
|
||||||
public void processAst(IASTTranslationUnit ast) {
|
public void processAst(IASTTranslationUnit ast) {
|
||||||
final IProblem pt = getProblemById(ER_ID, getFile());
|
final List<IProblem> pts = getProblemsByMainId(ER_ID, getFile());
|
||||||
try {
|
try {
|
||||||
ast.accept(new ASTVisitor() {
|
ast.accept(new ASTVisitor() {
|
||||||
{
|
{
|
||||||
|
@ -45,33 +47,55 @@ public class NamingConventionFunctionChecker extends AbstractIndexAstChecker imp
|
||||||
|
|
||||||
public int visit(IASTDeclaration element) {
|
public int visit(IASTDeclaration element) {
|
||||||
if (element instanceof IASTFunctionDefinition) {
|
if (element instanceof IASTFunctionDefinition) {
|
||||||
String parameter = (String) getPreference(pt, PARAM_KEY);
|
|
||||||
Pattern pattern = Pattern.compile(parameter);
|
|
||||||
IASTName astName = ((IASTFunctionDefinition) element).getDeclarator().getName();
|
IASTName astName = ((IASTFunctionDefinition) element).getDeclarator().getName();
|
||||||
String name = astName.toString();
|
String name = getSearchibleName(astName);
|
||||||
if (astName instanceof ICPPASTQualifiedName) {
|
if (name != null) {
|
||||||
if (!shouldReportCppMethods())
|
for (Iterator<IProblem> iterator = pts.iterator(); iterator.hasNext();) {
|
||||||
return PROCESS_SKIP;
|
IProblem pt = iterator.next();
|
||||||
ICPPASTQualifiedName cppAstName = (ICPPASTQualifiedName) astName;
|
if (!shouldReport(astName, pt))
|
||||||
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
|
|
||||||
return PROCESS_SKIP;
|
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;
|
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) {
|
} catch (Exception e) {
|
||||||
CodanCheckersActivator.log(e);
|
CodanCheckersActivator.log(e);
|
||||||
|
@ -88,17 +112,17 @@ public class NamingConventionFunctionChecker extends AbstractIndexAstChecker imp
|
||||||
public void initPreferences(IProblemWorkingCopy problem) {
|
public void initPreferences(IProblemWorkingCopy problem) {
|
||||||
super.initPreferences(problem);
|
super.initPreferences(problem);
|
||||||
addPreference(problem, PARAM_KEY, CheckersMessages.NamingConventionFunctionChecker_LabelNamePattern, "^[a-z]"); //$NON-NLS-1$
|
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,
|
addListPreference(problem, PARAM_EXCEPT_ARG_LIST, CheckersMessages.GenericParameter_ParameterExceptions,
|
||||||
CheckersMessages.GenericParameter_ParameterExceptionsItem);
|
CheckersMessages.GenericParameter_ParameterExceptionsItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldReportCppMethods() {
|
public boolean shouldReportCppMethods(IProblem pt) {
|
||||||
return (Boolean) getPreference(getProblemById(ER_ID, getFile()), PARAM_METHODS);
|
return (Boolean) getPreference(pt, PARAM_METHODS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFilteredArg(String arg) {
|
public boolean isFilteredArg(String arg, IProblem pt) {
|
||||||
return isFilteredArg(arg, getProblemById(ER_ID, getFile()), PARAM_EXCEPT_ARG_LIST);
|
return isFilteredArg(arg, pt, PARAM_EXCEPT_ARG_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -13,6 +13,7 @@ CaseBreakChecker_EmptyCaseDescription=Check also empty case statement (except if
|
||||||
CaseBreakChecker_LastCaseDescription=Check also the last case statement
|
CaseBreakChecker_LastCaseDescription=Check also the last case statement
|
||||||
CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved
|
CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved
|
||||||
NamingConventionFunctionChecker_LabelNamePattern=Name Pattern
|
NamingConventionFunctionChecker_LabelNamePattern=Name Pattern
|
||||||
|
NamingConventionFunctionChecker_ParameterMethods=Also check C++ method names
|
||||||
ReturnChecker_Param0=Also check functions with implicit return value
|
ReturnChecker_Param0=Also check functions with implicit return value
|
||||||
GenericParameter_ParameterExceptions=Exceptions (value of the problem argument)
|
GenericParameter_ParameterExceptions=Exceptions (value of the problem argument)
|
||||||
GenericParameter_ParameterExceptionsItem=Value of the argument
|
GenericParameter_ParameterExceptionsItem=Value of the argument
|
||||||
|
|
|
@ -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.CodanCorePlugin;
|
||||||
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.IProblem;
|
||||||
import org.eclipse.cdt.codan.core.model.IProblemLocation;
|
import org.eclipse.cdt.codan.core.model.IProblemLocation;
|
||||||
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
|
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
|
@ -81,8 +82,22 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
|
||||||
public void reportProblem(String id, IASTNode astNode, Object... args) {
|
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();
|
IASTFileLocation astLocation = astNode.getFileLocation();
|
||||||
IPath location = new Path(astLocation.getFileName());
|
IPath location = new Path(astLocation.getFileName());
|
||||||
IFile astFile = ResourceLookup.selectFileForLocation(location, getProject());
|
IFile astFile = ResourceLookup.selectFileForLocation(location, getProject());
|
||||||
|
@ -91,7 +106,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
|
||||||
}
|
}
|
||||||
if (astFile == null) {
|
if (astFile == null) {
|
||||||
Activator.log("Cannot resolve location: " + location); //$NON-NLS-1$
|
Activator.log("Cannot resolve location: " + location); //$NON-NLS-1$
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
IProblemLocation loc;
|
IProblemLocation loc;
|
||||||
int line = astLocation.getStartingLineNumber();
|
int line = astLocation.getStartingLineNumber();
|
||||||
|
@ -100,7 +115,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
|
||||||
astLocation.getNodeOffset() + astLocation.getNodeLength(), line);
|
astLocation.getNodeOffset() + astLocation.getNodeLength(), line);
|
||||||
else
|
else
|
||||||
loc = getRuntime().getProblemLocationFactory().createProblemLocation(astFile, line);
|
loc = getRuntime().getProblemLocationFactory().createProblemLocation(astFile, line);
|
||||||
reportProblem(id, loc, args);
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -188,6 +188,13 @@ where xxx what checker would post as an argument for the problem.
|
||||||
</appinfo>
|
</appinfo>
|
||||||
</annotation>
|
</annotation>
|
||||||
</attribute>
|
</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>
|
</complexType>
|
||||||
</element>
|
</element>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.codan.core.model;
|
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.core.CodanRuntime;
|
||||||
import org.eclipse.cdt.codan.internal.core.CheckerInvocationContext;
|
import org.eclipse.cdt.codan.internal.core.CheckerInvocationContext;
|
||||||
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
|
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
|
||||||
|
@ -77,6 +80,27 @@ public abstract class AbstractChecker implements IChecker {
|
||||||
return problem;
|
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
|
* Reports a simple problem for given file and line, error message comes
|
||||||
* from problem definition
|
* from problem definition
|
||||||
|
|
|
@ -41,7 +41,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
/**
|
/**
|
||||||
* Scope preference - special preference that all file checkers should have,
|
* Scope preference - special preference that all file checkers should have,
|
||||||
* it allows user to include/exclude files for this specific problem.
|
* it allows user to include/exclude files for this specific problem.
|
||||||
*
|
*
|
||||||
* @param problem - problem for which scope preference is need
|
* @param problem - problem for which scope preference is need
|
||||||
* @return scope problem preference, null if not defined
|
* @return scope problem preference, null if not defined
|
||||||
*/
|
*/
|
||||||
|
@ -50,7 +50,6 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param problem - problem for which preference is extracted
|
* @param problem - problem for which preference is extracted
|
||||||
* @return launch mode preference
|
* @return launch mode preference
|
||||||
|
@ -67,7 +66,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
* be done within processResource method not in enabledInContext.
|
* be done within processResource method not in enabledInContext.
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* @param res - resource to test on
|
* @param res - resource to test on
|
||||||
* @return true if checker should report problems, fails otherwise.
|
* @return true if checker should report problems, fails otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -89,10 +88,10 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
* before printing of a problem.
|
* before printing of a problem.
|
||||||
* This test uses user "scope" preference for the given problem. If scope is
|
* This test uses user "scope" preference for the given problem. If scope is
|
||||||
* not defined preference it returns true.
|
* not defined preference it returns true.
|
||||||
*
|
*
|
||||||
* @param problem - problem to test for
|
* @param problem - problem to test for
|
||||||
* @param resource - resource to test on
|
* @param resource - resource to test on
|
||||||
*
|
*
|
||||||
* @return true if problem should be report for given resource, fails
|
* @return true if problem should be report for given resource, fails
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -109,9 +108,23 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
super.reportProblem(problemId, loc, args);
|
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
|
* Add a parameter
|
||||||
*
|
*
|
||||||
* @param problem
|
* @param problem
|
||||||
* - problem that has parameter
|
* - problem that has parameter
|
||||||
* @param key
|
* @param key
|
||||||
|
@ -133,7 +146,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
/**
|
/**
|
||||||
* Add preference of type list of strings, list is empty by
|
* Add preference of type list of strings, list is empty by
|
||||||
* default
|
* default
|
||||||
*
|
*
|
||||||
* @param problem
|
* @param problem
|
||||||
* - problem
|
* - problem
|
||||||
* @param key
|
* @param key
|
||||||
|
@ -143,7 +156,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
* @param itemLabel
|
* @param itemLabel
|
||||||
* @return preference instance of of the list, can be used to add default
|
* @return preference instance of of the list, can be used to add default
|
||||||
* values or set different element type
|
* values or set different element type
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public ListProblemPreference addListPreference(IProblemWorkingCopy problem, String key, String label, String itemLabel) {
|
public ListProblemPreference addListPreference(IProblemWorkingCopy problem, String key, String label, String itemLabel) {
|
||||||
MapProblemPreference map = getTopLevelPreference(problem);
|
MapProblemPreference map = getTopLevelPreference(problem);
|
||||||
|
@ -155,7 +168,7 @@ public abstract class AbstractCheckerWithProblemPreferences extends AbstractChec
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add preference for the given problem with default value
|
* Add preference for the given problem with default value
|
||||||
*
|
*
|
||||||
* @param problem
|
* @param problem
|
||||||
* @param pref - preference
|
* @param pref - preference
|
||||||
* @param defaultValue - default value of the 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
|
* Convenience method for setting default preference value for checker that
|
||||||
* uses "map" as top level problem preference.
|
* uses "map" as top level problem preference.
|
||||||
*
|
*
|
||||||
* @param problem - problem for which to set default value for a prefence
|
* @param problem - problem for which to set default value for a prefence
|
||||||
* @param key - preference key
|
* @param key - preference key
|
||||||
* @param defaultValue - value of preference to be set
|
* @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
|
* If top level preference does not exist create a map preference with name
|
||||||
* "params"
|
* "params"
|
||||||
* and return it.
|
* and return it.
|
||||||
*
|
*
|
||||||
* @param problem
|
* @param problem
|
||||||
* @return top level preference if it is a map
|
* @return top level preference if it is a map
|
||||||
* @since 2.0
|
* @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
|
* Returns value of the preference for the key in the top level
|
||||||
* preference map for the given problem
|
* preference map for the given problem
|
||||||
*
|
*
|
||||||
* @param problem - problem for which to get the preference
|
* @param problem - problem for which to get the preference
|
||||||
* @param key - preference key
|
* @param key - preference key
|
||||||
* @return value of the preference
|
* @return value of the preference
|
||||||
|
|
|
@ -23,10 +23,8 @@ public interface IProblemElement extends Cloneable {
|
||||||
*
|
*
|
||||||
* @see {@link Object#clone}
|
* @see {@link Object#clone}
|
||||||
* @return new object which is copy of this one
|
* @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
|
* @return problem profile where element belongs, can return null if profile
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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 PROBLEM_ELEMENT = "problem"; //$NON-NLS-1$
|
||||||
private static final String CATEGORY_ELEMENT = "category"; //$NON-NLS-1$
|
private static final String CATEGORY_ELEMENT = "category"; //$NON-NLS-1$
|
||||||
private static final Object DEFAULT = "DEFAULT"; //$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 Collection<IChecker> checkers = new ArrayList<IChecker>();
|
||||||
private static CheckersRegistry instance;
|
private static CheckersRegistry instance;
|
||||||
private static boolean initialized = false;
|
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 patt = getAtt(configurationElement, "messagePattern", false); //$NON-NLS-1$
|
||||||
String desc = getAtt(configurationElement, "description", false); //$NON-NLS-1$
|
String desc = getAtt(configurationElement, "description", false); //$NON-NLS-1$
|
||||||
String markerType = getAtt(configurationElement, "markerType", 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) {
|
if (enab != null) {
|
||||||
p.setEnabled(Boolean.valueOf(enab));
|
p.setEnabled(Boolean.valueOf(enab));
|
||||||
}
|
}
|
||||||
|
@ -205,6 +207,9 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
||||||
p.setMarkerType(markerType);
|
p.setMarkerType(markerType);
|
||||||
}
|
}
|
||||||
p.setDescription(desc);
|
p.setDescription(desc);
|
||||||
|
if (smultiple != null) {
|
||||||
|
p.setMultiple(Boolean.valueOf(smultiple));
|
||||||
|
}
|
||||||
addProblem(p, category);
|
addProblem(p, category);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -329,15 +334,11 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
||||||
public IProblemProfile getWorkspaceProfile() {
|
public IProblemProfile getWorkspaceProfile() {
|
||||||
IProblemProfile wp = profiles.get(ResourcesPlugin.getWorkspace());
|
IProblemProfile wp = profiles.get(ResourcesPlugin.getWorkspace());
|
||||||
if (wp == null) {
|
if (wp == null) {
|
||||||
try {
|
wp = (IProblemProfile) getDefaultProfile().clone();
|
||||||
wp = (IProblemProfile) getDefaultProfile().clone();
|
((ProblemProfile) wp).setResource(ResourcesPlugin.getWorkspace());
|
||||||
((ProblemProfile) wp).setResource(ResourcesPlugin.getWorkspace());
|
// load default values
|
||||||
// load default values
|
CodanPreferencesLoader loader = new CodanPreferencesLoader(wp);
|
||||||
CodanPreferencesLoader loader = new CodanPreferencesLoader(wp);
|
loader.load(CodanPreferencesLoader.getWorkspaceNode());
|
||||||
loader.load(CodanPreferencesLoader.getWorkspaceNode());
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
wp = getDefaultProfile();
|
|
||||||
}
|
|
||||||
profiles.put(ResourcesPlugin.getWorkspace(), wp);
|
profiles.put(ResourcesPlugin.getWorkspace(), wp);
|
||||||
}
|
}
|
||||||
return wp;
|
return wp;
|
||||||
|
@ -363,20 +364,16 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
||||||
IProblemProfile prof = profiles.get(element);
|
IProblemProfile prof = profiles.get(element);
|
||||||
if (prof == null) {
|
if (prof == null) {
|
||||||
if (element instanceof IProject) {
|
if (element instanceof IProject) {
|
||||||
try {
|
prof = (IProblemProfile) getWorkspaceProfile().clone();
|
||||||
prof = (IProblemProfile) getWorkspaceProfile().clone();
|
((ProblemProfile) prof).setResource(element);
|
||||||
((ProblemProfile) prof).setResource(element);
|
// load default values
|
||||||
// load default values
|
CodanPreferencesLoader loader = new CodanPreferencesLoader(prof);
|
||||||
CodanPreferencesLoader loader = new CodanPreferencesLoader(prof);
|
Preferences projectNode = CodanPreferencesLoader.getProjectNode((IProject) element);
|
||||||
Preferences projectNode = CodanPreferencesLoader.getProjectNode((IProject) element);
|
boolean useWorkspace = projectNode.getBoolean(PreferenceConstants.P_USE_PARENT, false);
|
||||||
boolean useWorkspace = projectNode.getBoolean(PreferenceConstants.P_USE_PARENT, false);
|
if (!useWorkspace) {
|
||||||
if (!useWorkspace) {
|
loader.load(projectNode);
|
||||||
loader.load(projectNode);
|
|
||||||
}
|
|
||||||
profiles.put(element, prof);
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
// can't
|
|
||||||
}
|
}
|
||||||
|
profiles.put(element, prof);
|
||||||
} else if (element.getParent() != null) {
|
} else if (element.getParent() != null) {
|
||||||
prof = getResourceProfile(element.getParent());
|
prof = getResourceProfile(element.getParent());
|
||||||
} else {
|
} else {
|
||||||
|
@ -394,13 +391,8 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
||||||
* getResourceProfileWorkingCopy(org.eclipse.core.resources.IResource)
|
* getResourceProfileWorkingCopy(org.eclipse.core.resources.IResource)
|
||||||
*/
|
*/
|
||||||
public IProblemProfile getResourceProfileWorkingCopy(IResource element) {
|
public IProblemProfile getResourceProfileWorkingCopy(IResource element) {
|
||||||
try {
|
IProblemProfile prof = (IProblemProfile) getResourceProfile(element).clone();
|
||||||
IProblemProfile prof = (IProblemProfile) getResourceProfile(element).clone();
|
return prof;
|
||||||
return prof;
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
// can't
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -463,4 +455,43 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
||||||
public int getCheckersSize() {
|
public int getCheckersSize() {
|
||||||
return checkers.size();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,17 @@
|
||||||
package org.eclipse.cdt.codan.internal.core.model;
|
package org.eclipse.cdt.codan.internal.core.model;
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.core.model.CodanSeverity;
|
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.IProblemReporter;
|
||||||
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
||||||
import org.eclipse.cdt.codan.core.model.ProblemProfileChangeEvent;
|
import org.eclipse.cdt.codan.core.model.ProblemProfileChangeEvent;
|
||||||
import org.eclipse.cdt.codan.core.param.IProblemPreference;
|
import org.eclipse.cdt.codan.core.param.IProblemPreference;
|
||||||
|
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A type of problems reported by Codan.
|
* 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 id;
|
||||||
private String name;
|
private String name;
|
||||||
private String messagePattern;
|
private String messagePattern;
|
||||||
|
@ -28,6 +30,11 @@ public class CodanProblem extends CodanProblemElement implements IProblemWorking
|
||||||
private IProblemPreference rootPreference;
|
private IProblemPreference rootPreference;
|
||||||
private String description;
|
private String description;
|
||||||
private String markerType = IProblemReporter.GENERIC_CODE_ANALYSIS_MARKER_TYPE;
|
private String markerType = IProblemReporter.GENERIC_CODE_ANALYSIS_MARKER_TYPE;
|
||||||
|
private boolean multiple;
|
||||||
|
|
||||||
|
public void setMultiple(boolean multiple) {
|
||||||
|
this.multiple = multiple;
|
||||||
|
}
|
||||||
|
|
||||||
public CodanSeverity getSeverity() {
|
public CodanSeverity getSeverity() {
|
||||||
return severity;
|
return severity;
|
||||||
|
@ -50,6 +57,14 @@ public class CodanProblem extends CodanProblemElement implements IProblemWorking
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @noreference This method is not intended to be referenced by clients.
|
||||||
|
*/
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name;
|
return name;
|
||||||
|
@ -156,4 +171,22 @@ public class CodanProblem extends CodanProblemElement implements IProblemWorking
|
||||||
checkSet();
|
checkSet();
|
||||||
this.markerType = markerType;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,25 +124,21 @@ public class CodanProblemCategory extends CodanProblemElement implements IProble
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
try {
|
CodanProblemCategory catClone = (CodanProblemCategory) super.clone();
|
||||||
CodanProblemCategory catClone = (CodanProblemCategory) super.clone();
|
catClone.list = new ArrayList<IProblemElement>();
|
||||||
catClone.list = new ArrayList<IProblemElement>();
|
for (Iterator<IProblemElement> iterator = this.list.iterator(); iterator.hasNext();) {
|
||||||
for (Iterator<IProblemElement> iterator = this.list.iterator(); iterator.hasNext();) {
|
IProblemElement child = iterator.next();
|
||||||
IProblemElement child = iterator.next();
|
IProblemElement childClone = (IProblemElement) child.clone();
|
||||||
IProblemElement childClone = (IProblemElement) child.clone();
|
if (childClone instanceof CodanProblemElement) {
|
||||||
if (childClone instanceof CodanProblemElement) {
|
CodanProblemElement cce = (CodanProblemElement) childClone;
|
||||||
CodanProblemElement cce = (CodanProblemElement) childClone;
|
boolean fro = cce.isFrozen();
|
||||||
boolean fro = cce.isFrozen();
|
cce.setFrozen(false);
|
||||||
cce.setFrozen(false);
|
cce.setParentCategory(catClone);
|
||||||
cce.setParentCategory(catClone);
|
cce.setFrozen(fro);
|
||||||
cce.setFrozen(fro);
|
|
||||||
}
|
|
||||||
catClone.list.add(childClone);
|
|
||||||
}
|
}
|
||||||
return catClone;
|
catClone.list.add(childClone);
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
return catClone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Reference in a new issue