isVariableDeclaration: Handle pointer to const pointer (#1395)
isVariableDeclaration did not handle pointer to const pointer, or pointer to volatile pointer. This resulted in FPs in examples like the following: class Fred { public: const char *const *data; const char *const *getData() { return data; }; } where cppcheck would say getData could be static, since it didn't recognize const char *const *data as a variable declaration.
This commit is contained in:
parent
ca5542131a
commit
5e120b567c
|
@ -3550,6 +3550,17 @@ static const Token* skipPointers(const Token* tok)
|
|||
return tok;
|
||||
}
|
||||
|
||||
static const Token* skipPointersAndQualifiers(const Token* tok)
|
||||
{
|
||||
tok = skipPointers(tok);
|
||||
while (Token::Match(tok, "const|volatile")) {
|
||||
tok = tok->next();
|
||||
tok = skipPointers(tok);
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const
|
||||
{
|
||||
const bool isCPP = check && check->mTokenizer->isCPP();
|
||||
|
@ -3582,7 +3593,7 @@ bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok,
|
|||
}
|
||||
}
|
||||
} else if (Token::Match(localTypeTok, "%type%")) {
|
||||
localVarTok = skipPointers(localTypeTok->strAt(1)=="const"?localTypeTok->tokAt(2):localTypeTok->next());
|
||||
localVarTok = skipPointersAndQualifiers(localTypeTok->next());
|
||||
}
|
||||
|
||||
if (!localVarTok)
|
||||
|
|
|
@ -196,6 +196,7 @@ private:
|
|||
TEST_CASE(constArrayOperator); // #4406
|
||||
TEST_CASE(constRangeBasedFor); // #5514
|
||||
TEST_CASE(const_shared_ptr);
|
||||
TEST_CASE(constPtrToConstPtr);
|
||||
|
||||
TEST_CASE(initializerListOrder);
|
||||
TEST_CASE(initializerListUsage);
|
||||
|
@ -6215,6 +6216,14 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void constPtrToConstPtr() {
|
||||
checkConst("class Fred {\n"
|
||||
"public:\n"
|
||||
" const char *const *data;\n"
|
||||
" const char *const *getData() { return data; }\n}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::getData' can be const.\n", errout.str());
|
||||
}
|
||||
|
||||
void checkInitializerListOrder(const char code[]) {
|
||||
// Clear the error log
|
||||
errout.str("");
|
||||
|
|
|
@ -141,6 +141,10 @@ private:
|
|||
TEST_CASE(isVariableDeclarationRValueRef);
|
||||
TEST_CASE(isVariableDeclarationDoesNotIdentifyCase);
|
||||
TEST_CASE(isVariableStlType);
|
||||
TEST_CASE(isVariablePointerToConstPointer);
|
||||
TEST_CASE(isVariablePointerToVolatilePointer);
|
||||
TEST_CASE(isVariablePointerToConstVolatilePointer);
|
||||
TEST_CASE(isVariableMultiplePointersAndQualifiers);
|
||||
|
||||
TEST_CASE(VariableValueType1);
|
||||
TEST_CASE(VariableValueType2);
|
||||
|
@ -954,6 +958,50 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void isVariablePointerToConstPointer() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize var("char* const * s;");
|
||||
bool result = nullScope.isVariableDeclaration(var.tokens(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0, &settings1);
|
||||
ASSERT(false == v.isArray());
|
||||
ASSERT(true == v.isPointer());
|
||||
ASSERT(false == v.isReference());
|
||||
}
|
||||
|
||||
void isVariablePointerToVolatilePointer() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize var("char* volatile * s;");
|
||||
bool result = nullScope.isVariableDeclaration(var.tokens(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0, &settings1);
|
||||
ASSERT(false == v.isArray());
|
||||
ASSERT(true == v.isPointer());
|
||||
ASSERT(false == v.isReference());
|
||||
}
|
||||
|
||||
void isVariablePointerToConstVolatilePointer() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize var("char* const volatile * s;");
|
||||
bool result = nullScope.isVariableDeclaration(var.tokens(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0, &settings1);
|
||||
ASSERT(false == v.isArray());
|
||||
ASSERT(true == v.isPointer());
|
||||
ASSERT(false == v.isReference());
|
||||
}
|
||||
|
||||
void isVariableMultiplePointersAndQualifiers() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize var("const char* const volatile * const volatile * const volatile * const volatile s;");
|
||||
bool result = nullScope.isVariableDeclaration(var.tokens()->next(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0, &settings1);
|
||||
ASSERT(false == v.isArray());
|
||||
ASSERT(true == v.isPointer());
|
||||
ASSERT(false == v.isReference());
|
||||
}
|
||||
|
||||
void arrayMemberVar1() {
|
||||
GET_SYMBOL_DB("struct Foo {\n"
|
||||
" int x;\n"
|
||||
|
|
Loading…
Reference in New Issue