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

View File

@ -1937,6 +1937,38 @@ class MisraChecker:
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):
for token in data.tokenlist:
if isFunctionCall(token) and (token.astOperand1.str in ('malloc', 'calloc', 'realloc', 'free')):
@ -1998,6 +2030,20 @@ class MisraChecker:
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):
"""Return the list of expected violations in the verify test"""
return self.verify_expected
@ -2495,6 +2541,7 @@ class MisraChecker:
self.misra_20_10(cfg)
self.misra_20_13(cfg)
self.misra_20_14(cfg)
self.misra_21_1(cfg)
self.misra_21_3(cfg)
self.misra_21_4(cfg)
self.misra_21_5(cfg)
@ -2504,6 +2551,7 @@ class MisraChecker:
self.misra_21_9(cfg)
self.misra_21_10(cfg)
self.misra_21_11(cfg)
self.misra_21_12(cfg)
# 22.4 is already covered by Cppcheck writeReadOnlyFile

View File

@ -11,6 +11,7 @@
#include <wchar.h> //21.6
#include <time.h> // 21.10
#include <tgmath.h> // 21.11
#include <fenv.h>
typedef unsigned char u8;
@ -395,7 +396,7 @@ void misra_14_2() {
struct {
unsigned int x:1;
unsigned int y:1;
} _14_4_struct;
} r14_4_struct;
void misra_14_4(bool b) {
if (x+4){} // 14.4
else {}
@ -403,7 +404,7 @@ void misra_14_4(bool b) {
if (b) {}
else {}
if (_14_4_struct.x) {}
if (r14_4_struct.x) {}
}
void misra_15_1() {
@ -652,12 +653,12 @@ struct {
} nested_2;
uint8_t data_3[]; // 18.7
} nested_3;
} _18_7_struct;
} r18_7_struct;
struct {
uint16_t len;
uint8_t data_1[ 19 ];
uint8_t data_2[ ]; // 18.7
} _18_7_struct;
} r18_7_struct;
void misra_18_8(int x) {
int buf1[10];
@ -688,6 +689,58 @@ union misra_19_2 { }; // 19.2
# def fun_2013(v) () // 20.13
#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() {
p1=malloc(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
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())
out << " isImplicitlyVirtual=\"true\"";
}
if (function->isStatic())
out << " isStatic=\"true\"";
if (function->argCount() == 0U)
out << "/>" << std::endl;
else {

View File

@ -221,6 +221,8 @@ private:
TEST_CASE(functionImplicitlyVirtual);
TEST_CASE(functionStatic);
TEST_CASE(namespaces1);
TEST_CASE(namespaces2);
TEST_CASE(namespaces3); // #3854 - unknown macro
@ -2287,6 +2289,14 @@ private:
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() {
GET_SYMBOL_DB("namespace fred {\n"
" namespace barney {\n"