diff --git a/addons/misra.py b/addons/misra.py index 4d9bd6fb9..00463fdac 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -850,6 +850,46 @@ def isNoReturnScope(tok): return False +# Return the token which the value is assigned to +def getAssignedVariableToken(valueToken): + if not valueToken: + return None + if not valueToken.astParent: + return None + operator = valueToken.astParent + if operator.isAssignmentOp: + return operator.astOperand1 + if operator.isArithmeticalOp: + return getAssignedVariableToken(operator) + return None + +# If the value is used as a return value, return the function definition +def getFunctionUsingReturnValue(valueToken): + if not valueToken: + return None + if not valueToken.astParent: + return None + operator = valueToken.astParent + if operator.str == 'return': + return operator.scope.function + if operator.isArithmeticalOp: + return getFunctionUsingReturnValue(operator) + return None + +# Return true if the token follows a specific sequence of token str values +def tokenFollowsSequence(token, sequence): + if not token: + return False + for i in reversed(sequence): + prev = token.previous + if not prev: + return False + if prev.str != i: + return False + token = prev + return True + + class Define: def __init__(self, directive): self.args = [] @@ -1353,6 +1393,45 @@ class MisraChecker: if compiled.match(tok.str): self.reportError(tok, 7, 3) + def misra_7_4(self, data): + # A string literal shall not be assigned to an object unless the object's type + # is constant. + def reportErrorIfVariableIsNotConst(variable, stringLiteral): + if variable.valueType: + if variable.valueType.constness != 1: + self.reportError(stringLiteral, 7, 4) + + for token in data.tokenlist: + if token.isString: + # Check normal variable assignment + variable = getAssignedVariableToken(token) + if variable: + reportErrorIfVariableIsNotConst(variable, token) + + # Check use as return value + function = getFunctionUsingReturnValue(token) + if function: + # "Primitive" test since there is no info available on return value type + if not tokenFollowsSequence(function.tokenDef, ['const', 'char', '*']): + self.reportError(token, 7, 4) + + # Check use as function parameter + if isFunctionCall(token) and token.astOperand1 and token.astOperand1.function: + functionDeclaration = token.astOperand1.function + parametersUsed = getArguments(token) + + if functionDeclaration and functionDeclaration.tokenDef: + if functionDeclaration.tokenDef.Id == token.astOperand1.Id: + # Token is not a function call, but it is the definition of the function + continue + + for i in range(len(parametersUsed)): + usedParameter = parametersUsed[i] + parameterDefinition = functionDeclaration.argument.get(i+1) + + if usedParameter.isString and parameterDefinition.nameToken: + reportErrorIfVariableIsNotConst(parameterDefinition.nameToken, usedParameter) + def misra_8_11(self, data): for var in data.variables: if var.isExtern and simpleMatch(var.nameToken.next, '[ ]') and var.nameToken.scope.type == 'Global': @@ -2958,6 +3037,7 @@ class MisraChecker: if cfgNumber == 0: self.executeCheck(701, self.misra_7_1, data.rawTokens) self.executeCheck(703, self.misra_7_3, data.rawTokens) + self.executeCheck(704, self.misra_7_4, cfg) self.executeCheck(811, self.misra_8_11, cfg) self.executeCheck(812, self.misra_8_12, cfg) if cfgNumber == 0: diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 7da34cc02..f0806bae2 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -233,6 +233,28 @@ void misra_7_3() { long double misra_7_3_e = 7.3l; //7.3 } +typedef const char* MISRA_7_4_CHAR_CONST; +MISRA_7_4_CHAR_CONST misra_7_4_return_const_type_def (void) { return "return_typedef_const"; } +char *misra_7_4_return_non_const (void) { return 1 + "return_non_const"; } // 7.4 18.4 +const char *misra_7_4_return_const (void) { return 1 + "return_const"; } // 18.4 + +void misra_7_4_const_call(int a, const char* b) { } // 2.7 +void misra_7_4_call(int a, char* b) { } // 2.7 + +void misra_7_4() +{ + const char *a = "text a"; + char* const b = "text_b"; // 7.4 + char *c = "text c"; // 7.4 + char *d = 1 + "text d"; // 7.4 18.4 + char *e = "text e" + 1 + 2; // 7.4 18.4 + char *f = 1 + "text f" + 2; // 7.4 18.4 + const wchar_t *g = "text_g"; + wchar_t *h = "text_h"; // 7.4 + + misra_7_4_const_call(1, ("text_const_call")); + misra_7_4_call(1, "text_call"); // 7.4 11.8 +} extern int a811[]; // 8.11