1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
#!/usr/bin/env python3
#
# Misc: Uncategorized checks that might be moved to some better addon later
#
# Example usage of this addon (scan a sourcefile main.cpp)
# cppcheck --dump main.cpp
# python misc.py main.cpp.dump
import cppcheckdata
import sys
import re
DEBUG = ('-debug' in sys.argv)
VERIFY = ('-verify' in sys.argv)
VERIFY_EXPECTED = []
VERIFY_ACTUAL = []
def reportError(token, severity, msg, id):
if id == 'debug' and not DEBUG:
return
if VERIFY:
VERIFY_ACTUAL.append(str(token.linenr) + ':' + id)
else:
cppcheckdata.reportError(token, severity, msg, 'misc', id)
def simpleMatch(token, pattern):
return cppcheckdata.simpleMatch(token, pattern)
# Get function arguments
def getArgumentsRecursive(tok, arguments):
if tok is None:
return
if tok.str == ',':
getArgumentsRecursive(tok.astOperand1, arguments)
getArgumentsRecursive(tok.astOperand2, arguments)
else:
arguments.append(tok)
def getArguments(ftok):
arguments = []
getArgumentsRecursive(ftok.astOperand2, arguments)
return arguments
def isStringLiteral(tokenString):
return tokenString.startswith('"')
# check data
def stringConcatInArrayInit(data):
# Get all string macros
stringMacros = []
for cfg in data.iterconfigurations():
for directive in cfg.directives:
res = re.match(r'#define[ ]+([A-Za-z0-9_]+)[ ]+".*', directive.str)
if res:
macroName = res.group(1)
if macroName not in stringMacros:
stringMacros.append(macroName)
# Check code
arrayInit = False
for i in range(len(data.rawTokens)):
if i < 2:
continue
tok1 = data.rawTokens[i-2].str
tok2 = data.rawTokens[i-1].str
tok3 = data.rawTokens[i-0].str
if tok3 == '}':
arrayInit = False
elif tok1 == ']' and tok2 == '=' and tok3 == '{':
arrayInit = True
elif arrayInit and (tok1 in [',', '{']):
isString2 = (isStringLiteral(tok2) or (tok2 in stringMacros))
isString3 = (isStringLiteral(tok3) or (tok3 in stringMacros))
if isString2 and isString3:
reportError(data.rawTokens[i], 'style', 'String concatenation in array initialization, missing comma?', 'stringConcatInArrayInit')
def implicitlyVirtual(data):
for cfg in data.iterconfigurations():
for function in cfg.functions:
if function.isImplicitlyVirtual is None:
continue
if not function.isImplicitlyVirtual:
continue
reportError(function.tokenDef, 'style', 'Function \'' + function.name + '\' overrides base class function but is not marked with \'virtual\' keyword.', 'implicitlyVirtual')
def ellipsisStructArg(data):
for cfg in data.iterconfigurations():
for tok in cfg.tokenlist:
if tok.str != '(':
continue
if tok.astOperand1 is None or tok.astOperand2 is None:
continue
if tok.astOperand2.str != ',':
continue
if tok.scope.type in ['Global', 'Class']:
continue
if tok.astOperand1.function is None:
continue
for argnr, argvar in tok.astOperand1.function.argument.items():
if argnr < 1:
continue
if not simpleMatch(argvar.typeStartToken, '...'):
continue
callArgs = getArguments(tok)
for i in range(argnr-1, len(callArgs)):
valueType = callArgs[i].valueType
if valueType is None:
argStart = callArgs[i].previous
while argStart.str != ',':
if argStart.str == ')':
argStart = argStart.link
argStart = argStart.previous
argEnd = callArgs[i]
while argEnd.str != ',' and argEnd.str != ')':
if argEnd.str == '(':
argEnd = argEnd.link
argEnd = argEnd.next
expression = ''
argStart = argStart.next
while argStart != argEnd:
expression = expression + argStart.str
argStart = argStart.next
reportError(tok, 'debug', 'Bailout, unknown argument type for argument \'' + expression + '\'.', 'debug')
continue
if valueType.pointer > 0:
continue
if valueType.type != 'record' and valueType.type != 'container':
continue
reportError(tok, 'style', 'Passing record to ellipsis function \'' + tok.astOperand1.function.name + '\'.', 'ellipsisStructArg')
break
for arg in sys.argv[1:]:
if arg in ['-debug', '-verify', '--cli']:
continue
print("Checking %s..." % arg)
data = cppcheckdata.CppcheckData(arg)
if VERIFY:
VERIFY_ACTUAL = []
VERIFY_EXPECTED = []
for tok in data.rawTokens:
if tok.str.startswith('//'):
for word in tok.str[2:].split(' '):
if word in ['stringConcatInArrayInit', 'implicitlyVirtual', 'ellipsisStructArg']:
VERIFY_EXPECTED.append(str(tok.linenr) + ':' + word)
stringConcatInArrayInit(data)
implicitlyVirtual(data)
ellipsisStructArg(data)
if VERIFY:
for expected in VERIFY_EXPECTED:
if expected not in VERIFY_ACTUAL:
print('Expected but not seen: ' + expected)
sys.exit(1)
for actual in VERIFY_ACTUAL:
if actual not in VERIFY_EXPECTED:
print('Not expected: ' + actual)
sys.exit(1)
sys.exit(cppcheckdata.EXIT_CODE)
|