915 lines
14 KiB
Python
915 lines
14 KiB
Python
#/usr/bin/python
|
|
#
|
|
# MISRA checkers
|
|
#
|
|
# The goal is that this addon will check conformance against latest MISRA C standard.
|
|
#
|
|
# Example usage of this addon (scan a sourcefile main.cpp)
|
|
# cppcheck --dump main.cpp
|
|
# python misra.py main.cpp.dump
|
|
#
|
|
# Limitations: This addon is released as open source. Rule texts can't be freely
|
|
# distributed. https://www.misra.org.uk/forum/viewtopic.php?f=56&t=1189
|
|
#
|
|
#
|
|
|
|
import cppcheckdata
|
|
import sys
|
|
import re
|
|
|
|
def reportError(token, num):
|
|
sys.stderr.write(
|
|
'[' + token.file + ':' + str(token.linenr) + '] misra ' + str(num) + ' violation\n')
|
|
|
|
def hasSideEffects(expr):
|
|
if not expr:
|
|
return False
|
|
if expr.str in ['++', '--', '=']:
|
|
return True
|
|
# Todo: Check function calls
|
|
return hasSideEffects(expr.astOperand1) or hasSideEffects(expr.astOperand2)
|
|
|
|
def isPrimaryExpression(expr):
|
|
return expr and (expr.isName or expr.isNumber or (expr.str in ['!', '==', '!=', '<', '<=', '>', '>=', '&&', '||']))
|
|
|
|
|
|
|
|
# 1
|
|
# STATUS: Use compiler
|
|
def misra1(data):
|
|
return
|
|
|
|
# 2
|
|
# STATUS: ?
|
|
def misra2(data):
|
|
return
|
|
|
|
# 3
|
|
# STATUS: Done
|
|
def misra3check(token):
|
|
prev = token.previous
|
|
if not prev or prev.str != '{':
|
|
return True
|
|
prev = prev.previous
|
|
if not prev or prev.str != ')':
|
|
return True
|
|
prev = prev.link
|
|
if not prev or prev.str != '(':
|
|
return True
|
|
prev = prev.link
|
|
if not prev or not prev.isName or (prev in ['for','if','switch','while']):
|
|
return True
|
|
after = token.next
|
|
if not after or after.str != '(':
|
|
return True
|
|
after = after.link
|
|
if not after or after.str != ')':
|
|
return True
|
|
after = after.next
|
|
if not after or after.str != ';':
|
|
return True
|
|
after = after.next
|
|
if not after or after.str != '}':
|
|
return True
|
|
return False
|
|
|
|
def misra3(data):
|
|
for token in data.tokenlist:
|
|
if token.str != 'asm':
|
|
continue
|
|
if misra3check(token):
|
|
reportError(token, 3)
|
|
|
|
# 4
|
|
# STATUS: Done. Checked by Cppcheck
|
|
def misra4(data):
|
|
return
|
|
|
|
# 5
|
|
# STATUS: TODO
|
|
def misra5(data):
|
|
return
|
|
|
|
# 6
|
|
# STATUS: TODO
|
|
def misra6(data):
|
|
return
|
|
|
|
# 7
|
|
# STATUS: TODO - requires some info from preprocessor
|
|
def misra7(data):
|
|
return
|
|
|
|
# 8
|
|
# STATUS: TODO
|
|
def misra8(data):
|
|
return
|
|
|
|
# 9
|
|
# STATUS: TODO
|
|
def misra9(data):
|
|
return
|
|
|
|
# 10
|
|
# STATUS: TODO (Parse comments?)
|
|
def misra10(data):
|
|
return
|
|
|
|
# Identifiers
|
|
# -----------
|
|
|
|
# 11
|
|
# STATUS: Done.
|
|
def misra11(data):
|
|
for token in data.tokenlist:
|
|
if token.isName and len(token.str) > 31:
|
|
reportError(token, 11)
|
|
|
|
# 12
|
|
# STATUS: Done. Use compiler (-Wshadow etc)
|
|
def misra12(data):
|
|
return
|
|
|
|
# 13
|
|
# STATUS: TODO originalName is missing right now
|
|
def misra13(data):
|
|
for token in data.tokenlist:
|
|
if not token in ['char','short','int','long','float','double']:
|
|
continue
|
|
#if token.originalName != '':
|
|
|
|
# 14
|
|
# STATUS: Done
|
|
def misra14(data):
|
|
for token in data.tokenlist:
|
|
if token.str != 'char':
|
|
continue
|
|
if token.isUnsigned or token.isSigned:
|
|
continue
|
|
reportError(token, 14)
|
|
|
|
# 15
|
|
# STATUS: Done
|
|
def misra15(data):
|
|
reportError(data.tokenlist[0], 15)
|
|
|
|
# 16
|
|
# STATUS: TODO : ValueType information is needed
|
|
def misra16(data):
|
|
return
|
|
|
|
# 17
|
|
# STATUS: Done (Cppcheck duplicateTypedef)
|
|
def misra17(data):
|
|
return
|
|
|
|
# 18
|
|
# STATUS: TODO
|
|
def misra18(data):
|
|
return
|
|
|
|
# 19
|
|
# STATUS: Done
|
|
def misra19(rawTokens):
|
|
for tok in rawTokens:
|
|
if re.match(r'0[0-7]+', tok.str):
|
|
reportError(tok, 19)
|
|
|
|
# 20
|
|
# STATUS: Use compiler
|
|
def misra20(data):
|
|
return
|
|
|
|
# 21
|
|
# STATUS: Done. Use compiler (-Wshadow etc). Cppcheck has some checking also.
|
|
def misra21(data):
|
|
return
|
|
|
|
# 22
|
|
# STATUS: TODO
|
|
def misra22(data):
|
|
return
|
|
|
|
# 23
|
|
# STATUS: TODO
|
|
def misra23(data):
|
|
return
|
|
|
|
# 24
|
|
# STATUS: Probably done. Use compiler.
|
|
def misra24(data):
|
|
return
|
|
|
|
# 25
|
|
# STATUS: TODO
|
|
def misra25(data):
|
|
return
|
|
|
|
# 26
|
|
# STATUS: Done. Use compiler.
|
|
def misra26(data):
|
|
return
|
|
|
|
# 27
|
|
# STATUS: TODO
|
|
def misra27(data):
|
|
return
|
|
|
|
# 28
|
|
# STATUS: Done
|
|
def misra28(rawTokens):
|
|
for token in rawTokens:
|
|
if token.str == 'register':
|
|
reportError(token, 28)
|
|
|
|
# 29
|
|
# STATUS: TODO
|
|
def misra29(data):
|
|
return
|
|
|
|
# 30
|
|
# STATUS: Done. Cppcheck uninitVar etc..
|
|
def misra30(data):
|
|
return
|
|
|
|
# 31
|
|
# STATUS: TODO
|
|
def misra31(data):
|
|
return
|
|
|
|
# 32
|
|
# STATUS: Done
|
|
def misra32(data):
|
|
for token in data.tokenlist:
|
|
if token.str != 'enum':
|
|
continue
|
|
|
|
# Goto start '{'
|
|
tok = token.next
|
|
if tok and tok.isName:
|
|
tok = tok.next
|
|
if not tok or tok.str != '{':
|
|
continue
|
|
|
|
# Parse enum body and remember which members are assigned
|
|
eqList = []
|
|
eq = False
|
|
tok = tok.next
|
|
while tok and tok.str != '}':
|
|
if tok.str == '=':
|
|
eq = True
|
|
elif tok.str == ',':
|
|
eqList.append(eq)
|
|
eq = False
|
|
elif tok.link and (tok.str in ['(','[','{','<']):
|
|
tok = tok.link
|
|
tok = tok.next
|
|
eqList.append(eq)
|
|
|
|
# is there error?
|
|
if len(eqList) <= 1:
|
|
continue
|
|
err = False
|
|
if eqList[0] and eqList[1]:
|
|
err = (False in eqList[1:])
|
|
else:
|
|
err = (True in eqList[1:])
|
|
if err:
|
|
reportError(token, 32)
|
|
|
|
|
|
# 33
|
|
# STATUS: Done
|
|
def misra33(data):
|
|
for token in data.tokenlist:
|
|
if token.isLogicalOp and hasSideEffects(token.astOperand2):
|
|
reportError(token, 33)
|
|
|
|
# 34
|
|
# STATUS: Done
|
|
def misra34(data):
|
|
for token in data.tokenlist:
|
|
if not token.isLogicalOp:
|
|
continue
|
|
if not isPrimaryExpression(token.astOperand1) or not isPrimaryExpression(token.astOperand2):
|
|
reportError(token, 34)
|
|
|
|
# 35
|
|
# STATUS: TODO (The ValueType is not available yet)
|
|
def misra35(data):
|
|
return
|
|
|
|
# 36
|
|
# STATUS: Done. Cppcheck bitwise op checkers.
|
|
def misra36(data):
|
|
return
|
|
|
|
# 37
|
|
# STATUS: TODO The ValueType information is not available yet
|
|
def misra37(data):
|
|
return
|
|
|
|
# 38
|
|
# STATUS: Done. Cppcheck, compilers.
|
|
def misra38(data):
|
|
return
|
|
|
|
# 39
|
|
# STATUS: TODO (ValueType information is needed)
|
|
def misra39(data):
|
|
return
|
|
|
|
# 40
|
|
# STATUS: Done. Cppcheck
|
|
def misra40(data):
|
|
return
|
|
|
|
# 41
|
|
# STATUS: Done
|
|
def misra41(data):
|
|
reportError(data.tokenlist[0], 41)
|
|
|
|
# 42
|
|
# STATUS: TODO
|
|
def misra42(data):
|
|
return
|
|
|
|
# 43
|
|
# STATUS: Done. Cppcheck, Compiler
|
|
def misra43(data):
|
|
return
|
|
|
|
# 44
|
|
# STATUS: TODO
|
|
def misra44(data):
|
|
return
|
|
|
|
# 45
|
|
# STATUS: TODO
|
|
def misra45(data):
|
|
return
|
|
|
|
# 46
|
|
# STATUS: TODO (should be implemented in Cppcheck)
|
|
def misra46(data):
|
|
return
|
|
|
|
# 47
|
|
# STATUS: TODO
|
|
def misra47(data):
|
|
return
|
|
|
|
# 48
|
|
# STATUS: TODO
|
|
def misra48(data):
|
|
return
|
|
|
|
# 49
|
|
# STATUS: TODO
|
|
def misra49(data):
|
|
return
|
|
|
|
# 50
|
|
# STATUS: Done. Compiler
|
|
def misra50(data):
|
|
return
|
|
|
|
# 51
|
|
# STATUS: TODO (ValueType information is needed)
|
|
def misra51(data):
|
|
return
|
|
|
|
# 52
|
|
# STATUS: Done. Cppcheck (condition is always true, unreachable return, etc)
|
|
def misra52(data):
|
|
return
|
|
|
|
# 53
|
|
# STATUS: Done. Cppcheck (useless code, unchecked result)
|
|
def misra53(data):
|
|
return
|
|
|
|
# 54
|
|
# STATUS: TODO
|
|
def misra54(data):
|
|
return
|
|
|
|
# 55
|
|
# STATUS: TODO
|
|
def misra55(data):
|
|
return
|
|
|
|
# 56
|
|
# STATUS: Done.
|
|
def misra56(data):
|
|
for token in data.tokenlist:
|
|
if token.str == "goto":
|
|
reportError(token, 56)
|
|
|
|
# 57
|
|
# STATUS: Done.
|
|
def misra57(data):
|
|
for token in data.tokenlist:
|
|
if token.str == "continue":
|
|
reportError(token, 57)
|
|
|
|
# 58
|
|
# STATUS: TODO
|
|
def misra58(data):
|
|
for token in data.tokenlist:
|
|
if token.str != "break":
|
|
continue
|
|
s = token.scope
|
|
while s and s.type == 'If':
|
|
s = s.nestedIn
|
|
if s and s.type in ['While', 'For']:
|
|
reportError(token, 58)
|
|
|
|
# 59
|
|
# STATUS: TODO
|
|
def misra59(data):
|
|
return
|
|
|
|
# 60
|
|
# STATUS: TODO
|
|
def misra60(data):
|
|
return
|
|
|
|
# 61
|
|
# STATUS: TODO
|
|
def misra61(data):
|
|
return
|
|
|
|
# 62
|
|
# STATUS: Done. Compiler.
|
|
def misra62(data):
|
|
return
|
|
|
|
# 63
|
|
# STATUS: TODO
|
|
def misra63(data):
|
|
return
|
|
|
|
# 64
|
|
# STATUS: TODO
|
|
def misra64(data):
|
|
return
|
|
|
|
# 65
|
|
# STATUS: TODO
|
|
def misra65(data):
|
|
return
|
|
|
|
# 66
|
|
# STATUS: TODO
|
|
def misra66(data):
|
|
return
|
|
|
|
# 67
|
|
# STATUS: TODO
|
|
def misra67(data):
|
|
return
|
|
|
|
# 68
|
|
# STATUS: TODO
|
|
def misra68(data):
|
|
return
|
|
|
|
# 69
|
|
# STATUS: TODO
|
|
def misra69(data):
|
|
return
|
|
|
|
# 70
|
|
# STATUS: TODO
|
|
def misra70(data):
|
|
return
|
|
|
|
# 71
|
|
# STATUS: Done. Compilers warn about mismatches.
|
|
def misra71(data):
|
|
return
|
|
|
|
# 72
|
|
# STATUS: TODO
|
|
def misra72(data):
|
|
return
|
|
|
|
# 73
|
|
# STATUS: TODO
|
|
def misra73(data):
|
|
return
|
|
|
|
# 74
|
|
# STATUS: Done. Cppcheck builtin checker
|
|
def misra74(data):
|
|
return
|
|
|
|
# 75
|
|
# STATUS: Done. Should be checked by compilers.
|
|
def misra75(data):
|
|
return
|
|
|
|
# 76
|
|
# STATUS: TODO
|
|
def misra76(data):
|
|
return
|
|
|
|
# 77
|
|
# STATUS: TODO
|
|
def misra77(data):
|
|
return
|
|
|
|
# 78
|
|
# STATUS: TODO
|
|
def misra78(data):
|
|
return
|
|
|
|
# 79
|
|
# STATUS: Done. Compilers
|
|
def misra79(data):
|
|
return
|
|
|
|
# 80
|
|
# STATUS: Done. Compilers
|
|
def misra80(data):
|
|
return
|
|
|
|
# 81
|
|
# STATUS: TODO
|
|
def misra81(data):
|
|
return
|
|
|
|
# 82
|
|
# STATUS: TODO
|
|
def misra82(data):
|
|
return
|
|
|
|
# 83
|
|
# STATUS: TODO
|
|
def misra83(data):
|
|
return
|
|
|
|
# 84
|
|
# STATUS: TODO
|
|
def misra84(data):
|
|
return
|
|
|
|
# 85
|
|
# STATUS: TODO
|
|
def misra85(data):
|
|
return
|
|
|
|
# 86
|
|
# STATUS: TODO
|
|
def misra86(data):
|
|
return
|
|
|
|
# 87
|
|
# STATUS: TODO
|
|
def misra87(data):
|
|
return
|
|
|
|
# 88
|
|
# STATUS: TODO
|
|
def misra88(data):
|
|
return
|
|
|
|
# 89
|
|
# STATUS: TODO
|
|
def misra89(data):
|
|
return
|
|
|
|
# 90
|
|
# STATUS: TODO
|
|
def misra90(data):
|
|
return
|
|
|
|
# 91
|
|
# STATUS: TODO
|
|
def misra91(data):
|
|
return
|
|
|
|
# 92
|
|
# STATUS: TODO
|
|
def misra92(data):
|
|
return
|
|
|
|
# 93
|
|
# STATUS: TODO
|
|
def misra93(data):
|
|
return
|
|
|
|
# 94
|
|
# STATUS: TODO
|
|
def misra94(data):
|
|
return
|
|
|
|
# 95
|
|
# STATUS: TODO
|
|
def misra95(data):
|
|
return
|
|
|
|
# 96
|
|
# STATUS: TODO
|
|
def misra96(data):
|
|
return
|
|
|
|
# 97
|
|
# STATUS: TODO
|
|
def misra97(data):
|
|
return
|
|
|
|
# 98
|
|
# STATUS: TODO
|
|
def misra98(data):
|
|
return
|
|
|
|
# 99
|
|
# STATUS: TODO
|
|
def misra99(data):
|
|
return
|
|
|
|
# 100
|
|
# STATUS: TODO
|
|
def misra100(data):
|
|
return
|
|
|
|
# 101
|
|
# STATUS: TODO
|
|
def misra101(data):
|
|
return
|
|
|
|
# 102
|
|
# STATUS: TODO
|
|
def misra102(data):
|
|
return
|
|
|
|
# 103
|
|
# STATUS: TODO
|
|
def misra103(data):
|
|
return
|
|
|
|
# 104
|
|
# STATUS: TODO
|
|
def misra104(data):
|
|
return
|
|
|
|
# 105
|
|
# STATUS: TODO
|
|
def misra105(data):
|
|
return
|
|
|
|
# 106
|
|
# STATUS: TODO
|
|
def misra106(data):
|
|
return
|
|
|
|
# 107
|
|
# STATUS: Cppcheck has this checking
|
|
def misra107(data):
|
|
return
|
|
|
|
# 108
|
|
# STATUS: TODO
|
|
def misra108(data):
|
|
return
|
|
|
|
# 109
|
|
# STATUS: TODO
|
|
def misra109(data):
|
|
return
|
|
|
|
# 110
|
|
# STATUS: TODO
|
|
def misra110(data):
|
|
return
|
|
|
|
# 111
|
|
# STATUS: TODO
|
|
def misra111(data):
|
|
return
|
|
|
|
# 112
|
|
# STATUS: TODO
|
|
def misra112(data):
|
|
return
|
|
|
|
# 113
|
|
# STATUS: TODO
|
|
def misra113(data):
|
|
return
|
|
|
|
# 114
|
|
# STATUS: TODO
|
|
def misra114(data):
|
|
return
|
|
|
|
# 115
|
|
# STATUS: TODO
|
|
def misra115(data):
|
|
return
|
|
|
|
# 116
|
|
# STATUS: TODO
|
|
def misra116(data):
|
|
return
|
|
|
|
# 117
|
|
# STATUS: Cppcheck (--library)
|
|
def misra117(data):
|
|
return
|
|
|
|
# 118
|
|
# STATUS: TODO
|
|
def misra118(data):
|
|
return
|
|
|
|
# 119
|
|
# STATUS: TODO
|
|
def misra119(data):
|
|
return
|
|
|
|
# 120
|
|
# STATUS: TODO
|
|
def misra120(data):
|
|
return
|
|
|
|
# 121
|
|
# STATUS: TODO
|
|
def misra121(data):
|
|
return
|
|
|
|
# 122
|
|
# STATUS: TODO
|
|
def misra122(data):
|
|
return
|
|
|
|
# 123
|
|
# STATUS: TODO
|
|
def misra123(data):
|
|
return
|
|
|
|
# 124
|
|
# STATUS: TODO
|
|
def misra124(data):
|
|
return
|
|
|
|
# 125
|
|
# STATUS: TODO
|
|
def misra125(data):
|
|
return
|
|
|
|
# 126
|
|
# STATUS: TODO
|
|
def misra126(data):
|
|
return
|
|
|
|
# 127
|
|
# STATUS: TODO
|
|
def misra127(data):
|
|
return
|
|
|
|
|
|
for arg in sys.argv[1:]:
|
|
print('Checking ' + arg + '...')
|
|
data = cppcheckdata.parsedump(arg)
|
|
|
|
cfgNumber = 0
|
|
|
|
for cfg in data.configurations:
|
|
cfgNumber = cfgNumber + 1
|
|
if len(data.configurations) > 1:
|
|
print('Checking ' + arg + ', config "' + cfg.name + '"...')
|
|
misra1(cfg)
|
|
misra2(cfg)
|
|
misra3(cfg)
|
|
misra4(cfg)
|
|
misra5(cfg)
|
|
misra6(cfg)
|
|
misra7(cfg)
|
|
misra8(cfg)
|
|
misra9(cfg)
|
|
misra10(cfg)
|
|
misra11(cfg)
|
|
misra12(cfg)
|
|
misra13(cfg)
|
|
misra14(cfg)
|
|
misra15(cfg)
|
|
misra16(cfg)
|
|
misra17(cfg)
|
|
misra18(cfg)
|
|
if cfgNumber == 1:
|
|
misra19(data.rawTokens)
|
|
misra20(cfg)
|
|
misra21(cfg)
|
|
misra22(cfg)
|
|
misra23(cfg)
|
|
misra24(cfg)
|
|
misra25(cfg)
|
|
misra26(cfg)
|
|
misra27(cfg)
|
|
if cfgNumber == 1:
|
|
misra28(data.rawTokens)
|
|
misra29(cfg)
|
|
misra30(cfg)
|
|
misra31(cfg)
|
|
misra32(cfg)
|
|
misra33(cfg)
|
|
misra34(cfg)
|
|
misra35(cfg)
|
|
misra36(cfg)
|
|
misra37(cfg)
|
|
misra38(cfg)
|
|
misra39(cfg)
|
|
misra40(cfg)
|
|
misra41(cfg)
|
|
misra42(cfg)
|
|
misra43(cfg)
|
|
misra44(cfg)
|
|
misra45(cfg)
|
|
misra46(cfg)
|
|
misra47(cfg)
|
|
misra48(cfg)
|
|
misra49(cfg)
|
|
misra50(cfg)
|
|
misra51(cfg)
|
|
misra52(cfg)
|
|
misra53(cfg)
|
|
misra54(cfg)
|
|
misra55(cfg)
|
|
misra56(cfg)
|
|
misra57(cfg)
|
|
misra58(cfg)
|
|
misra59(cfg)
|
|
misra60(cfg)
|
|
misra61(cfg)
|
|
misra62(cfg)
|
|
misra63(cfg)
|
|
misra64(cfg)
|
|
misra65(cfg)
|
|
misra66(cfg)
|
|
misra67(cfg)
|
|
misra68(cfg)
|
|
misra69(cfg)
|
|
misra70(cfg)
|
|
misra71(cfg)
|
|
misra72(cfg)
|
|
misra73(cfg)
|
|
misra74(cfg)
|
|
misra75(cfg)
|
|
misra76(cfg)
|
|
misra77(cfg)
|
|
misra78(cfg)
|
|
misra79(cfg)
|
|
misra80(cfg)
|
|
misra81(cfg)
|
|
misra82(cfg)
|
|
misra83(cfg)
|
|
misra84(cfg)
|
|
misra85(cfg)
|
|
misra86(cfg)
|
|
misra87(cfg)
|
|
misra88(cfg)
|
|
misra89(cfg)
|
|
misra90(cfg)
|
|
misra91(cfg)
|
|
misra92(cfg)
|
|
misra93(cfg)
|
|
misra94(cfg)
|
|
misra95(cfg)
|
|
misra96(cfg)
|
|
misra97(cfg)
|
|
misra98(cfg)
|
|
misra99(cfg)
|
|
misra100(cfg)
|
|
misra101(cfg)
|
|
misra102(cfg)
|
|
misra103(cfg)
|
|
misra104(cfg)
|
|
misra105(cfg)
|
|
misra106(cfg)
|
|
misra107(cfg)
|
|
misra108(cfg)
|
|
misra109(cfg)
|
|
misra110(cfg)
|
|
misra111(cfg)
|
|
misra112(cfg)
|
|
misra113(cfg)
|
|
misra114(cfg)
|
|
misra115(cfg)
|
|
misra116(cfg)
|
|
misra117(cfg)
|
|
misra118(cfg)
|
|
misra119(cfg)
|
|
misra120(cfg)
|
|
misra121(cfg)
|
|
misra122(cfg)
|
|
misra123(cfg)
|
|
misra124(cfg)
|
|
misra125(cfg)
|
|
misra126(cfg)
|
|
misra127(cfg)
|
|
|
|
|