diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index 66f66a8dc..ec0e73b8f 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -81,15 +81,21 @@ class MacroUsage: file = None linenr = None column = None + usefile = None + uselinenr = None + usecolumn = None def __init__(self, element): self.name = element.get('name') _load_location(self, element) + self.usefile = element.get('usefile') + self.useline = element.get('useline') + self.usecolumn = element.get('usecolumn') def __repr__(self): - attrs = ["name", "file", "linenr", "column"] + attrs = ["name", "file", "linenr", "column", "usefile", "useline", "usecolumn"] return "{}({})".format( - "Directive", + "MacroUsage", ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs)) ) diff --git a/addons/misra.py b/addons/misra.py index b3e193d39..9c15e2b48 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -3239,6 +3239,57 @@ class MisraChecker: if res: self.reportError(directive, 20, 11) + def misra_20_12(self, cfg): + def _is_hash_hash_op(expansion_list, arg): + return re.search(r'##[ ]*%s[^a-zA-Z0-9_]' % arg, expansion_list) or \ + re.search(r'[^a-zA-Z0-9_]%s[ ]*##' % arg, expansion_list) + + def _is_other_op(expansion_list, arg): + pos = expansion_list.find(arg) + while pos >= 0: + pos1 = pos - 1 + pos2 = pos + len(arg) + pos = expansion_list.find(arg, pos2) + if isalnum(expansion_list[pos1]) or expansion_list[pos1] == '_': + continue + if isalnum(expansion_list[pos2]) or expansion_list[pos2] == '_': + continue + while expansion_list[pos1] == ' ': + pos1 = pos1 - 1 + if expansion_list[pos1] == '#': + continue + while expansion_list[pos2] == ' ': + pos2 = pos2 + 1 + if expansion_list[pos2] == '#': + continue + return True + return False + + def _is_arg_macro_usage(directive, arg): + for macro_usage in cfg.macro_usage: + if macro_usage.file == directive.file and macro_usage.linenr == directive.linenr: + for macro_usage_arg in cfg.macro_usage: + if macro_usage_arg == macro_usage: + continue + if (macro_usage.usefile == macro_usage_arg.usefile and + macro_usage.uselinenr == macro_usage_arg.uselinenr and + macro_usage.usecolumn == macro_usage_arg.usecolumn): + # TODO: check arg better + return True + return False + + for directive in cfg.directives: + define = Define(directive) + expansion_list = '(%s)' % define.expansionList + for arg in define.args: + if not _is_hash_hash_op(expansion_list, arg): + continue + if not _is_other_op(expansion_list, arg): + continue + if _is_arg_macro_usage(directive, arg): + self.reportError(directive, 20, 12) + break + def misra_20_13(self, data): dir_pattern = re.compile(r'#[ ]*([^ (<]*)') for directive in data.directives: @@ -3913,6 +3964,7 @@ class MisraChecker: self.executeCheck(2009, self.misra_20_9, cfg) self.executeCheck(2010, self.misra_20_10, cfg) self.executeCheck(2011, self.misra_20_11, cfg) + self.executeCheck(2012, self.misra_20_12, cfg) self.executeCheck(2013, self.misra_20_13, cfg) self.executeCheck(2014, self.misra_20_14, cfg) self.executeCheck(2101, self.misra_21_1, cfg) diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 7693ed059..14be0e361 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -1571,6 +1571,10 @@ struct { int a; } struct_20_7_s; #define M_20_11(a) # a ## 1 // 20.11 20.10 +#define M_20_12_AA 0xffff +#define M_20_12_BB(x) (x) + wow ## x // 20.12 20.10 +misra_20_12 = M_20_12_BB(M_20_12_AA); + #else1 // 20.13 #ifdef A