cppcheck/addons/misra.py

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)