MISRA Rule 7.4 Check if variables assigned as string literals are const (#2866)
This commit is contained in:
parent
aad29ddb9a
commit
05b804d126
|
@ -850,6 +850,46 @@ def isNoReturnScope(tok):
|
||||||
return False
|
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:
|
class Define:
|
||||||
def __init__(self, directive):
|
def __init__(self, directive):
|
||||||
self.args = []
|
self.args = []
|
||||||
|
@ -1353,6 +1393,45 @@ class MisraChecker:
|
||||||
if compiled.match(tok.str):
|
if compiled.match(tok.str):
|
||||||
self.reportError(tok, 7, 3)
|
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):
|
def misra_8_11(self, data):
|
||||||
for var in data.variables:
|
for var in data.variables:
|
||||||
if var.isExtern and simpleMatch(var.nameToken.next, '[ ]') and var.nameToken.scope.type == 'Global':
|
if var.isExtern and simpleMatch(var.nameToken.next, '[ ]') and var.nameToken.scope.type == 'Global':
|
||||||
|
@ -2958,6 +3037,7 @@ class MisraChecker:
|
||||||
if cfgNumber == 0:
|
if cfgNumber == 0:
|
||||||
self.executeCheck(701, self.misra_7_1, data.rawTokens)
|
self.executeCheck(701, self.misra_7_1, data.rawTokens)
|
||||||
self.executeCheck(703, self.misra_7_3, 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(811, self.misra_8_11, cfg)
|
||||||
self.executeCheck(812, self.misra_8_12, cfg)
|
self.executeCheck(812, self.misra_8_12, cfg)
|
||||||
if cfgNumber == 0:
|
if cfgNumber == 0:
|
||||||
|
|
|
@ -233,6 +233,28 @@ void misra_7_3() {
|
||||||
long double misra_7_3_e = 7.3l; //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
|
extern int a811[]; // 8.11
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue