Fix multiple config dumps
With multiple configurations, option --dump only dumps the last configuration. Fix it to dump every configuration. Also update all Python addons so that they can handle multiple-configuration dumps. Additionally run autopep8 on addons/*.py. The results of 'make test' before and after applying this commit are identical.
This commit is contained in:
parent
dbc7e2f338
commit
e7fdb1c825
|
@ -12,8 +12,11 @@ import cppcheckdata
|
|||
import sys
|
||||
import re
|
||||
|
||||
|
||||
def reportError(token, severity, msg):
|
||||
sys.stderr.write('[' + token.file + ':' + str(token.linenr) + '] (' + severity + ') cert.py: ' + msg + '\n')
|
||||
sys.stderr.write(
|
||||
'[' + token.file + ':' + str(token.linenr) + '] (' + severity + ') cert.py: ' + msg + '\n')
|
||||
|
||||
|
||||
def isUnpackedStruct(var):
|
||||
decl = var.typeStartToken
|
||||
|
@ -26,17 +29,19 @@ def isUnpackedStruct(var):
|
|||
linenr = linenr - 1
|
||||
if linenr == 0:
|
||||
return True
|
||||
if re.match(r'#pragma\s+pack\s*\(',line):
|
||||
if re.match(r'#pragma\s+pack\s*\(', line):
|
||||
return False
|
||||
break
|
||||
decl = decl.next
|
||||
return False
|
||||
|
||||
|
||||
def isLocalUnpackedStruct(arg):
|
||||
if arg and arg.str == '&' and not arg.astOperand2:
|
||||
arg = arg.astOperand1
|
||||
return arg and arg.variable and (arg.variable.isLocal or arg.variable.isArgument) and isUnpackedStruct(arg.variable)
|
||||
|
||||
|
||||
def isBitwiseOp(token):
|
||||
return token and (token.str in ['&', '|', '^'])
|
||||
|
||||
|
@ -60,7 +65,8 @@ def exp42(data):
|
|||
arg2 = token.astOperand2.astOperand1.astOperand2
|
||||
|
||||
if token.astOperand1.str == 'memcmp' and (isLocalUnpackedStruct(arg1) or isLocalUnpackedStruct(arg2)):
|
||||
reportError(token, 'style', 'EXP42-C Comparison of struct padding data (fix either by packing the struct using \'#pragma pack\' or by rewriting the comparison)')
|
||||
reportError(
|
||||
token, 'style', 'EXP42-C Comparison of struct padding data (fix either by packing the struct using \'#pragma pack\' or by rewriting the comparison)')
|
||||
|
||||
# EXP46-C
|
||||
# Do not use a bitwise operator with a Boolean-like operand
|
||||
|
@ -70,10 +76,14 @@ def exp42(data):
|
|||
def exp46(data):
|
||||
for token in data.tokenlist:
|
||||
if isBitwiseOp(token) and (isComparisonOp(token.astOperand1) or isComparisonOp(token.astOperand2)):
|
||||
reportError(token, 'style', 'EXP46-C Bitwise operator is used with a Boolean-like operand')
|
||||
reportError(
|
||||
token, 'style', 'EXP46-C Bitwise operator is used with a Boolean-like operand')
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
print('Checking ' + arg + '...')
|
||||
data = cppcheckdata.parsedump(arg)
|
||||
exp42(data)
|
||||
exp46(data)
|
||||
for cfg in data.configurations:
|
||||
if len(data.configurations) > 1:
|
||||
print('Checking ' + arg + ', config "' + cfg.name + '"...')
|
||||
exp42(cfg)
|
||||
exp46(cfg)
|
||||
|
|
|
@ -15,13 +15,15 @@ import xml.etree.ElementTree as ET
|
|||
#
|
||||
# To iterate through all tokens use such code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# code = ''
|
||||
# for token in data.tokenlist:
|
||||
# code = code + token.str + ' '
|
||||
# print(code)
|
||||
# @endcode
|
||||
#
|
||||
|
||||
|
||||
class Token:
|
||||
Id = None
|
||||
## Token string
|
||||
|
@ -69,7 +71,7 @@ class Token:
|
|||
#
|
||||
# Example code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# code = ''
|
||||
# for token in data.tokenlist:
|
||||
# code = code + token.str
|
||||
|
@ -91,7 +93,7 @@ class Token:
|
|||
#
|
||||
# Example code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# code = ''
|
||||
# for token in data.tokenlist:
|
||||
# code = code + token.str
|
||||
|
@ -119,7 +121,7 @@ class Token:
|
|||
#
|
||||
# Example code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# for token in data.tokenlist:
|
||||
#
|
||||
# # is this a addition?
|
||||
|
@ -127,7 +129,7 @@ class Token:
|
|||
#
|
||||
# # print LHS operand
|
||||
# print(token.astOperand1.str)
|
||||
#
|
||||
#
|
||||
# @endcode
|
||||
astOperand1 = None
|
||||
astOperand2Id = None
|
||||
|
@ -135,7 +137,7 @@ class Token:
|
|||
#
|
||||
# Example code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# for token in data.tokenlist:
|
||||
#
|
||||
# # is this a division?
|
||||
|
@ -143,7 +145,7 @@ class Token:
|
|||
#
|
||||
# # print RHS operand
|
||||
# print(token.astOperand2.str)
|
||||
#
|
||||
#
|
||||
# @endcode
|
||||
astOperand2 = None
|
||||
|
||||
|
@ -226,16 +228,20 @@ class Token:
|
|||
|
||||
## Scope. Information about global scope, function scopes, class scopes, inner scopes, etc.
|
||||
# C++ class: http://cppcheck.sourceforge.net/devinfo/doxyoutput/classScope.html
|
||||
|
||||
|
||||
class Scope:
|
||||
Id = None
|
||||
classStartId = None
|
||||
|
||||
|
||||
## The { Token for this scope
|
||||
classStart = None
|
||||
classEndId = None
|
||||
## The } Token for this scope
|
||||
classEnd = None
|
||||
## Name of this scope. For a function scope, this is the function name, For a class scope, this is the class name.
|
||||
## Name of this scope.
|
||||
# For a function scope, this is the function name;
|
||||
# for a class scope, this is the class name.
|
||||
className = None
|
||||
## Type of scope: Global, Function, Class, If, While
|
||||
type = None
|
||||
|
@ -257,7 +263,10 @@ class Scope:
|
|||
self.nestedIn = IdMap[self.nestedInId]
|
||||
|
||||
## Information about a function
|
||||
# C++ class: http://cppcheck.sourceforge.net/devinfo/doxyoutput/classFunction.html
|
||||
# C++ class:
|
||||
# http://cppcheck.sourceforge.net/devinfo/doxyoutput/classFunction.html
|
||||
|
||||
|
||||
class Function:
|
||||
Id = None
|
||||
argument = None
|
||||
|
@ -281,11 +290,14 @@ class Function:
|
|||
self.tokenDef = IdMap[self.tokenDefId]
|
||||
|
||||
## Information about a variable
|
||||
# C++ class: http://cppcheck.sourceforge.net/devinfo/doxyoutput/classVariable.html
|
||||
# C++ class:
|
||||
# http://cppcheck.sourceforge.net/devinfo/doxyoutput/classVariable.html
|
||||
|
||||
|
||||
class Variable:
|
||||
Id = None
|
||||
nameTokenId = None
|
||||
# name token in variable declaration
|
||||
## name token in variable declaration
|
||||
nameToken = None
|
||||
typeStartTokenId = None
|
||||
## start token of variable declaration
|
||||
|
@ -330,17 +342,21 @@ class Variable:
|
|||
self.typeEndToken = IdMap[self.typeEndTokenId]
|
||||
|
||||
## ValueFlow class
|
||||
|
||||
|
||||
class ValueFlow:
|
||||
## ValueFlow::Value class
|
||||
# Each possible value has a ValueFlow::Value item.
|
||||
# Each ValueFlow::Value either has a intvalue or tokvalue
|
||||
# C++ class: http://cppcheck.sourceforge.net/devinfo/doxyoutput/classValueFlow_1_1Value.html
|
||||
# C++ class:
|
||||
# http://cppcheck.sourceforge.net/devinfo/doxyoutput/classValueFlow_1_1Value.html
|
||||
|
||||
class Value:
|
||||
# integer value
|
||||
# #integer value
|
||||
intvalue = None
|
||||
# token value
|
||||
## token value
|
||||
tokvalue = None
|
||||
# condition where this Value comes from
|
||||
## condition where this Value comes from
|
||||
condition = None
|
||||
|
||||
def __init__(self, element):
|
||||
|
@ -363,25 +379,14 @@ class ValueFlow:
|
|||
for value in element:
|
||||
self.values.append(ValueFlow.Value(value))
|
||||
|
||||
## Class that makes cppcheck dump data available
|
||||
#
|
||||
# To iterate through all tokens use such code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# code = ''
|
||||
# for token in data.tokenlist:
|
||||
# code = code + token.str + ' '
|
||||
# print(code)
|
||||
# @endcode
|
||||
#
|
||||
# To iterate through all scopes (functions, types, etc) use such code:
|
||||
# @code
|
||||
# data = CppcheckData.parsedump(...)
|
||||
# for scope in data.scopes:
|
||||
# print('type:' + scope.type + ' name:' + scope.className)
|
||||
# @endcode
|
||||
#
|
||||
class CppcheckData:
|
||||
## Configuration class
|
||||
# This class contains the tokens, scopes, functions, variables and
|
||||
# value flows for one configuration.
|
||||
|
||||
|
||||
class Configuration:
|
||||
## Name of the configuration, "" for default
|
||||
name = ''
|
||||
## List of Token items
|
||||
tokenlist = []
|
||||
## List of Scope items
|
||||
|
@ -393,15 +398,15 @@ class CppcheckData:
|
|||
## List of ValueFlow values
|
||||
valueflow = []
|
||||
|
||||
def __init__(self, filename):
|
||||
def __init__(self, confignode):
|
||||
self.name = confignode.get('cfg')
|
||||
self.tokenlist = []
|
||||
self.scopes = []
|
||||
self.functions = []
|
||||
self.variables = []
|
||||
self.valueflow = []
|
||||
|
||||
data = ET.parse(filename)
|
||||
for element in data.getroot():
|
||||
for element in confignode:
|
||||
if element.tag == 'tokenlist':
|
||||
for token in element:
|
||||
self.tokenlist.append(Token(token))
|
||||
|
@ -450,11 +455,60 @@ class CppcheckData:
|
|||
for variable in self.variables:
|
||||
variable.setId(IdMap)
|
||||
|
||||
## Class that makes cppcheck dump data available
|
||||
# Contains a list of Configuration instances
|
||||
#
|
||||
# To iterate through all configurations use such code:
|
||||
# @code
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# for cfg in data.configurations:
|
||||
# print('cfg: ' + cfg.name)
|
||||
# @endcode
|
||||
#
|
||||
# To iterate through all tokens in each configuration use such code:
|
||||
# @code
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# for cfg in data.configurations:
|
||||
# print('cfg: ' + cfg.name)
|
||||
# code = ''
|
||||
# for token in cfg.tokenlist:
|
||||
# code = code + token.str + ' '
|
||||
# print(' ' + code)
|
||||
# @endcode
|
||||
#
|
||||
# To iterate through all scopes (functions, types, etc) use such code:
|
||||
# @code
|
||||
# data = cppcheckdata.parsedump(...)
|
||||
# for cfg in data.configurations:
|
||||
# print('cfg: ' + cfg.name)
|
||||
# for scope in cfg.scopes:
|
||||
# print(' type:' + scope.type + ' name:' + scope.className)
|
||||
# @endcode
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
class CppcheckData:
|
||||
## List of Configurations
|
||||
configurations = []
|
||||
|
||||
def __init__(self, filename):
|
||||
self.configurations = []
|
||||
|
||||
data = ET.parse(filename)
|
||||
# root is 'dumps' node, each config has its own 'dump' subnode.
|
||||
for cfgnode in data.getroot():
|
||||
self.configurations.append(Configuration(cfgnode))
|
||||
|
||||
## parse a cppcheck dump file
|
||||
|
||||
|
||||
def parsedump(filename):
|
||||
return CppcheckData(filename)
|
||||
|
||||
## Check if type of ast node is float/double
|
||||
|
||||
|
||||
def astIsFloat(token):
|
||||
if not token:
|
||||
return False
|
||||
|
|
|
@ -12,25 +12,29 @@ for arg in sys.argv[1:]:
|
|||
print('Checking ' + arg + '...')
|
||||
data = cppcheckdata.parsedump(arg)
|
||||
|
||||
for token in data.tokenlist:
|
||||
if token.str != '(' or not token.astOperand1 or token.astOperand2:
|
||||
continue
|
||||
for cfg in data.configurations:
|
||||
if len(data.configurations) > 1:
|
||||
print('Checking ' + arg + ', config "' + cfg.name + '"...')
|
||||
for token in cfg.tokenlist:
|
||||
if token.str != '(' or not token.astOperand1 or token.astOperand2:
|
||||
continue
|
||||
|
||||
# we probably have a cast.. if there is something inside the parentheses
|
||||
# there is a cast. Otherwise this is a function call.
|
||||
typetok = token.next
|
||||
if not typetok.isName:
|
||||
continue
|
||||
# we probably have a cast.. if there is something inside the parentheses
|
||||
# there is a cast. Otherwise this is a function call.
|
||||
typetok = token.next
|
||||
if not typetok.isName:
|
||||
continue
|
||||
|
||||
# cast number => skip output
|
||||
if token.astOperand1.isNumber:
|
||||
continue
|
||||
# cast number => skip output
|
||||
if token.astOperand1.isNumber:
|
||||
continue
|
||||
|
||||
# void cast => often used to suppress compiler warnings
|
||||
if typetok.str == 'void':
|
||||
continue
|
||||
# void cast => often used to suppress compiler warnings
|
||||
if typetok.str == 'void':
|
||||
continue
|
||||
|
||||
msg = '[' + token.file + ':' + str(token.linenr) + '] (information) findcasts.py: found a cast\n'
|
||||
if not msg in messages:
|
||||
messages.append(msg)
|
||||
sys.stderr.write(msg)
|
||||
msg = '[' + token.file + ':' + str(
|
||||
token.linenr) + '] (information) findcasts.py: found a cast\n'
|
||||
if not msg in messages:
|
||||
messages.append(msg)
|
||||
sys.stderr.write(msg)
|
||||
|
|
|
@ -21,21 +21,27 @@ for arg in sys.argv[1:]:
|
|||
|
||||
|
||||
def reportError(token, severity, msg):
|
||||
sys.stderr.write('[' + token.file + ':' + str(token.linenr) + '] (' + severity + ') naming.py: ' + msg + '\n')
|
||||
sys.stderr.write(
|
||||
'[' + token.file + ':' + str(token.linenr) + '] (' + severity + ') naming.py: ' + msg + '\n')
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if not arg[-5:] == '.dump':
|
||||
continue
|
||||
print('Checking ' + arg + '...')
|
||||
data = cppcheckdata.parsedump(arg)
|
||||
if RE_VARNAME:
|
||||
for var in data.variables:
|
||||
res = re.match(RE_VARNAME, var.nameToken.str)
|
||||
if not res:
|
||||
reportError(var.typeStartToken, 'style', 'Variable ' + var.nameToken.str + ' violates naming convention')
|
||||
if RE_FUNCTIONNAME:
|
||||
for scope in data.scopes:
|
||||
if scope.type == 'Function':
|
||||
res = re.match(RE_FUNCTIONNAME, scope.className)
|
||||
for cfg in data.configurations:
|
||||
if len(data.configurations) > 1:
|
||||
print('Checking ' + arg + ', config "' + cfg.name + '"...')
|
||||
if RE_VARNAME:
|
||||
for var in cfg.variables:
|
||||
res = re.match(RE_VARNAME, var.nameToken.str)
|
||||
if not res:
|
||||
reportError(scope.classStart, 'style', 'Function ' + scope.className + ' violates naming convention')
|
||||
reportError(var.typeStartToken, 'style', 'Variable ' +
|
||||
var.nameToken.str + ' violates naming convention')
|
||||
if RE_FUNCTIONNAME:
|
||||
for scope in cfg.scopes:
|
||||
if scope.type == 'Function':
|
||||
res = re.match(RE_FUNCTIONNAME, scope.className)
|
||||
if not res:
|
||||
reportError(
|
||||
scope.classStart, 'style', 'Function ' + scope.className + ' violates naming convention')
|
||||
|
|
|
@ -9,7 +9,8 @@ import sys
|
|||
|
||||
|
||||
def reportError(token, severity, msg):
|
||||
sys.stderr.write('[' + token.file + ':' + str(token.linenr) + '] (' + severity + ') threadsafety.py: ' + msg + '\n')
|
||||
sys.stderr.write(
|
||||
'[' + token.file + ':' + str(token.linenr) + '] (' + severity + ') threadsafety.py: ' + msg + '\n')
|
||||
|
||||
|
||||
def checkstatic(data):
|
||||
|
@ -20,4 +21,7 @@ def checkstatic(data):
|
|||
for arg in sys.argv[1:]:
|
||||
print('Checking ' + arg + '...')
|
||||
data = cppcheckdata.parsedump(arg)
|
||||
checkstatic(data)
|
||||
for cfg in data.configurations:
|
||||
if len(data.configurations) > 1:
|
||||
print('Checking ' + arg + ', config "' + cfg.name + '"...')
|
||||
checkstatic(cfg)
|
||||
|
|
|
@ -143,6 +143,17 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
|||
}
|
||||
}
|
||||
|
||||
// write dump file xml prolog
|
||||
std::ofstream fdump;
|
||||
if (_settings.dump) {
|
||||
const std::string dumpfile(filename + ".dump");
|
||||
fdump.open(dumpfile.c_str());
|
||||
if (fdump.is_open()) {
|
||||
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
||||
fdump << "<dumps>" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::set<unsigned long long> checksums;
|
||||
unsigned int checkCount = 0;
|
||||
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
|
||||
|
@ -203,11 +214,9 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
|||
if (!result)
|
||||
continue;
|
||||
|
||||
// dump xml
|
||||
// dump xml if --dump
|
||||
if (_settings.dump) {
|
||||
std::ofstream fdump((filename + ".dump").c_str());
|
||||
if (fdump.is_open()) {
|
||||
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
||||
fdump << "<dump cfg=\"" << cfg << "\">" << std::endl;
|
||||
_tokenizer.dump(fdump);
|
||||
fdump << "</dump>" << std::endl;
|
||||
|
@ -265,6 +274,10 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
|
|||
}
|
||||
}
|
||||
|
||||
// dumped all configs, close root </dumps> element now
|
||||
if (_settings.dump && fdump.is_open())
|
||||
fdump << "</dumps>" << std::endl;
|
||||
|
||||
} catch (const std::runtime_error &e) {
|
||||
internalError(filename, e.what());
|
||||
} catch (const InternalError &e) {
|
||||
|
|
Loading…
Reference in New Issue