misra.py: Handle more cases in Rule 20.3 check (#2529)

This commit add two additional cases for rule 20.3:

1. Support violations in the following format: `#include file.h`
2. Better multiline include directives and inline comments support.

See added test cases for examples.
This commit is contained in:
Georgy Komarov 2020-02-10 10:56:26 +03:00 committed by GitHub
parent bb701fd8be
commit 0ff23dbd0b
2 changed files with 46 additions and 17 deletions

View File

@ -1971,22 +1971,32 @@ class MisraChecker:
self.reportError(directive, 20, 2) self.reportError(directive, 20, 2)
break break
def misra_20_3(self, rawTokens): def misra_20_3(self, data):
linenr = -1 for directive in data.directives:
for token in rawTokens: if not directive.str.startswith('#include '):
if token.str.startswith('/') or token.linenr == linenr:
continue continue
linenr = token.linenr
if not simpleMatch(token, '# include'): words = directive.str.split(' ')
continue
headerToken = token.next.next # If include directive contains more than two words, here would be
num = 0 # violation anyway.
while headerToken and headerToken.linenr == linenr: if len(words) > 2:
if not headerToken.str.startswith('/*') and not headerToken.str.startswith('//'): self.reportError(directive, 20, 3)
num += 1
headerToken = headerToken.next # Handle include directives with not quoted argument
if num != 1: elif len(words) > 1:
self.reportError(token, 20, 3) filename = words[1]
if not ((filename.startswith('"') and
filename.endswith('"')) or
(filename.startswith('<') and
filename.endswith('>'))):
# We are handle only directly included files in the
# following format: #include file.h
# Cases with macro expansion provided by MISRA document are
# skipped because we don't always have access to directive
# definition.
if '.' in filename:
self.reportError(directive, 20, 3)
def misra_20_4(self, data): def misra_20_4(self, data):
for directive in data.directives: for directive in data.directives:
@ -2642,8 +2652,7 @@ class MisraChecker:
self.executeCheck(1902, self.misra_19_2, cfg) self.executeCheck(1902, self.misra_19_2, cfg)
self.executeCheck(2001, self.misra_20_1, cfg) self.executeCheck(2001, self.misra_20_1, cfg)
self.executeCheck(2002, self.misra_20_2, cfg) self.executeCheck(2002, self.misra_20_2, cfg)
if cfgNumber == 0: self.executeCheck(2003, self.misra_20_3, cfg)
self.executeCheck(2003, self.misra_20_3, data.rawTokens)
self.executeCheck(2004, self.misra_20_4, cfg) self.executeCheck(2004, self.misra_20_4, cfg)
self.executeCheck(2005, self.misra_20_5, cfg) self.executeCheck(2005, self.misra_20_5, cfg)
self.executeCheck(2006, self.misra_20_7, cfg) self.executeCheck(2006, self.misra_20_7, cfg)

View File

@ -2,9 +2,29 @@
// ~/cppcheck/cppcheck --dump misra-test.c && python ../../misra.py -verify misra-test.c.dump // ~/cppcheck/cppcheck --dump misra-test.c && python ../../misra.py -verify misra-test.c.dump
#include "path\file.h" // 20.2 #include "path\file.h" // 20.2
#include /*abc*/ "file.h" // no warning #include /*abc*/ "file.h" // no warning
/*foo*/#include "file.h" // no warning
#include "./file.h" // no warning
#include \
"file.h"
#include /*abc*/ \
"file.h"
#include "fi" "le.h" // 20.3 (strings are concatenated after preprocessing)
#include "fi" <le.h> // 20.3
#include <fi> <le.h> // 20.3
#include PATH "file.h" // 20.3 #include PATH "file.h" // 20.3
#define H_20_3_ok "file.h"
#include H_20_3_ok
#include file.h // 20.3
#define H_20_3_bad file.h
#include H_20_3_bad // TODO: 20.3 Trac #9606
#include "//file.h" // 20.2
#include "//file.h" H_20_3_bad // 20.2 20.3
//#include H_20_3_bad // no warning
#include H_20_3_ok H_20_3_ok // 20.3
#include<file.h> // no warning #include<file.h> // no warning
#include <setjmp.h> // 21.4 #include <setjmp.h> // 21.4
#include <signal.h> // 21.5 #include <signal.h> // 21.5
#include <stdio.h> //21.6 #include <stdio.h> //21.6