Add --suppress-rules argument for misra.py (#1259)
* Added ignore list - Added ignore list - Use argparse to parse arguments - Source formatting * misra.py changed argument name - Changed ` --ignore-rules` to ` --suppress-rules` * Resolved VERIFY option in misra.py Resolved broken broken logic in commit to add argparse. * edit suppression list Modified names Hide some arguments * command line help formatting * Revert removal of --no-summary argument * missing text rules no longer reported * VERIFY scope modified to global
This commit is contained in:
parent
9f47d04af6
commit
6ce3571bdd
260
addons/misra.py
260
addons/misra.py
|
@ -19,25 +19,38 @@ import cppcheckdata
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import argparse
|
||||||
import subprocess
|
|
||||||
|
|
||||||
ruleTexts = {}
|
ruleTexts = {}
|
||||||
|
suppressRules = {}
|
||||||
|
typeBits = {
|
||||||
|
'CHAR': None,
|
||||||
|
'SHORT': None,
|
||||||
|
'INT': None,
|
||||||
|
'LONG': None,
|
||||||
|
'LONG_LONG': None,
|
||||||
|
'POINTER': None
|
||||||
|
}
|
||||||
|
|
||||||
VERIFY = False
|
VERIFY = False
|
||||||
SHOW_SUMMARY = True
|
|
||||||
QUIET = False
|
QUIET = False
|
||||||
|
SHOW_SUMMARY = True
|
||||||
VERIFY_EXPECTED = []
|
VERIFY_EXPECTED = []
|
||||||
VERIFY_ACTUAL = []
|
VERIFY_ACTUAL = []
|
||||||
VIOLATIONS = []
|
VIOLATIONS = []
|
||||||
|
|
||||||
|
|
||||||
def printStatus(*args, **kwargs):
|
def printStatus(*args, **kwargs):
|
||||||
if not QUIET:
|
if not QUIET:
|
||||||
print(*args, **kwargs)
|
print(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def reportError(location, num1, num2):
|
def reportError(location, num1, num2):
|
||||||
if VERIFY:
|
if VERIFY:
|
||||||
VERIFY_ACTUAL.append(str(location.linenr) + ':' + str(num1) + '.' + str(num2))
|
VERIFY_ACTUAL.append(str(location.linenr) + ':' + str(num1) + '.' + str(num2))
|
||||||
|
elif num1 in suppressRules and num2 in suppressRules[num1]:
|
||||||
|
# ignore error
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
num = num1 * 100 + num2
|
num = num1 * 100 + num2
|
||||||
id = 'misra-c2012-' + str(num1) + '.' + str(num2)
|
id = 'misra-c2012-' + str(num1) + '.' + str(num2)
|
||||||
|
@ -47,11 +60,11 @@ def reportError(location, num1, num2):
|
||||||
errmsg = 'misra violation (use --rule-texts=<file> to get proper output) [' + id + ']'
|
errmsg = 'misra violation (use --rule-texts=<file> to get proper output) [' + id + ']'
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
errmsg = '[' + location.file + ':' + str(location.linenr) + '] (style): ' + errmsg + '\n'
|
sys.stderr.write('[' + location.file + ':' + str(location.linenr) + '] (style): ' + errmsg + '\n')
|
||||||
sys.stderr.write(errmsg)
|
|
||||||
|
|
||||||
VIOLATIONS.append(errmsg)
|
VIOLATIONS.append(errmsg)
|
||||||
|
|
||||||
|
|
||||||
def simpleMatch(token, pattern):
|
def simpleMatch(token, pattern):
|
||||||
for p in pattern.split(' '):
|
for p in pattern.split(' '):
|
||||||
if not token or token.str != p:
|
if not token or token.str != p:
|
||||||
|
@ -59,6 +72,7 @@ def simpleMatch(token, pattern):
|
||||||
token = token.next
|
token = token.next
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def rawlink(rawtoken):
|
def rawlink(rawtoken):
|
||||||
if rawtoken.str == '}':
|
if rawtoken.str == '}':
|
||||||
indent = 0
|
indent = 0
|
||||||
|
@ -74,6 +88,7 @@ def rawlink(rawtoken):
|
||||||
rawtoken = None
|
rawtoken = None
|
||||||
return rawtoken
|
return rawtoken
|
||||||
|
|
||||||
|
|
||||||
KEYWORDS = {
|
KEYWORDS = {
|
||||||
'auto',
|
'auto',
|
||||||
'break',
|
'break',
|
||||||
|
@ -178,15 +193,15 @@ def bitsOfEssentialType(expr):
|
||||||
if type is None:
|
if type is None:
|
||||||
return 0
|
return 0
|
||||||
if type == 'char':
|
if type == 'char':
|
||||||
return CHAR_BIT
|
return typeBits['CHAR']
|
||||||
if type == 'short':
|
if type == 'short':
|
||||||
return SHORT_BIT
|
return typeBits['SHORT']
|
||||||
if type == 'int':
|
if type == 'int':
|
||||||
return INT_BIT
|
return typeBits['INT']
|
||||||
if type == 'long':
|
if type == 'long':
|
||||||
return LONG_BIT
|
return typeBits['LONG']
|
||||||
if type == 'long long':
|
if type == 'long long':
|
||||||
return LONG_LONG_BIT
|
return typeBits['LONG_LONG']
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -356,7 +371,7 @@ def findRawLink(token):
|
||||||
if indent <= 1:
|
if indent <= 1:
|
||||||
return token
|
return token
|
||||||
indent = indent - 1
|
indent = indent - 1
|
||||||
if forward == True:
|
if forward is True:
|
||||||
token = token.next
|
token = token.next
|
||||||
else:
|
else:
|
||||||
token = token.previous
|
token = token.previous
|
||||||
|
@ -364,6 +379,7 @@ def findRawLink(token):
|
||||||
# raw link not found
|
# raw link not found
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def numberOfParentheses(tok1, tok2):
|
def numberOfParentheses(tok1, tok2):
|
||||||
while tok1 and tok1 != tok2:
|
while tok1 and tok1 != tok2:
|
||||||
if tok1.str == '(' or tok1.str == ')':
|
if tok1.str == '(' or tok1.str == ')':
|
||||||
|
@ -399,7 +415,8 @@ def getArgumentsRecursive(tok, arguments):
|
||||||
getArgumentsRecursive(tok.astOperand1, arguments)
|
getArgumentsRecursive(tok.astOperand1, arguments)
|
||||||
getArgumentsRecursive(tok.astOperand2, arguments)
|
getArgumentsRecursive(tok.astOperand2, arguments)
|
||||||
else:
|
else:
|
||||||
arguments.append(tok);
|
arguments.append(tok)
|
||||||
|
|
||||||
|
|
||||||
def getArguments(ftok):
|
def getArguments(ftok):
|
||||||
arguments = []
|
arguments = []
|
||||||
|
@ -410,9 +427,11 @@ def getArguments(ftok):
|
||||||
def isHexDigit(c):
|
def isHexDigit(c):
|
||||||
return (c >= '0' and c <= '9') or (c >= 'a' and c <= 'f') or (c >= 'A' and c >= 'F')
|
return (c >= '0' and c <= '9') or (c >= 'a' and c <= 'f') or (c >= 'A' and c >= 'F')
|
||||||
|
|
||||||
|
|
||||||
def isOctalDigit(c):
|
def isOctalDigit(c):
|
||||||
return (c >= '0' and c <= '7')
|
return (c >= '0' and c <= '7')
|
||||||
|
|
||||||
|
|
||||||
def isNoReturnScope(tok):
|
def isNoReturnScope(tok):
|
||||||
if tok is None or tok.str != '}':
|
if tok is None or tok.str != '}':
|
||||||
return False
|
return False
|
||||||
|
@ -429,12 +448,14 @@ def isNoReturnScope(tok):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def misra_3_1(rawTokens):
|
def misra_3_1(rawTokens):
|
||||||
for token in rawTokens:
|
for token in rawTokens:
|
||||||
if token.str.startswith('/*') or token.str.startswith('//'):
|
if token.str.startswith('/*') or token.str.startswith('//'):
|
||||||
if '//' in token.str[2:] or '/*' in token.str[2:]:
|
if '//' in token.str[2:] or '/*' in token.str[2:]:
|
||||||
reportError(token, 3, 1)
|
reportError(token, 3, 1)
|
||||||
|
|
||||||
|
|
||||||
def misra_4_1(rawTokens):
|
def misra_4_1(rawTokens):
|
||||||
for token in rawTokens:
|
for token in rawTokens:
|
||||||
if token.str[0] != '"':
|
if token.str[0] != '"':
|
||||||
|
@ -445,21 +466,21 @@ def misra_4_1(rawTokens):
|
||||||
pos = pos + 1
|
pos = pos + 1
|
||||||
if token.str[pos1] != '\\':
|
if token.str[pos1] != '\\':
|
||||||
continue
|
continue
|
||||||
if token.str[pos1+1] == '\\':
|
if token.str[pos1 + 1] == '\\':
|
||||||
pos = pos1 + 2
|
pos = pos1 + 2
|
||||||
continue
|
continue
|
||||||
if token.str[pos1+1] == 'x':
|
if token.str[pos1 + 1] == 'x':
|
||||||
if not isHexDigit(token.str[pos1+2]):
|
if not isHexDigit(token.str[pos1 + 2]):
|
||||||
reportError(token, 4, 1)
|
reportError(token, 4, 1)
|
||||||
continue
|
continue
|
||||||
if not isHexDigit(token.str[pos1+3]):
|
if not isHexDigit(token.str[pos1 + 3]):
|
||||||
reportError(token, 4, 1)
|
reportError(token, 4, 1)
|
||||||
continue
|
continue
|
||||||
elif isOctalDigit(token.str[pos1+1]):
|
elif isOctalDigit(token.str[pos1 + 1]):
|
||||||
if not isOctalDigit(token.str[pos1+2]):
|
if not isOctalDigit(token.str[pos1 + 2]):
|
||||||
reportError(token, 4, 1)
|
reportError(token, 4, 1)
|
||||||
continue
|
continue
|
||||||
if not isOctalDigit(token.str[pos1+2]):
|
if not isOctalDigit(token.str[pos1 + 2]):
|
||||||
reportError(token, 4, 1)
|
reportError(token, 4, 1)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -489,6 +510,7 @@ def misra_5_1(data):
|
||||||
else:
|
else:
|
||||||
reportError(variable2.nameToken, 5, 1)
|
reportError(variable2.nameToken, 5, 1)
|
||||||
|
|
||||||
|
|
||||||
def misra_5_2(data):
|
def misra_5_2(data):
|
||||||
scopeVars = {}
|
scopeVars = {}
|
||||||
for var in data.variables:
|
for var in data.variables:
|
||||||
|
@ -534,7 +556,6 @@ def misra_5_2(data):
|
||||||
reportError(scopename2.bodyStart, 5, 2)
|
reportError(scopename2.bodyStart, 5, 2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def misra_5_3(data):
|
def misra_5_3(data):
|
||||||
enum = []
|
enum = []
|
||||||
scopeVars = {}
|
scopeVars = {}
|
||||||
|
@ -587,6 +608,7 @@ def misra_5_3(data):
|
||||||
if (scope.className and scope.className[:31] == e[:31]):
|
if (scope.className and scope.className[:31] == e[:31]):
|
||||||
reportError(scope.bodyStart, 5, 3)
|
reportError(scope.bodyStart, 5, 3)
|
||||||
|
|
||||||
|
|
||||||
def misra_5_4(data):
|
def misra_5_4(data):
|
||||||
macro = {}
|
macro = {}
|
||||||
compile_name = re.compile(r'#define ([a-zA-Z0-9_]+)')
|
compile_name = re.compile(r'#define ([a-zA-Z0-9_]+)')
|
||||||
|
@ -986,7 +1008,8 @@ def misra_12_2(data):
|
||||||
|
|
||||||
def misra_12_3(data):
|
def misra_12_3(data):
|
||||||
for token in data.tokenlist:
|
for token in data.tokenlist:
|
||||||
if token.str != ',' or token.scope.type == 'Enum' or token.scope.type == 'Class' or token.scope.type == 'Global':
|
if token.str != ',' or token.scope.type == 'Enum' or \
|
||||||
|
token.scope.type == 'Class' or token.scope.type == 'Global':
|
||||||
continue
|
continue
|
||||||
if token.astParent and token.astParent.str in ['(', ',', '{']:
|
if token.astParent and token.astParent.str in ['(', ',', '{']:
|
||||||
continue
|
continue
|
||||||
|
@ -994,9 +1017,9 @@ def misra_12_3(data):
|
||||||
|
|
||||||
|
|
||||||
def misra_12_4(data):
|
def misra_12_4(data):
|
||||||
if INT_BIT == 16:
|
if typeBits['INT'] == 16:
|
||||||
max_uint = 0xffff
|
max_uint = 0xffff
|
||||||
elif INT_BIT == 32:
|
elif typeBits['INT'] == 32:
|
||||||
max_uint = 0xffffffff
|
max_uint = 0xffffffff
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
@ -1392,6 +1415,7 @@ def misra_20_5(data):
|
||||||
if directive.str.startswith('#undef '):
|
if directive.str.startswith('#undef '):
|
||||||
reportError(directive, 20, 5)
|
reportError(directive, 20, 5)
|
||||||
|
|
||||||
|
|
||||||
def misra_20_13(data):
|
def misra_20_13(data):
|
||||||
for directive in data.directives:
|
for directive in data.directives:
|
||||||
dir = directive.str
|
dir = directive.str
|
||||||
|
@ -1399,9 +1423,11 @@ def misra_20_13(data):
|
||||||
dir = dir[:dir.find(' ')]
|
dir = dir[:dir.find(' ')]
|
||||||
if dir.find('(') > 0:
|
if dir.find('(') > 0:
|
||||||
dir = dir[:dir.find('(')]
|
dir = dir[:dir.find('(')]
|
||||||
if dir not in ['#define', '#elif', '#else', '#endif', '#error', '#if', '#ifdef', '#ifndef', '#include', '#pragma', '#undef', '#warning']:
|
if dir not in ['#define', '#elif', '#else', '#endif', '#error', '#if', '#ifdef', '#ifndef', '#include',
|
||||||
|
'#pragma', '#undef', '#warning']:
|
||||||
reportError(directive, 20, 13)
|
reportError(directive, 20, 13)
|
||||||
|
|
||||||
|
|
||||||
def misra_20_14(data):
|
def misra_20_14(data):
|
||||||
# stack for #if blocks. contains the #if directive until the corresponding #endif is seen.
|
# stack for #if blocks. contains the #if directive until the corresponding #endif is seen.
|
||||||
# the size increases when there are inner #if directives.
|
# the size increases when there are inner #if directives.
|
||||||
|
@ -1410,7 +1436,7 @@ def misra_20_14(data):
|
||||||
if directive.str.startswith('#if ') or directive.str.startswith('#ifdef ') or directive.str.startswith('#ifndef '):
|
if directive.str.startswith('#if ') or directive.str.startswith('#ifdef ') or directive.str.startswith('#ifndef '):
|
||||||
ifStack.append(directive)
|
ifStack.append(directive)
|
||||||
elif directive.str == '#else' or directive.str.startswith('#elif '):
|
elif directive.str == '#else' or directive.str.startswith('#elif '):
|
||||||
if len(ifStack)==0:
|
if len(ifStack) == 0:
|
||||||
reportError(directive, 20, 14)
|
reportError(directive, 20, 14)
|
||||||
ifStack.append(directive)
|
ifStack.append(directive)
|
||||||
elif directive.file != ifStack[-1].file:
|
elif directive.file != ifStack[-1].file:
|
||||||
|
@ -1422,6 +1448,7 @@ def misra_20_14(data):
|
||||||
reportError(directive, 20, 14)
|
reportError(directive, 20, 14)
|
||||||
ifStack.pop()
|
ifStack.pop()
|
||||||
|
|
||||||
|
|
||||||
def misra_21_3(data):
|
def misra_21_3(data):
|
||||||
for token in data.tokenlist:
|
for token in data.tokenlist:
|
||||||
if isFunctionCall(token) and (token.astOperand1.str in {'malloc', 'calloc', 'realloc', 'free'}):
|
if isFunctionCall(token) and (token.astOperand1.str in {'malloc', 'calloc', 'realloc', 'free'}):
|
||||||
|
@ -1483,6 +1510,26 @@ def misra_21_11(data):
|
||||||
reportError(directive, 21, 11)
|
reportError(directive, 21, 11)
|
||||||
|
|
||||||
|
|
||||||
|
def setSuppressionList(suppressionlist):
|
||||||
|
num1 = 0
|
||||||
|
num2 = 0
|
||||||
|
global suppressRules
|
||||||
|
rule_pattern = re.compile(r'([0-9]+).([0-9]+)')
|
||||||
|
strlist = suppressionlist.split(",")
|
||||||
|
|
||||||
|
# build ignore list
|
||||||
|
suppressRules = {}
|
||||||
|
for item in strlist:
|
||||||
|
res = rule_pattern.match(item)
|
||||||
|
if res:
|
||||||
|
num1 = int(res.group(1))
|
||||||
|
num2 = int(res.group(2))
|
||||||
|
if num1 in suppressRules:
|
||||||
|
suppressRules[num1][num2] = True
|
||||||
|
else:
|
||||||
|
suppressRules[num1] = {num2: True}
|
||||||
|
|
||||||
|
|
||||||
def loadRuleTexts(filename):
|
def loadRuleTexts(filename):
|
||||||
num1 = 0
|
num1 = 0
|
||||||
num2 = 0
|
num2 = 0
|
||||||
|
@ -1526,37 +1573,6 @@ def loadRuleTexts(filename):
|
||||||
ruleTexts[num] = ruleTexts[num] + ' ' + line
|
ruleTexts[num] = ruleTexts[num] + ' ' + line
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
print("""
|
|
||||||
Syntax: misra.py [OPTIONS] <dumpfiles>
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
|
|
||||||
--rule-texts=<file> Load rule texts from plain text file.
|
|
||||||
|
|
||||||
If you have the tool 'pdftotext' you might be able
|
|
||||||
to generate this textfile with such command:
|
|
||||||
|
|
||||||
$ pdftotext MISRA_C_2012.pdf MISRA_C_2012.txt
|
|
||||||
|
|
||||||
Otherwise you can more or less copy/paste the chapter
|
|
||||||
Appendix A Summary of guidelines
|
|
||||||
from the MISRA pdf. You can buy the MISRA pdf from
|
|
||||||
http://www.misra.org.uk/
|
|
||||||
|
|
||||||
Format:
|
|
||||||
|
|
||||||
<..arbitrary text..>
|
|
||||||
Appendix A Summary of guidelines
|
|
||||||
Rule 1.1
|
|
||||||
Rule text for 1.1
|
|
||||||
Rule 1.2
|
|
||||||
Rule text for 1.2
|
|
||||||
<...>
|
|
||||||
|
|
||||||
--quiet Only print something when there is an error
|
|
||||||
""")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def generateTable():
|
def generateTable():
|
||||||
numberOfRules = {}
|
numberOfRules = {}
|
||||||
|
@ -1593,14 +1609,15 @@ def generateTable():
|
||||||
addon.append(res.group(1) + '.' + res.group(2))
|
addon.append(res.group(1) + '.' + res.group(2))
|
||||||
|
|
||||||
# rules handled by cppcheck
|
# rules handled by cppcheck
|
||||||
cppcheck = ['1.3', '2.1', '2.2', '2.4', '2.6', '8.3', '12.2', '13.2', '13.6', '17.5', '18.1', '18.6', '20.6', '22.1', '22.2', '22.4', '22.6']
|
cppcheck = ['1.3', '2.1', '2.2', '2.4', '2.6', '8.3', '12.2', '13.2', '13.6', '17.5', '18.1', '18.6',
|
||||||
|
'20.6', '22.1', '22.2', '22.4', '22.6']
|
||||||
|
|
||||||
# rules that can be checked with compilers
|
# rules that can be checked with compilers
|
||||||
compiler = ['1.1', '1.2']
|
# compiler = ['1.1', '1.2']
|
||||||
|
|
||||||
# print table
|
# print table
|
||||||
for i1 in range(1,23):
|
for i1 in range(1, 23):
|
||||||
for i2 in range(1,numberOfRules[i1]+1):
|
for i2 in range(1, numberOfRules[i1] + 1):
|
||||||
num = str(i1) + '.' + str(i2)
|
num = str(i1) + '.' + str(i2)
|
||||||
s = ''
|
s = ''
|
||||||
if num in addon:
|
if num in addon:
|
||||||
|
@ -1611,44 +1628,19 @@ def generateTable():
|
||||||
print(num[:8] + s)
|
print(num[:8] + s)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
for arg in sys.argv[1:]:
|
|
||||||
if arg == '-verify':
|
|
||||||
VERIFY = True
|
|
||||||
elif arg.startswith('--rule-texts='):
|
|
||||||
filename = arg[13:]
|
|
||||||
if not os.path.isfile(filename):
|
|
||||||
print('Fatal error: file is not found: ' + filename)
|
|
||||||
sys.exit(1)
|
|
||||||
loadRuleTexts(filename)
|
|
||||||
elif ".dump" in arg:
|
|
||||||
continue
|
|
||||||
elif arg == "-generate-table":
|
|
||||||
generateTable()
|
|
||||||
elif arg == "--no-summary":
|
|
||||||
SHOW_SUMMARY = False
|
|
||||||
elif arg == "--quiet":
|
|
||||||
QUIET = True
|
|
||||||
else:
|
|
||||||
print('Fatal error: unhandled argument ' + arg)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
exitCode = 0
|
def parseDump(dumpfile):
|
||||||
for arg in sys.argv[1:]:
|
|
||||||
if not arg.endswith('.dump'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
data = cppcheckdata.parsedump(arg)
|
data = cppcheckdata.parsedump(dumpfile)
|
||||||
|
|
||||||
CHAR_BIT = data.platform.char_bit
|
typeBits['CHAR'] = data.platform.char_bit
|
||||||
SHORT_BIT = data.platform.short_bit
|
typeBits['SHORT'] = data.platform.short_bit
|
||||||
INT_BIT = data.platform.int_bit
|
typeBits['INT'] = data.platform.int_bit
|
||||||
LONG_BIT = data.platform.long_bit
|
typeBits['LONG'] = data.platform.long_bit
|
||||||
LONG_LONG_BIT = data.platform.long_long_bit
|
typeBits['LONG_LONG'] = data.platform.long_long_bit
|
||||||
POINTER_BIT = data.platform.pointer_bit
|
typeBits['POINTER'] = data.platform.pointer_bit
|
||||||
|
|
||||||
if VERIFY:
|
if VERIFY:
|
||||||
VERIFY_ACTUAL = []
|
|
||||||
VERIFY_EXPECTED = []
|
|
||||||
for tok in data.rawTokens:
|
for tok in data.rawTokens:
|
||||||
if tok.str.startswith('//') and 'TODO' not in tok.str:
|
if tok.str.startswith('//') and 'TODO' not in tok.str:
|
||||||
compiled = re.compile(r'[0-9]+\.[0-9]+')
|
compiled = re.compile(r'[0-9]+\.[0-9]+')
|
||||||
|
@ -1656,14 +1648,14 @@ for arg in sys.argv[1:]:
|
||||||
if compiled.match(word):
|
if compiled.match(word):
|
||||||
VERIFY_EXPECTED.append(str(tok.linenr) + ':' + word)
|
VERIFY_EXPECTED.append(str(tok.linenr) + ':' + word)
|
||||||
else:
|
else:
|
||||||
printStatus('Checking ' + arg + '...')
|
printStatus('Checking ' + dumpfile + '...')
|
||||||
|
|
||||||
cfgNumber = 0
|
cfgNumber = 0
|
||||||
|
|
||||||
for cfg in data.configurations:
|
for cfg in data.configurations:
|
||||||
cfgNumber = cfgNumber + 1
|
cfgNumber = cfgNumber + 1
|
||||||
if len(data.configurations) > 1:
|
if len(data.configurations) > 1:
|
||||||
printStatus('Checking ' + arg + ', config "' + cfg.name + '"...')
|
printStatus('Checking ' + dumpfile + ', config "' + cfg.name + '"...')
|
||||||
|
|
||||||
if cfgNumber == 1:
|
if cfgNumber == 1:
|
||||||
misra_3_1(data.rawTokens)
|
misra_3_1(data.rawTokens)
|
||||||
|
@ -1747,8 +1739,9 @@ for arg in sys.argv[1:]:
|
||||||
misra_21_10(cfg)
|
misra_21_10(cfg)
|
||||||
misra_21_11(cfg)
|
misra_21_11(cfg)
|
||||||
# 22.4 is already covered by Cppcheck writeReadOnlyFile
|
# 22.4 is already covered by Cppcheck writeReadOnlyFile
|
||||||
|
|
||||||
|
exitCode = 0
|
||||||
if VERIFY:
|
if VERIFY:
|
||||||
exitCode = 0
|
|
||||||
for expected in VERIFY_EXPECTED:
|
for expected in VERIFY_EXPECTED:
|
||||||
if expected not in VERIFY_ACTUAL:
|
if expected not in VERIFY_ACTUAL:
|
||||||
print('Expected but not seen: ' + expected)
|
print('Expected but not seen: ' + expected)
|
||||||
|
@ -1757,11 +1750,74 @@ for arg in sys.argv[1:]:
|
||||||
if actual not in VERIFY_EXPECTED:
|
if actual not in VERIFY_EXPECTED:
|
||||||
print('Not expected: ' + actual)
|
print('Not expected: ' + actual)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
|
else:
|
||||||
|
if len(VIOLATIONS) > 0:
|
||||||
|
if SHOW_SUMMARY:
|
||||||
|
print("\nRule violations found: %d\n" % (len(VIOLATIONS)))
|
||||||
|
exitCode = 1
|
||||||
|
|
||||||
if not VERIFY:
|
sys.exit(exitCode)
|
||||||
if len(VIOLATIONS) > 0:
|
|
||||||
if SHOW_SUMMARY:
|
|
||||||
print("\nRule violations found: %d\n"%(len(VIOLATIONS)))
|
|
||||||
exitCode = 1
|
|
||||||
|
|
||||||
sys.exit(exitCode)
|
|
||||||
|
RULE_TEXTS_HELP = '''Path to text file of MISRA rules
|
||||||
|
|
||||||
|
If you have the tool 'pdftotext' you might be able
|
||||||
|
to generate this textfile with such command:
|
||||||
|
|
||||||
|
pdftotext MISRA_C_2012.pdf MISRA_C_2012.txt
|
||||||
|
|
||||||
|
Otherwise you can more or less copy/paste the chapter
|
||||||
|
Appendix A Summary of guidelines
|
||||||
|
from the MISRA pdf. You can buy the MISRA pdf from
|
||||||
|
http://www.misra.org.uk/
|
||||||
|
|
||||||
|
Format:
|
||||||
|
|
||||||
|
<..arbitrary text..>
|
||||||
|
Appendix A Summary of guidelines
|
||||||
|
Rule 1.1
|
||||||
|
Rule text for 1.1
|
||||||
|
Rule 1.2
|
||||||
|
Rule text for 1.2
|
||||||
|
<...>
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
SUPPRESS_RULES_HELP = '''MISRA rules to suppress (comma-separated)
|
||||||
|
|
||||||
|
For example, if you'd like to suppress rules 15.1, 11.3,
|
||||||
|
and 20.13, run:
|
||||||
|
|
||||||
|
python misra.py --suppress-rules 15.1,11.3,20.13 ...
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
|
||||||
|
parser.add_argument("--rule-texts", type=str, help=RULE_TEXTS_HELP)
|
||||||
|
parser.add_argument("--suppress-rules", type=str, help=SUPPRESS_RULES_HELP)
|
||||||
|
parser.add_argument("--quiet", help="Only print something when there is an error", action="store_true")
|
||||||
|
parser.add_argument("--no-summary", help="Hide summary of violations", action="store_true")
|
||||||
|
parser.add_argument("-verify", help=argparse.SUPPRESS, action="store_true")
|
||||||
|
parser.add_argument("-generate-table", help=argparse.SUPPRESS, action="store_true")
|
||||||
|
parser.add_argument("file", help="Path of dump file from cppcheck")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.generate_table:
|
||||||
|
generateTable()
|
||||||
|
else:
|
||||||
|
if args.verify:
|
||||||
|
VERIFY = True
|
||||||
|
if args.rule_texts:
|
||||||
|
filename = os.path.normpath(args.rule_texts)
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
print('Fatal error: file is not found: ' + filename)
|
||||||
|
sys.exit(1)
|
||||||
|
loadRuleTexts(filename)
|
||||||
|
if args.suppress_rules:
|
||||||
|
setSuppressionList(args.suppress_rules)
|
||||||
|
if args.quiet:
|
||||||
|
QUIET = True
|
||||||
|
if args.no_summary:
|
||||||
|
SHOW_SUMMARY = False
|
||||||
|
if args.file:
|
||||||
|
parseDump(args.file)
|
||||||
|
|
Loading…
Reference in New Issue