From 7a009fece0f3812a69b3a79f9bc85d7f1a55b1a8 Mon Sep 17 00:00:00 2001 From: Georgiy Komarov Date: Sat, 8 May 2021 11:27:31 +0300 Subject: [PATCH] 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. --- .travis.yml | 1 + addons/misra.py | 31 +++++++++++++++++++++++++------ addons/test/misra/misra-test.c | 1 + addons/test/misra/misra-test.h | 3 ++- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4fe087e48..bf578eb39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/addons/misra.py b/addons/misra.py index b431295e9..9d177568c 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -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 + '...') diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 48bb2e2db..a0092160c 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -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 diff --git a/addons/test/misra/misra-test.h b/addons/test/misra/misra-test.h index bc5473e44..ed932fcaf 100644 --- a/addons/test/misra/misra-test.h +++ b/addons/test/misra/misra-test.h @@ -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