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 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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue