#/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)