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:
rikardfalkeborn 2018-09-25 06:19:26 +02:00 committed by Daniel Marjamäki
parent ca5542131a
commit 5e120b567c
3 changed files with 69 additions and 1 deletions

View File

@ -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)

View File

@ -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("");

View File

@ -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"