diff --git a/addons/misra.py b/addons/misra.py index 6c096f9d4..d81ef7222 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -543,6 +543,30 @@ def generateTable(): print(num[:8] + s) +def remove_file_prefix(file_path, prefix): + """ + Remove a file path prefix from a give path. leftover + directory separators at the beginning of a file + after the removal are also stripped. + + Example: + '/remove/this/path/file.c' + with a prefix of: + '/remove/this/path' + becomes: + file.c + """ + result = None + if file_path.startswith(prefix): + result = file_path[len(prefix):] + # Remove any leftover directory separators at the + # beginning + result = result.lstrip('\\/') + else: + result = file_path + return result + + class Rule(object): """Class to keep rule text and metadata""" @@ -636,6 +660,9 @@ class MisraChecker: # List of suppression extracted from the dumpfile self.dumpfileSuppressions = None + # Prefix to ignore when matching suppression files. + self.filePrefix = None + # Statistics of all violations suppressed per rule self.suppressionStats = dict() @@ -2010,7 +2037,10 @@ class MisraChecker: # Remove any prefix listed in command arguments from the filename. filename = None if location.file is not None: - filename = os.path.basename(location.file) + if self.filePrefix is not None: + filename = remove_file_prefix(location.file, self.filePrefix) + else: + filename = os.path.basename(location.file) if ruleNum in self.suppressedRules: fileDict = self.suppressedRules[ruleNum] @@ -2090,6 +2120,12 @@ class MisraChecker: for line in sorted(outlist, reverse=True): print(" %s" % line) + def setFilePrefix(self, prefix): + """ + Set the file prefix to ignnore from files when matching + suppression files + """ + self.filePrefix = prefix def setSuppressionList(self, suppressionlist): num1 = 0 @@ -2404,6 +2440,7 @@ def get_args(): parser.add_argument("-generate-table", help=argparse.SUPPRESS, action="store_true") parser.add_argument("dumpfile", nargs='*', help="Path of dump file from cppcheck") parser.add_argument("--show-suppressed-rules", help="Print rule suppression list", action="store_true") + parser.add_argument("-P", "--file-prefix", type=str, help="Prefix to strip when matching suppression file rules") parser.add_argument("--cli", help="Addon is executed from Cppcheck", action="store_true") return parser.parse_args() @@ -2435,6 +2472,9 @@ def main(): if args.suppress_rules: checker.setSuppressionList(args.suppress_rules) + if args.file_prefix: + checker.setFilePrefix(args.file_prefix) + if args.dumpfile: exitCode = 0 for item in args.dumpfile: diff --git a/addons/test/test-misra.py b/addons/test/test-misra.py index 43a549f36..b8750f279 100644 --- a/addons/test/test-misra.py +++ b/addons/test/test-misra.py @@ -124,3 +124,34 @@ def test_rules_suppression(checker, capsys): found = re.search(re_suppressed, captured) assert(found is None) dump_remove(src) + + +def test_arguments_regression(): + args_ok = ["-generate-table", + "--rule-texts=./addons/test/assets/misra_rules_multiple_lines.txt", + "--verify-rule-texts", + "-t=foo", "--template=foo", + "--suppress-rules=15.1", + "--quiet", + "--cli", + "--no-summary", + "--show-suppressed-rules", + "-P=src/", "--file-prefix=src/"] + # Arguments with expected SystemExit + args_exit = ["--non-exists", "--non-exists-param=42", "-h", "--help"] + + from addons.misra import get_args + + for arg in args_exit: + sys.argv.append(arg) + with pytest.raises(SystemExit): + get_args() + sys.argv.remove(arg) + + for arg in args_ok: + sys.argv.append(arg) + try: + get_args() + except SystemExit: + pytest.fail("Unexpected SystemExit with '%s'" % arg) + sys.argv.remove(arg)