const variables/parameters; Improved check to handle pointers also (misra 8.13)
This commit is contained in:
parent
5f548a4b6c
commit
eb9a251a4c
|
@ -1452,6 +1452,54 @@ void CheckOther::checkConstVariable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::checkConstPointer()
|
||||||
|
{
|
||||||
|
if (!mSettings->severity.isEnabled(Severity::style))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::set<const Variable *> pointers;
|
||||||
|
std::set<const Variable *> nonConstPointers;
|
||||||
|
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
|
||||||
|
if (!tok->variable())
|
||||||
|
continue;
|
||||||
|
if (tok == tok->variable()->nameToken())
|
||||||
|
continue;
|
||||||
|
if (!tok->valueType())
|
||||||
|
continue;
|
||||||
|
if (tok->valueType()->pointer == 0 || tok->valueType()->constness > 0)
|
||||||
|
continue;
|
||||||
|
if (nonConstPointers.find(tok->variable()) != nonConstPointers.end())
|
||||||
|
continue;
|
||||||
|
pointers.insert(tok->variable());
|
||||||
|
bool nonConst = true;
|
||||||
|
const Token *parent = tok->astParent();
|
||||||
|
bool deref = false;
|
||||||
|
if (parent && parent->isUnaryOp("*"))
|
||||||
|
deref = true;
|
||||||
|
else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok)
|
||||||
|
deref = true;
|
||||||
|
if (deref) {
|
||||||
|
while (Token::Match(parent->astParent(), "%cop%") && parent->astParent()->isBinaryOp())
|
||||||
|
parent = parent->astParent();
|
||||||
|
if (Token::simpleMatch(parent->astParent(), "return"))
|
||||||
|
nonConst = false;
|
||||||
|
else if (Token::Match(parent->astParent(), "%assign%") && parent == parent->astParent()->astOperand2()) {
|
||||||
|
bool takingRef = false;
|
||||||
|
const Token *lhs = parent->astParent()->astOperand1();
|
||||||
|
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs)
|
||||||
|
takingRef = true;
|
||||||
|
nonConst = takingRef;
|
||||||
|
} else if (Token::simpleMatch(parent->astParent(), "[") && parent->astParent()->astOperand2() == parent)
|
||||||
|
nonConst = false;
|
||||||
|
}
|
||||||
|
if (nonConst)
|
||||||
|
nonConstPointers.insert(tok->variable());
|
||||||
|
}
|
||||||
|
for (const Variable *p: pointers) {
|
||||||
|
if (nonConstPointers.find(p) == nonConstPointers.end())
|
||||||
|
constVariableError(p, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
void CheckOther::constVariableError(const Variable *var, const Function *function)
|
void CheckOther::constVariableError(const Variable *var, const Function *function)
|
||||||
{
|
{
|
||||||
const std::string vartype((var && var->isArgument()) ? "Parameter" : "Variable");
|
const std::string vartype((var && var->isArgument()) ? "Parameter" : "Variable");
|
||||||
|
|
|
@ -95,6 +95,7 @@ public:
|
||||||
checkOther.clarifyCalculation();
|
checkOther.clarifyCalculation();
|
||||||
checkOther.checkPassByReference();
|
checkOther.checkPassByReference();
|
||||||
checkOther.checkConstVariable();
|
checkOther.checkConstVariable();
|
||||||
|
checkOther.checkConstPointer();
|
||||||
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
|
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
|
||||||
checkOther.checkInvalidFree();
|
checkOther.checkInvalidFree();
|
||||||
checkOther.clarifyStatement();
|
checkOther.clarifyStatement();
|
||||||
|
@ -135,6 +136,7 @@ public:
|
||||||
void checkPassByReference();
|
void checkPassByReference();
|
||||||
|
|
||||||
void checkConstVariable();
|
void checkConstVariable();
|
||||||
|
void checkConstPointer();
|
||||||
|
|
||||||
/** @brief Using char variable as array index / as operand in bit operation */
|
/** @brief Using char variable as array index / as operand in bit operation */
|
||||||
void checkCharVariable();
|
void checkCharVariable();
|
||||||
|
|
|
@ -99,6 +99,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(constVariable);
|
TEST_CASE(constVariable);
|
||||||
TEST_CASE(constParameterCallback);
|
TEST_CASE(constParameterCallback);
|
||||||
|
TEST_CASE(constPointer);
|
||||||
|
|
||||||
TEST_CASE(switchRedundantAssignmentTest);
|
TEST_CASE(switchRedundantAssignmentTest);
|
||||||
TEST_CASE(switchRedundantOperationTest);
|
TEST_CASE(switchRedundantOperationTest);
|
||||||
|
@ -2631,6 +2632,29 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:13]: (style) Parameter 'signal' can be declared with const. However it seems that 'signalEvent' is a callback function, if 'signal' is declared with const you might also need to cast function pointer(s).\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:13]: (style) Parameter 'signal' can be declared with const. However it seems that 'signalEvent' is a callback function, if 'signal' is declared with const you might also need to cast function pointer(s).\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void constPointer() {
|
||||||
|
check("void foo(int *p) { return *p; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(int *p) { x = *p; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(int *p) { int &ref = *p; ref = 12; }");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void foo(int *p) { x = *p + 10; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(int *p) { return p[10]; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(int *p) { int &ref = p[0]; ref = 12; }");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void foo(int *p) { x[*p] = 12; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void switchRedundantAssignmentTest() {
|
void switchRedundantAssignmentTest() {
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -5667,7 +5691,7 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
check("void test(int * p, int * q) {\n"
|
check("void test(const int * p, const int * q) {\n"
|
||||||
" int i = *p;\n"
|
" int i = *p;\n"
|
||||||
" int j = *p;\n"
|
" int j = *p;\n"
|
||||||
"}");
|
"}");
|
||||||
|
@ -5795,7 +5819,7 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:4]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:4]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'.\n", errout.str());
|
||||||
|
|
||||||
check("void test(int * p) {\n"
|
check("void test(const int * p) {\n"
|
||||||
" int i = *p;\n"
|
" int i = *p;\n"
|
||||||
" int j = *p;\n"
|
" int j = *p;\n"
|
||||||
"}");
|
"}");
|
||||||
|
@ -8160,7 +8184,7 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (style) Redundant pointer operation on 'y' - it's already a pointer.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (style) Redundant pointer operation on 'y' - it's already a pointer.\n", errout.str());
|
||||||
|
|
||||||
// no warning for bitwise AND
|
// no warning for bitwise AND
|
||||||
check("void f(int *b) {\n"
|
check("void f(const int *b) {\n"
|
||||||
" int x = 0x20 & *b;\n"
|
" int x = 0x20 & *b;\n"
|
||||||
"}\n", nullptr, false, true);
|
"}\n", nullptr, false, true);
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
Loading…
Reference in New Issue