From 94a3ef0bdbc63b6179c84043524e64d8ba23e816 Mon Sep 17 00:00:00 2001 From: Grigoris Pavlakis <grigpavl@ece.auth.gr> Date: Sat, 30 Mar 2019 01:45:04 +0200 Subject: [PATCH] Add rule suppression functionality; just pass , do a general refactor to comply with PEP8 and get rid of most of the ugly code --- ci/cppcheck-misra.sh | 2 +- ci/summarizer.py | 105 +++++++++++++++++++++++++++---------------- 2 files changed, 67 insertions(+), 40 deletions(-) diff --git a/ci/cppcheck-misra.sh b/ci/cppcheck-misra.sh index 16cc6fca..6f9f2197 100755 --- a/ci/cppcheck-misra.sh +++ b/ci/cppcheck-misra.sh @@ -26,4 +26,4 @@ sed -i -r 's/(.*Script.*)|(.*Checking.*)|(.*MISRA.*)//gm; /(^$)/d; s/(\s\(.*\)\s # run the summarizer for a nice, clean summary of errors echo -e "\u001b[34;1mSummarizing results...\u001b[0m" -python3.6 ci/summarizer.py ci/report.msr +ci/summarizer.py --report ci/report.msr --suppress 5.2 5.3 12.1 15.5 # these are random, will be replaced diff --git a/ci/summarizer.py b/ci/summarizer.py index c39c2a11..af31c29e 100755 --- a/ci/summarizer.py +++ b/ci/summarizer.py @@ -1,80 +1,107 @@ #!/bin/env python3.6 -from sys import argv -from collections import Counter +from argparse import ArgumentParser """ Naive parser and pretty printer for the MISRA reports by cppcheck """ + class Summarizer(object): - def __init__(self, report_name): + def __init__(self, report_name, suppression_list): with open(report_name, 'r') as f: - self.file_lines = f.readlines() + self.file_lines = f.readlines() # read the report file f.close() - - self.red = "\033[91m" + + self.red = "\033[91m" # terminal colors self.yellow = "\033[93m" self.green = "\033[92m" self.bold = "\033[1m" self.end = "\033[0m" + self.violations_map = {} # dictionary containing filenames, rule violations and line where the violation + # occurred + self.suppression_list = suppression_list # list of rule numbers to be suppressed def analyze(self): """ A really dumb parser for the pre-processed report generated by cppcheck """ - - errors_map = {} # dictionary containing filenames, rule violations and line where the violation occurred - - lines_seen = set() # contains the unique lines from the file - - if len(self.file_lines) == 0: - print(bold + green + "Static analysis for MISRA compliance complete. No errors found." + end) - return 0 + + lines_seen = set() # contains the unique lines from the file + for line in self.file_lines: # remove duplicate lines if line not in lines_seen: lines_seen.add(line) - + line_contents = line.split(':') - file_name = line_contents[0] # first part is the filename (index 0) - error = (line_contents[1], line_contents[2].strip('\n')) # index 1 is the line number, index 2 is the number of violated rule + file_name = line_contents[0] # first part is the filename (index 0) + violation = (line_contents[1], line_contents[2].strip( + '\n')) # index 1 is the line number, index 2 is the number of violated rule (both are strings) - if file_name not in errors_map.keys(): - errors_map[file_name] = list() # create a new list for the new filename and append the tuple in it - errors_map[file_name].append(error) + if file_name not in self.violations_map.keys(): + self.violations_map[ + file_name] = list() # create a new list for the new filename and append the tuple w/ line & + # rule no. + self.violations_map[file_name].append(violation) else: - errors_map[file_name].append(error) # do not append if it already exists - - return errors_map # return the completed error dictionary + self.violations_map[file_name].append(violation) # do not append if it already exists + + for e in self.suppression_list: + for file_name in self.violations_map.keys(): + self.violations_map[file_name] = [x for x in self.violations_map[file_name] if x[1] != str(e)] + # replace the list of infractions with a new one, containing everything except the suppressed rules + self.violations_map = {k: v for (k, v) in self.violations_map.items() if len(v) != 0} + # "delete" all keys whose lists are empty - def pretty_print(self, errors): + def pretty_print_violations(self): """ - Pretty-prints the contents of the error dictionary with colors and stuff + Just a pretty printing function, no fancy logic here. """ - - print(self.bold + self.red + "=================================================\n" + self.end) - print(self.bold + self.red + " Static analysis results: Error Summary \n" + self.end) - for file_name in errors: + print(self.bold + self.red + "=========================================================\n" + self.end) + print(self.bold + self.red + " Static analysis results: Infraction summary \n" + self.end) + for file_name in self.violations_map: print("") - for error in sorted(errors[file_name], key=lambda x: int(x[0])): + for violation in sorted(self.violations_map[file_name], key=lambda x: int(x[0])): name_string = f"{self.bold}{self.red}File {self.yellow}{file_name}{self.red}" - rule_violated_string = f"violates rule {self.yellow}#{error[1]}{self.red} of the MISRA C 2012 standard" - line_number_string = f"at line {self.yellow}{error[0]}{self.end}" - + rule_violated_string = f"violates rule {self.yellow}#{violation[1]}{self.red} " \ + f"of the MISRA C 2012 standard" + line_number_string = f"at line {self.yellow}{violation[0]}{self.end}" + print(f"{name_string.ljust(75)} {rule_violated_string} {line_number_string}") print("") print("") - print(self.bold + self.red +"=================================================" + self.end) + print(self.bold + self.red + "=================================================" + self.end) + + def suppression_info(self): + """ + Pretty-prints the suppressed rule numbers. + :return: + """ + if (len(self.suppression_list) != 0): + print(self.bold + self.yellow + "WARNING: Suppressed infractions of rules: ", end="") + print(f", ".join(self.suppression_list), end=".") + print("") + print("") + else: + print(self.bold + self.green + "All available rules enforced - no suppressions") if __name__ == "__main__": - s = Summarizer(argv[1]) - errors = s.analyze() - if isinstance(errors, dict): - s.pretty_print(errors) + cli = ArgumentParser() + cli.add_argument("--report", nargs=1, default="./report.msr") + cli.add_argument("--suppress", nargs="*", type=str, default="") + + args = cli.parse_args() + s = Summarizer(str(args.report[0]), args.suppress) + s.analyze() + s.suppression_info() + + if len(s.violations_map) != 0: + s.pretty_print_violations() exit(127) - elif isinstance(errors, int) and errors == 0: + elif len(s.violations_map) == 0: + print(s.bold + s.green + "Static analysis for MISRA compliance complete. No infractions found." + s.end) exit(0) -- GitLab