Add MISRA checks for rules 21.1 and 21.12 (#2284)

* Add MISRA 21.1 check

This also required add static field for functions in symboldatabase.

* Add MISRA R21.12

* Use newer ASSERT macroses in tests
This commit is contained in:
Georgy Komarov 2019-10-26 09:32:46 +03:00 committed by Daniel Marjamäki
parent 37bb19f02c
commit 72f07c8a33
5 changed files with 132 additions and 4 deletions

View File

@ -341,6 +341,7 @@ class Function:
tokenDef Token in function definition tokenDef Token in function definition
isVirtual Is this function is virtual isVirtual Is this function is virtual
isImplicitlyVirtual Is this function is virtual this in the base classes isImplicitlyVirtual Is this function is virtual this in the base classes
isStatic Is this function is static
""" """
Id = None Id = None
@ -352,6 +353,7 @@ class Function:
type = None type = None
isVirtual = None isVirtual = None
isImplicitlyVirtual = None isImplicitlyVirtual = None
isStatic = None
def __init__(self, element): def __init__(self, element):
self.Id = element.get('id') self.Id = element.get('id')
@ -362,6 +364,8 @@ class Function:
self.isVirtual = (isVirtual and isVirtual == 'true') self.isVirtual = (isVirtual and isVirtual == 'true')
isImplicitlyVirtual = element.get('isImplicitlyVirtual') isImplicitlyVirtual = element.get('isImplicitlyVirtual')
self.isImplicitlyVirtual = (isImplicitlyVirtual and isImplicitlyVirtual == 'true') self.isImplicitlyVirtual = (isImplicitlyVirtual and isImplicitlyVirtual == 'true')
isStatic = element.get('isStatic')
self.isStatic = (isStatic and isStatic == 'true')
self.argument = {} self.argument = {}
self.argumentId = {} self.argumentId = {}

View File

@ -1937,6 +1937,38 @@ class MisraChecker:
ifStack.pop() ifStack.pop()
def misra_21_1(self, data):
# Reference: n1570 7.1.3 - Reserved identifiers
re_forbidden_macro = re.compile(r'#define (errno|_[_A-Z]+)')
# Search for forbidden identifiers in macro names
for directive in data.directives:
res = re.search(re_forbidden_macro, directive.str)
if res:
self.reportError(directive, 21, 1)
# Search for forbidden identifiers
for token in data.tokenlist:
if not token.isName:
continue
if len(token.str) < 2:
continue
if token.str == 'errno':
self.reportError(token, 21, 1)
if token.str[0] == '_':
if (token.str[1] in string.ascii_uppercase) or (token.str[1] == '_'):
self.reportError(token, 21, 1)
# Allow identifiers with file scope visibility (static)
if token.scope.type == 'Global':
if token.variable and token.variable.isStatic:
continue
if token.function and token.function.isStatic:
continue
self.reportError(token, 21, 1)
def misra_21_3(self, data): def misra_21_3(self, data):
for token in data.tokenlist: for token in data.tokenlist:
if isFunctionCall(token) and (token.astOperand1.str in ('malloc', 'calloc', 'realloc', 'free')): if isFunctionCall(token) and (token.astOperand1.str in ('malloc', 'calloc', 'realloc', 'free')):
@ -1998,6 +2030,20 @@ class MisraChecker:
self.reportError(directive, 21, 11) self.reportError(directive, 21, 11)
def misra_21_12(self, data):
if findInclude(data.directives, '<fenv.h>'):
for token in data.tokenlist:
if token.str == 'fexcept_t' and token.isName:
self.reportError(token, 21, 12)
if isFunctionCall(token) and (token.astOperand1.str in (
'feclearexcept',
'fegetexceptflag',
'feraiseexcept',
'fesetexceptflag',
'fetestexcept')):
self.reportError(token, 21, 12)
def get_verify_expected(self): def get_verify_expected(self):
"""Return the list of expected violations in the verify test""" """Return the list of expected violations in the verify test"""
return self.verify_expected return self.verify_expected
@ -2495,6 +2541,7 @@ class MisraChecker:
self.misra_20_10(cfg) self.misra_20_10(cfg)
self.misra_20_13(cfg) self.misra_20_13(cfg)
self.misra_20_14(cfg) self.misra_20_14(cfg)
self.misra_21_1(cfg)
self.misra_21_3(cfg) self.misra_21_3(cfg)
self.misra_21_4(cfg) self.misra_21_4(cfg)
self.misra_21_5(cfg) self.misra_21_5(cfg)
@ -2504,6 +2551,7 @@ class MisraChecker:
self.misra_21_9(cfg) self.misra_21_9(cfg)
self.misra_21_10(cfg) self.misra_21_10(cfg)
self.misra_21_11(cfg) self.misra_21_11(cfg)
self.misra_21_12(cfg)
# 22.4 is already covered by Cppcheck writeReadOnlyFile # 22.4 is already covered by Cppcheck writeReadOnlyFile

View File

@ -11,6 +11,7 @@
#include <wchar.h> //21.6 #include <wchar.h> //21.6
#include <time.h> // 21.10 #include <time.h> // 21.10
#include <tgmath.h> // 21.11 #include <tgmath.h> // 21.11
#include <fenv.h>
typedef unsigned char u8; typedef unsigned char u8;
@ -395,7 +396,7 @@ void misra_14_2() {
struct { struct {
unsigned int x:1; unsigned int x:1;
unsigned int y:1; unsigned int y:1;
} _14_4_struct; } r14_4_struct;
void misra_14_4(bool b) { void misra_14_4(bool b) {
if (x+4){} // 14.4 if (x+4){} // 14.4
else {} else {}
@ -403,7 +404,7 @@ void misra_14_4(bool b) {
if (b) {} if (b) {}
else {} else {}
if (_14_4_struct.x) {} if (r14_4_struct.x) {}
} }
void misra_15_1() { void misra_15_1() {
@ -652,12 +653,12 @@ struct {
} nested_2; } nested_2;
uint8_t data_3[]; // 18.7 uint8_t data_3[]; // 18.7
} nested_3; } nested_3;
} _18_7_struct; } r18_7_struct;
struct { struct {
uint16_t len; uint16_t len;
uint8_t data_1[ 19 ]; uint8_t data_1[ 19 ];
uint8_t data_2[ ]; // 18.7 uint8_t data_2[ ]; // 18.7
} _18_7_struct; } r18_7_struct;
void misra_18_8(int x) { void misra_18_8(int x) {
int buf1[10]; int buf1[10];
@ -688,6 +689,58 @@ union misra_19_2 { }; // 19.2
# def fun_2013(v) () // 20.13 # def fun_2013(v) () // 20.13
#endif #endif
#define _Incompatible 0xdeadbeef // 21.1
#define __Incompatible 0xdeadbeef // 21.1
#define __starts_with_lower 0xdeadbeef // 21.1
#define __MY_HEADER_ // 21.1
#define _starts_with_lower 1 // no warning
static int _file_scope_id_21_1 = 42; // no warning
static int _file_scope_id_21_1_fn() { return 42; } // no warning
static int __file_scope_id_21_1 = 42; // 21.1
static int __file_scope_id_21_1_fn() { return 42; } // 21.1
static int _File_scope_id_21_1 = 42; // 21.1
static int _File_scope_id_21_1_fn() { return 42; } // 21.1
int _external_scope_id_21_1 = 42; // 21.1
int _external_scope_id_21_1_fn() { return 42; } // 21.1
int __external_scope_id_21_1 = 42; // 21.1
int __external_scope_id_21_1_fn() { return 42; } // 21.1
int _External_scope_id_21_1 = 42; // 21.1
int _External_scope_id_21_1_fn() { return 42; } // 21.1
int errno = 42; // 21.1
int errno() { // 21.1
// TODO: 15.5 false positive
return 42; // 15.5
}
struct _struct_21_1 { int a; }; // 21.1
struct _Struct_21_1 { int a; }; // 21.1
struct __struct_21_1 { int a; }; // 21.1
typedef struct { int a; } _struct_21_1_t; // 21.1
typedef struct { int a; } _Struct_21_1_t; // 21.1
typedef struct { int a; } __struct_21_1_t; // 21.1
enum _enum_21_1 { ENUM211_1 }; // 21.1
enum _Enum_21_1 { ENUM211_2 }; // 21.1
enum __enum_21_1 { ENUM211_3 }; // 21.1
enum __enum_21_1 { ENUM211_3 }; // 21.1
typedef enum { ENUM211_4 } _enum_21_1_t; // 21.1
typedef enum { ENUM211_5 } _Enum_21_1_t; // 21.1
typedef enum { ENUM211_6 } __enum_21_1_t; // 21.1
enum enum_21_1_valid_id {
ENUM211_7,
_ENUM211_8, // 21.1
__ENUM211_9, // 21.1
_eNUM211_10, // 21.1
enum211_11
};
union _union_21_1 { int a; }; // 21.1 19.2
union _Union_21_1 { int a; }; // 21.1 19.2
union __union_21_1 { int a; }; // 21.1 19.2
typedef union { int a; } _union_21_1_t; // 21.1 19.2
typedef union { int a; } _Union_21_1_t; // 21.1 19.2
typedef union { int a; } __union_21_1_t; // 21.1 19.2
void misra_21_3() { void misra_21_3() {
p1=malloc(10); // 21.3 p1=malloc(10); // 21.3
p2=calloc(10); // 21.3 p2=calloc(10); // 21.3
@ -713,3 +766,14 @@ void misra_21_9() {
(void)bsearch(key,base,num,size,cmp); // 21.9 (void)bsearch(key,base,num,size,cmp); // 21.9
qsort(base,num,size,cmp); // 21.9 qsort(base,num,size,cmp); // 21.9
} }
void misra_21_12() {
int rc;
fexcept_t f; // 21.12
rc = feclearexcept(1); // 21.12
rc = fegetexceptflag(&f, 1); // 21.12
rc = feraiseexcept(1); // 21.12
rc = fesetexceptflag(&f, 1); // 21.12
rc = fetestexcept(1); // 21.12
}

View File

@ -3225,6 +3225,8 @@ void SymbolDatabase::printXml(std::ostream &out) const
else if (function->isImplicitlyVirtual()) else if (function->isImplicitlyVirtual())
out << " isImplicitlyVirtual=\"true\""; out << " isImplicitlyVirtual=\"true\"";
} }
if (function->isStatic())
out << " isStatic=\"true\"";
if (function->argCount() == 0U) if (function->argCount() == 0U)
out << "/>" << std::endl; out << "/>" << std::endl;
else { else {

View File

@ -221,6 +221,8 @@ private:
TEST_CASE(functionImplicitlyVirtual); TEST_CASE(functionImplicitlyVirtual);
TEST_CASE(functionStatic);
TEST_CASE(namespaces1); TEST_CASE(namespaces1);
TEST_CASE(namespaces2); TEST_CASE(namespaces2);
TEST_CASE(namespaces3); // #3854 - unknown macro TEST_CASE(namespaces3); // #3854 - unknown macro
@ -2287,6 +2289,14 @@ private:
ASSERT_EQUALS(true, function && function->isImplicitlyVirtual(false)); ASSERT_EQUALS(true, function && function->isImplicitlyVirtual(false));
} }
void functionStatic() {
GET_SYMBOL_DB("static void fs() { }");
(void)db;
const Function *func = db->scopeList.back().function;
ASSERT(func);
ASSERT(func->isStatic());
}
void namespaces1() { void namespaces1() {
GET_SYMBOL_DB("namespace fred {\n" GET_SYMBOL_DB("namespace fred {\n"
" namespace barney {\n" " namespace barney {\n"