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:
Georgiy Komarov 2021-05-08 11:27:31 +03:00 committed by GitHub
parent bfa26b5a72
commit 7a009fece0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 7 deletions

View File

@ -74,6 +74,7 @@ matrix:
# We'll force C89 standard to enable an additional verification for
# 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.h
- python3 ../misra.py -verify misra/misra-test.c.dump
- ${CPPCHECK} --dump misra/misra-test.cpp
- python3 ../misra.py -verify misra/misra-test.cpp.dump

View File

@ -2962,7 +2962,7 @@ class MisraChecker:
ruleNum = num1 * 100 + num2
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):
# Error is suppressed. Ignore
self.suppressionStats.setdefault(ruleNum, 0)
@ -3126,6 +3126,14 @@ class MisraChecker:
check_function(*args)
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)
typeBits['CHAR'] = data.platform.char_bit
@ -3136,12 +3144,23 @@ class MisraChecker:
typeBits['POINTER'] = data.platform.pointer_bit
if self.settings.verify:
# Add suppressions from the current file
for tok in data.rawTokens:
if tok.str.startswith('//') and 'TODO' not in tok.str:
compiled = re.compile(r'[0-9]+\.[0-9]+')
for word in tok.str[2:].split(' '):
if compiled.match(word):
self.verify_expected.append(str(tok.linenr) + ':' + word)
fillVerifyExpected(self.verify_expected, tok)
# Add suppressions from the included headers
include_re = re.compile(r'^#include [<"]([a-zA-Z0-9]+[a-zA-Z\-_./\\0-9]*)[">]$')
dump_dir = os.path.dirname(data.filename)
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:
self.printStatus('Checking ' + dumpfile + '...')

View File

@ -1,4 +1,5 @@
// 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
#include "path\file.h" // 20.2

View File

@ -1,5 +1,6 @@
#ifndef MISRA_TEST_H
#define MISRA_TEST_H
struct misra_h_s { int foo; };
bool test(char *a);
bool test(char *); // 8.2
bool test(char *a); // OK
#endif // MISRA_TEST_H