diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index 550d2ea7174..d8bfcddd12f 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -254,6 +254,7 @@ class Token: isCast externLang isExpandedMacro Is this token a expanded macro token + macroName Macro name that this token is expanded from isRemovedVoidParameter Has void parameter been removed? isSplittedVarDeclComma Is this a comma changed to semicolon in a split variable declaration ('int a,b;' => 'int a; int b;') isSplittedVarDeclEq Is this a '=' changed to semicolon in a split variable declaration ('int a=5;' => 'int a; a=5;') @@ -313,6 +314,7 @@ class Token: isCast = False isUnsigned = False isSigned = False + macroName = None isExpandedMacro = False isRemovedVoidParameter = False isSplittedVarDeclComma = False @@ -386,7 +388,8 @@ def __init__(self, element): if element.get('isCast'): self.isCast = True self.externLang = element.get('externLang') - if element.get('isExpandedMacro'): + self.macroName = element.get('macroName') + if self.macroName or element.get('isExpandedMacro'): self.isExpandedMacro = True if element.get('isRemovedVoidParameter'): self.isRemovedVoidParameter = True diff --git a/addons/misra.py b/addons/misra.py index cc26146dd10..a93b9b518fe 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -2520,6 +2520,20 @@ def misra_11_3(self, data): self.reportError(token, 11, 3) def misra_11_4(self, data): + # Get list of macro definitions + macros = {} + for directive in data.directives: + #define X ((peripheral_t *)0x40000U) + res = re.match(r'#define ([A-Za-z0-9_]+).*', directive.str) + if res: + if res.group(1) in macros: + macros[res.group(1)].append(directive) + else: + macros[res.group(1)] = [directive] + + # If macro definition is non-compliant then warn about the macro definition instead of + # the macro usages. To reduce diagnostics for a non-compliant macro. + bad_macros = [] for token in data.tokenlist: if not isCast(token): continue @@ -2530,6 +2544,17 @@ def misra_11_4(self, data): if vt2.pointer > 0 and vt1.pointer == 0 and (vt1.isIntegral() or vt1.isEnum()) and vt2.type != 'void': self.reportError(token, 11, 4) elif vt1.pointer > 0 and vt2.pointer == 0 and (vt2.isIntegral() or vt2.isEnum()) and vt1.type != 'void': + if token.macroName is not None and \ + token.macroName == token.astOperand1.macroName and \ + token.astOperand1.isInt and \ + token.link.previous.str == '*' and \ + token.macroName == token.link.previous.macroName and \ + token.macroName in macros and \ + len(macros[token.macroName]) == 1: + if token.macroName not in bad_macros: + bad_macros.append(token.macroName) + self.reportError(macros[token.macroName][0], 11, 4) + continue self.reportError(token, 11, 4) def misra_11_5(self, data): diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index db73cfd6466..60295a837f1 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -798,12 +798,15 @@ static void misra_11_3(u8* p, struct Fred *fred) { struct Wilma *wilma = (struct Wilma *)fred; // 11.3 } +typedef struct { uint32_t something; } struct_11_4; +#define A_11_4 ((struct_11_4 *)0x40000U) // 11.4 + static void misra_11_4(u8*p) { u64 y = (u64)p; // 11.4 u8 *misra_11_4_A = ( u8 * ) 0x0005;// 11.4 s32 misra_11_4_B; u8 *q = ( u8 * ) misra_11_4_B; // 11.4 - + dummy = A_11_4->something; // no-warning } static void misra_11_5(void *p) { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 35ee843fa8c..26255413810 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5946,7 +5946,7 @@ void Tokenizer::dump(std::ostream &out) const if (tok->isExternC()) outs += " externLang=\"C\""; if (tok->isExpandedMacro()) - outs += " isExpandedMacro=\"true\""; + outs += " macroName=\"" + tok->getMacroName() + "\""; if (tok->isTemplateArg()) outs += " isTemplateArg=\"true\""; if (tok->isRemovedVoidParameter())