Record C/CPP/Posix Standard used for cppcheck in dump file / use this for misra checking (#1782)
* Add cmd parameter for choosing between C90 and C99 Misra specifies different requirements to the uniqueness of macros/enums/variables depending on what C standard that's being used. * Add standards configuration to each dump file Read standards config from misra addon to decide what rules to use. * Posix as standard setting should be deprecated. Don't include this in the xml * Rewritten to use a switch
This commit is contained in:
parent
5dd7dacfd7
commit
44670005ea
|
@ -569,6 +569,9 @@ class Configuration:
|
|||
arguments = []
|
||||
|
||||
for element in confignode:
|
||||
if element.tag == "standards":
|
||||
self.standards = Standards(element)
|
||||
|
||||
if element.tag == 'directivelist':
|
||||
for directive in element:
|
||||
self.directives.append(Directive(directive))
|
||||
|
@ -660,6 +663,21 @@ class Platform:
|
|||
self.long_long_bit = int(platformnode.get('long_long_bit'))
|
||||
self.pointer_bit = int(platformnode.get('pointer_bit'))
|
||||
|
||||
class Standards:
|
||||
"""
|
||||
Standards class
|
||||
This class contains versions of standards that were used for the cppcheck
|
||||
|
||||
Attributes:
|
||||
c C Standard used
|
||||
cpp C++ Standard used
|
||||
posix If Posix was used
|
||||
"""
|
||||
|
||||
def __init__(self, standardsnode):
|
||||
self.c = standardsnode.find("c").get("version")
|
||||
self.cpp = standardsnode.find("cpp").get("version")
|
||||
self.posix = standardsnode.find("posix") != None
|
||||
|
||||
class CppcheckData:
|
||||
"""
|
||||
|
|
|
@ -591,7 +591,7 @@ class Rule:
|
|||
|
||||
class MisraChecker:
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, stdversion = "c90"):
|
||||
|
||||
# Test validation rules lists
|
||||
self.verify_expected = list()
|
||||
|
@ -625,6 +625,14 @@ class MisraChecker:
|
|||
# Statistics of all violations suppressed per rule
|
||||
self.suppressionStats = dict()
|
||||
|
||||
self.stdversion = stdversion
|
||||
|
||||
def get_num_significant_naming_chars(self, cfg):
|
||||
if cfg.standards and cfg.standards.c == "c99":
|
||||
return 63
|
||||
else:
|
||||
return 31
|
||||
|
||||
def misra_3_1(self, rawTokens):
|
||||
for token in rawTokens:
|
||||
if token.str.startswith('/*') or token.str.startswith('//'):
|
||||
|
@ -733,6 +741,7 @@ class MisraChecker:
|
|||
|
||||
|
||||
def misra_5_3(self, data):
|
||||
num_sign_chars = self.get_num_significant_naming_chars(data)
|
||||
enum = []
|
||||
scopeVars = {}
|
||||
for var in data.variables:
|
||||
|
@ -759,7 +768,7 @@ class MisraChecker:
|
|||
outerScope = outerScope.nestedIn
|
||||
continue
|
||||
for outerVar in scopeVars[outerScope]:
|
||||
if innerVar.nameToken.str[:31] == outerVar.nameToken.str[:31]:
|
||||
if innerVar.nameToken.str[:num_sign_chars] == outerVar.nameToken.str[:num_sign_chars]:
|
||||
if outerVar.isArgument and outerScope.type == "Global" and not innerVar.isArgument:
|
||||
continue
|
||||
if int(innerVar.nameToken.linenr) > int(outerVar.nameToken.linenr):
|
||||
|
@ -768,7 +777,7 @@ class MisraChecker:
|
|||
self.reportError(outerVar.nameToken, 5, 3)
|
||||
outerScope = outerScope.nestedIn
|
||||
for scope in data.scopes:
|
||||
if scope.className and innerVar.nameToken.str[:31] == scope.className[:31]:
|
||||
if scope.className and innerVar.nameToken.str[:num_sign_chars] == scope.className[:num_sign_chars]:
|
||||
if int(innerVar.nameToken.linenr) > int(scope.bodyStart.linenr):
|
||||
self.reportError(innerVar.nameToken, 5, 3)
|
||||
else:
|
||||
|
@ -776,18 +785,19 @@ class MisraChecker:
|
|||
|
||||
for e in enum:
|
||||
for scope in data.scopes:
|
||||
if scope.className and innerVar.nameToken.str[:31] == e[:31]:
|
||||
if scope.className and innerVar.nameToken.str[:num_sign_chars] == e[:num_sign_chars]:
|
||||
if int(innerVar.nameToken.linenr) > int(innerScope.bodyStart.linenr):
|
||||
self.reportError(innerVar.nameToken, 5, 3)
|
||||
else:
|
||||
self.reportError(innerScope.bodyStart, 5, 3)
|
||||
for e in enum:
|
||||
for scope in data.scopes:
|
||||
if scope.className and scope.className[:31] == e[:31]:
|
||||
if scope.className and scope.className[:num_sign_chars] == e[:num_sign_chars]:
|
||||
self.reportError(scope.bodyStart, 5, 3)
|
||||
|
||||
|
||||
def misra_5_4(self, data):
|
||||
num_sign_chars = self.get_num_significant_naming_chars(data)
|
||||
macro = {}
|
||||
compile_name = re.compile(r'#define ([a-zA-Z0-9_]+)')
|
||||
compile_param = re.compile(r'#define ([a-zA-Z0-9_]+)[(]([a-zA-Z0-9_, ]+)[)]')
|
||||
|
@ -807,18 +817,18 @@ class MisraChecker:
|
|||
if len(macro[mvar]["params"]) > 0:
|
||||
for i, macroparam1 in enumerate(macro[mvar]["params"]):
|
||||
for j, macroparam2 in enumerate(macro[mvar]["params"]):
|
||||
if j > i and macroparam1[:31] == macroparam2[:31]:
|
||||
if j > i and macroparam1[:num_sign_chars] == macroparam2[:num_sign_chars]:
|
||||
self.reportError(mvar, 5, 4)
|
||||
|
||||
for x, m_var1 in enumerate(macro):
|
||||
for y, m_var2 in enumerate(macro):
|
||||
if x < y and macro[m_var1]["name"][:31] == macro[m_var2]["name"][:31]:
|
||||
if x < y and macro[m_var1]["name"][:num_sign_chars] == macro[m_var2]["name"][:num_sign_chars]:
|
||||
if m_var1.linenr > m_var2.linenr:
|
||||
self.reportError(m_var1, 5, 4)
|
||||
else:
|
||||
self.reportError(m_var2, 5, 4)
|
||||
for param in macro[m_var2]["params"]:
|
||||
if macro[m_var1]["name"][:31] == param[:31]:
|
||||
if macro[m_var1]["name"][:num_sign_chars] == param[:num_sign_chars]:
|
||||
if m_var1.linenr > m_var2.linenr:
|
||||
self.reportError(m_var1, 5, 4)
|
||||
else:
|
||||
|
@ -826,6 +836,7 @@ class MisraChecker:
|
|||
|
||||
|
||||
def misra_5_5(self, data):
|
||||
num_sign_chars = self.get_num_significant_naming_chars(data)
|
||||
macroNames = []
|
||||
compiled = re.compile(r'#define ([A-Za-z0-9_]+)')
|
||||
for dir in data.directives:
|
||||
|
@ -835,11 +846,11 @@ class MisraChecker:
|
|||
for var in data.variables:
|
||||
for macro in macroNames:
|
||||
if var.nameToken is not None:
|
||||
if var.nameToken.str[:31] == macro[:31]:
|
||||
if var.nameToken.str[:num_sign_chars] == macro[:num_sign_chars]:
|
||||
self.reportError(var.nameToken, 5, 5)
|
||||
for scope in data.scopes:
|
||||
for macro in macroNames:
|
||||
if scope.className and scope.className[:31] == macro[:31]:
|
||||
if scope.className and scope.className[:num_sign_chars] == macro[:num_sign_chars]:
|
||||
self.reportError(scope.bodyStart, 5, 5)
|
||||
|
||||
|
||||
|
|
|
@ -473,6 +473,10 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
// dump xml if --dump
|
||||
if ((mSettings.dump || !mSettings.addons.empty()) && fdump.is_open()) {
|
||||
fdump << "<dump cfg=\"" << ErrorLogger::toxml(mCurrentConfig) << "\">" << std::endl;
|
||||
fdump << " <standards>" << std::endl;
|
||||
fdump << " <c version=\"" << mSettings.standards.getC() << "\"/>" << std::endl;
|
||||
fdump << " <cpp version=\"" << mSettings.standards.getCPP() << "\"/>" << std::endl;
|
||||
fdump << " </standards>" << std::endl;
|
||||
preprocessor.dump(fdump);
|
||||
mTokenizer.dump(fdump);
|
||||
fdump << "</dump>" << std::endl;
|
||||
|
|
|
@ -56,6 +56,17 @@ struct Standards {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
const std::string getC(void) const {
|
||||
switch (c) {
|
||||
case C89:
|
||||
return "c89";
|
||||
case C99:
|
||||
return "c99";
|
||||
case C11:
|
||||
return "c11";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
bool setCPP(const std::string& str) {
|
||||
if (str == "c++03" || str == "C++03") {
|
||||
cpp = CPP03;
|
||||
|
@ -79,6 +90,21 @@ struct Standards {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
const std::string getCPP(void) const {
|
||||
switch (cpp) {
|
||||
case CPP03:
|
||||
return "c++03";
|
||||
case CPP11:
|
||||
return "c++11";
|
||||
case CPP14:
|
||||
return "c++14";
|
||||
case CPP17:
|
||||
return "c++17";
|
||||
case CPP20:
|
||||
return "c++20";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
Loading…
Reference in New Issue