Skip to content

Commit eb9a251

Browse files
committed
const variables/parameters; Improved check to handle pointers also (misra 8.13)
1 parent 5f548a4 commit eb9a251

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

lib/checkother.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,54 @@ void CheckOther::checkConstVariable()
14521452
}
14531453
}
14541454

1455+
void CheckOther::checkConstPointer()
1456+
{
1457+
if (!mSettings->severity.isEnabled(Severity::style))
1458+
return;
1459+
1460+
std::set<const Variable *> pointers;
1461+
std::set<const Variable *> nonConstPointers;
1462+
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
1463+
if (!tok->variable())
1464+
continue;
1465+
if (tok == tok->variable()->nameToken())
1466+
continue;
1467+
if (!tok->valueType())
1468+
continue;
1469+
if (tok->valueType()->pointer == 0 || tok->valueType()->constness > 0)
1470+
continue;
1471+
if (nonConstPointers.find(tok->variable()) != nonConstPointers.end())
1472+
continue;
1473+
pointers.insert(tok->variable());
1474+
bool nonConst = true;
1475+
const Token *parent = tok->astParent();
1476+
bool deref = false;
1477+
if (parent && parent->isUnaryOp("*"))
1478+
deref = true;
1479+
else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok)
1480+
deref = true;
1481+
if (deref) {
1482+
while (Token::Match(parent->astParent(), "%cop%") && parent->astParent()->isBinaryOp())
1483+
parent = parent->astParent();
1484+
if (Token::simpleMatch(parent->astParent(), "return"))
1485+
nonConst = false;
1486+
else if (Token::Match(parent->astParent(), "%assign%") && parent == parent->astParent()->astOperand2()) {
1487+
bool takingRef = false;
1488+
const Token *lhs = parent->astParent()->astOperand1();
1489+
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs)
1490+
takingRef = true;
1491+
nonConst = takingRef;
1492+
} else if (Token::simpleMatch(parent->astParent(), "[") && parent->astParent()->astOperand2() == parent)
1493+
nonConst = false;
1494+
}
1495+
if (nonConst)
1496+
nonConstPointers.insert(tok->variable());
1497+
}
1498+
for (const Variable *p: pointers) {
1499+
if (nonConstPointers.find(p) == nonConstPointers.end())
1500+
constVariableError(p, nullptr);
1501+
}
1502+
}
14551503
void CheckOther::constVariableError(const Variable *var, const Function *function)
14561504
{
14571505
const std::string vartype((var && var->isArgument()) ? "Parameter" : "Variable");

lib/checkother.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class CPPCHECKLIB CheckOther : public Check {
9595
checkOther.clarifyCalculation();
9696
checkOther.checkPassByReference();
9797
checkOther.checkConstVariable();
98+
checkOther.checkConstPointer();
9899
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
99100
checkOther.checkInvalidFree();
100101
checkOther.clarifyStatement();
@@ -135,6 +136,7 @@ class CPPCHECKLIB CheckOther : public Check {
135136
void checkPassByReference();
136137

137138
void checkConstVariable();
139+
void checkConstPointer();
138140

139141
/** @brief Using char variable as array index / as operand in bit operation */
140142
void checkCharVariable();

test/testother.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class TestOther : public TestFixture {
9999

100100
TEST_CASE(constVariable);
101101
TEST_CASE(constParameterCallback);
102+
TEST_CASE(constPointer);
102103

103104
TEST_CASE(switchRedundantAssignmentTest);
104105
TEST_CASE(switchRedundantOperationTest);
@@ -2631,6 +2632,29 @@ class TestOther : public TestFixture {
26312632
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());
26322633
}
26332634

2635+
void constPointer() {
2636+
check("void foo(int *p) { return *p; }");
2637+
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2638+
2639+
check("void foo(int *p) { x = *p; }");
2640+
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2641+
2642+
check("void foo(int *p) { int &ref = *p; ref = 12; }");
2643+
ASSERT_EQUALS("", errout.str());
2644+
2645+
check("void foo(int *p) { x = *p + 10; }");
2646+
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2647+
2648+
check("void foo(int *p) { return p[10]; }");
2649+
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2650+
2651+
check("void foo(int *p) { int &ref = p[0]; ref = 12; }");
2652+
ASSERT_EQUALS("", errout.str());
2653+
2654+
check("void foo(int *p) { x[*p] = 12; }");
2655+
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2656+
}
2657+
26342658
void switchRedundantAssignmentTest() {
26352659
check("void foo()\n"
26362660
"{\n"
@@ -5667,7 +5691,7 @@ class TestOther : public TestFixture {
56675691
"}");
56685692
ASSERT_EQUALS("", errout.str());
56695693

5670-
check("void test(int * p, int * q) {\n"
5694+
check("void test(const int * p, const int * q) {\n"
56715695
" int i = *p;\n"
56725696
" int j = *p;\n"
56735697
"}");
@@ -5795,7 +5819,7 @@ class TestOther : public TestFixture {
57955819
"}");
57965820
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:4]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'.\n", errout.str());
57975821

5798-
check("void test(int * p) {\n"
5822+
check("void test(const int * p) {\n"
57995823
" int i = *p;\n"
58005824
" int j = *p;\n"
58015825
"}");
@@ -8160,7 +8184,7 @@ class TestOther : public TestFixture {
81608184
ASSERT_EQUALS("[test.cpp:2]: (style) Redundant pointer operation on 'y' - it's already a pointer.\n", errout.str());
81618185

81628186
// no warning for bitwise AND
8163-
check("void f(int *b) {\n"
8187+
check("void f(const int *b) {\n"
81648188
" int x = 0x20 & *b;\n"
81658189
"}\n", nullptr, false, true);
81668190
ASSERT_EQUALS("", errout.str());

0 commit comments

Comments
 (0)