misra: Add support for expected suppressions in header files in `-verify` mode (#3252)
This commit allows to specify expected suppressions in the included header files. This is necessary to verify MISRA checkers, which make requirements for header files. For example, Rule 8.2 requires adding prototypes for each function to the header files.
This commit is contained in:
parent
bfa26b5a72
commit
7a009fece0
|
@ -74,6 +74,7 @@ matrix:
|
||||||
# We'll force C89 standard to enable an additional verification for
|
# We'll force C89 standard to enable an additional verification for
|
||||||
# rules 5.4 and 5.5 which have standard-dependent options.
|
# rules 5.4 and 5.5 which have standard-dependent options.
|
||||||
- ${CPPCHECK} --dump --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.c
|
- ${CPPCHECK} --dump --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.c
|
||||||
|
- ${CPPCHECK} --dump --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.h
|
||||||
- python3 ../misra.py -verify misra/misra-test.c.dump
|
- python3 ../misra.py -verify misra/misra-test.c.dump
|
||||||
- ${CPPCHECK} --dump misra/misra-test.cpp
|
- ${CPPCHECK} --dump misra/misra-test.cpp
|
||||||
- python3 ../misra.py -verify misra/misra-test.cpp.dump
|
- python3 ../misra.py -verify misra/misra-test.cpp.dump
|
||||||
|
|
|
@ -2962,7 +2962,7 @@ class MisraChecker:
|
||||||
ruleNum = num1 * 100 + num2
|
ruleNum = num1 * 100 + num2
|
||||||
|
|
||||||
if self.settings.verify:
|
if self.settings.verify:
|
||||||
self.verify_actual.append(str(location.linenr) + ':' + str(num1) + '.' + str(num2))
|
self.verify_actual.append('%s:%d %d.%d' % (location.file, location.linenr, num1, num2))
|
||||||
elif self.isRuleSuppressed(location.file, location.linenr, ruleNum):
|
elif self.isRuleSuppressed(location.file, location.linenr, ruleNum):
|
||||||
# Error is suppressed. Ignore
|
# Error is suppressed. Ignore
|
||||||
self.suppressionStats.setdefault(ruleNum, 0)
|
self.suppressionStats.setdefault(ruleNum, 0)
|
||||||
|
@ -3126,6 +3126,14 @@ class MisraChecker:
|
||||||
check_function(*args)
|
check_function(*args)
|
||||||
|
|
||||||
def parseDump(self, dumpfile):
|
def parseDump(self, dumpfile):
|
||||||
|
def fillVerifyExpected(verify_expected, tok):
|
||||||
|
"""Add expected suppressions to verify_expected list."""
|
||||||
|
rule_re = re.compile(r'[0-9]+\.[0-9]+')
|
||||||
|
if tok.str.startswith('//') and 'TODO' not in tok.str:
|
||||||
|
for word in tok.str[2:].split(' '):
|
||||||
|
if rule_re.match(word):
|
||||||
|
verify_expected.append('%s:%d %s' % (tok.file, tok.linenr, word))
|
||||||
|
|
||||||
data = cppcheckdata.parsedump(dumpfile)
|
data = cppcheckdata.parsedump(dumpfile)
|
||||||
|
|
||||||
typeBits['CHAR'] = data.platform.char_bit
|
typeBits['CHAR'] = data.platform.char_bit
|
||||||
|
@ -3136,12 +3144,23 @@ class MisraChecker:
|
||||||
typeBits['POINTER'] = data.platform.pointer_bit
|
typeBits['POINTER'] = data.platform.pointer_bit
|
||||||
|
|
||||||
if self.settings.verify:
|
if self.settings.verify:
|
||||||
|
# Add suppressions from the current file
|
||||||
for tok in data.rawTokens:
|
for tok in data.rawTokens:
|
||||||
if tok.str.startswith('//') and 'TODO' not in tok.str:
|
fillVerifyExpected(self.verify_expected, tok)
|
||||||
compiled = re.compile(r'[0-9]+\.[0-9]+')
|
# Add suppressions from the included headers
|
||||||
for word in tok.str[2:].split(' '):
|
include_re = re.compile(r'^#include [<"]([a-zA-Z0-9]+[a-zA-Z\-_./\\0-9]*)[">]$')
|
||||||
if compiled.match(word):
|
dump_dir = os.path.dirname(data.filename)
|
||||||
self.verify_expected.append(str(tok.linenr) + ':' + word)
|
for conf in data.configurations:
|
||||||
|
for directive in conf.directives:
|
||||||
|
m = re.match(include_re, directive.str)
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
header_dump_path = os.path.join(dump_dir, m.group(1) + '.dump')
|
||||||
|
if not os.path.exists(header_dump_path):
|
||||||
|
continue
|
||||||
|
header_data = cppcheckdata.parsedump(header_dump_path)
|
||||||
|
for tok in header_data.rawTokens:
|
||||||
|
fillVerifyExpected(self.verify_expected, tok)
|
||||||
else:
|
else:
|
||||||
self.printStatus('Checking ' + dumpfile + '...')
|
self.printStatus('Checking ' + dumpfile + '...')
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// To test:
|
// To test:
|
||||||
|
// ~/cppcheck/cppcheck --dump misra/misra-test.h --std=c89
|
||||||
// ~/cppcheck/cppcheck --dump --suppress=uninitvar --suppress=uninitStructMember misra/misra-test.c --std=c89 && python3 ../misra.py -verify misra/misra-test.c.dump
|
// ~/cppcheck/cppcheck --dump --suppress=uninitvar --suppress=uninitStructMember misra/misra-test.c --std=c89 && python3 ../misra.py -verify misra/misra-test.c.dump
|
||||||
|
|
||||||
#include "path\file.h" // 20.2
|
#include "path\file.h" // 20.2
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef MISRA_TEST_H
|
#ifndef MISRA_TEST_H
|
||||||
#define MISRA_TEST_H
|
#define MISRA_TEST_H
|
||||||
struct misra_h_s { int foo; };
|
struct misra_h_s { int foo; };
|
||||||
bool test(char *a);
|
bool test(char *); // 8.2
|
||||||
|
bool test(char *a); // OK
|
||||||
#endif // MISRA_TEST_H
|
#endif // MISRA_TEST_H
|
||||||
|
|
Loading…
Reference in New Issue