misra.py: Fix false negative for rule 20.4 (#2528)

Define different sets of reserved keywords for C90 and C99.
This will fix false negative for compliant example, defined in MISRA
document, and close trac 9506.
This commit is contained in:
Georgy Komarov 2020-02-09 12:46:13 +03:00 committed by GitHub
parent e9b7e7811b
commit 6d4eff46be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 37 deletions

View File

@ -70,42 +70,35 @@ def rawlink(rawtoken):
return rawtoken return rawtoken
KEYWORDS = { # Reserved keywords defined in ISO/IEC9899:1990 -- ch 6.1.1
'auto', C90_KEYWORDS = {
'break', 'auto', 'break', 'double', 'else', 'enum', 'extern', 'float', 'for',
'case', 'goto', 'if', 'case', 'char', 'const', 'continue', 'default', 'do', 'int',
'char', 'long', 'struct', 'switch', 'register', 'typedef', 'union', 'unsigned',
'const', 'void', 'volatile', 'while', 'return', 'short', 'signed', 'sizeof',
'continue', 'static'
'default',
'do',
'double',
'else',
'enum',
'extern',
'float',
'for',
'goto',
'if',
'int',
'long',
'register',
'return',
'short',
'signed',
'sizeof',
'static',
'struct',
'switch',
'typedef',
'union',
'unsigned',
'void',
'volatile',
'while'
} }
# Reserved keywords defined in ISO/IEC 9899 WF14/N1256 -- ch. 6.4.1
C99_KEYWORDS = {
'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do',
'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'inline',
'int', 'long', 'register', 'restrict', 'return', 'short', 'signed',
'sizeof', 'static', 'struct', 'switch', 'typedef', 'union', 'unsigned',
'void', 'volatile', 'while', '_Bool', '_Complex', '_Imaginary'
}
def isKeyword(keyword, standard='c99'):
kw_set = {}
if standard == 'c89':
kw_set = C90_KEYWORDS
elif standard == 'c99':
kw_set = C99_KEYWORDS
return keyword in kw_set
def getEssentialTypeCategory(expr): def getEssentialTypeCategory(expr):
if not expr: if not expr:
return None return None
@ -218,14 +211,14 @@ def isCast(expr):
return True return True
def isFunctionCall(expr): def isFunctionCall(expr, std='c99'):
if not expr: if not expr:
return False return False
if expr.str != '(' or not expr.astOperand1: if expr.str != '(' or not expr.astOperand1:
return False return False
if expr.astOperand1 != expr.previous: if expr.astOperand1 != expr.previous:
return False return False
if expr.astOperand1.str in KEYWORDS: if isKeyword(expr.astOperand1.str, std):
return False return False
return True return True
@ -1838,7 +1831,7 @@ class MisraChecker:
tok = scope.bodyStart tok = scope.bodyStart
while tok != scope.bodyEnd: while tok != scope.bodyEnd:
tok = tok.next tok = tok.next
if not isFunctionCall(tok): if not isFunctionCall(tok, data.standards.c):
continue continue
f = tok.astOperand1.function f = tok.astOperand1.function
if f is not None and f not in calls: if f is not None and f not in calls:
@ -1998,7 +1991,7 @@ class MisraChecker:
def misra_20_4(self, data): def misra_20_4(self, data):
for directive in data.directives: for directive in data.directives:
res = re.search(r'#define ([a-z][a-z0-9_]+)', directive.str) res = re.search(r'#define ([a-z][a-z0-9_]+)', directive.str)
if res and (res.group(1) in KEYWORDS): if res and isKeyword(res.group(1), data.standards.c):
self.reportError(directive, 20, 4) self.reportError(directive, 20, 4)
def misra_20_5(self, data): def misra_20_5(self, data):

View File

@ -955,6 +955,7 @@ union misra_19_2 { }; // 19.2
#include "notfound.h" // 20.1 #include "notfound.h" // 20.1
#define int short // 20.4 #define int short // 20.4
#define inline "foo" // no warning in C90 standard
#undef X // 20.5 #undef X // 20.5
#define M_20_7_1(A) (A+1) // 20.7 #define M_20_7_1(A) (A+1) // 20.7