Fixed #2384 ("The function 's::f' can be const" reported for pointer-to-pointer)
Moved check for pointer variables into isVariableDeclaration() Can now handle multiple scopes and multiple levels of indirection. Simplified check for strucs and unions, too, reducing the size of getVarList(). skipScopeIdentifiers() and skipPointers() should probably be methods on class Token.
This commit is contained in:
parent
76cf097104
commit
502cfe7243
|
@ -1110,48 +1110,17 @@ void SymbolDatabase::SpaceInfo::getVarList()
|
||||||
|
|
||||||
bool isClass = false;
|
bool isClass = false;
|
||||||
|
|
||||||
if (isVariableDeclaration(tok, vartok))
|
if (Token::Match(tok, "struct|union"))
|
||||||
|
{
|
||||||
|
tok = tok->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVariableDeclaration(tok, vartok, typetok))
|
||||||
{
|
{
|
||||||
typetok = vartok->previous();
|
|
||||||
isClass = (!typetok->isStandardType());
|
isClass = (!typetok->isStandardType());
|
||||||
tok = vartok->next();
|
tok = vartok->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structure?
|
|
||||||
else if (Token::Match(tok, "struct|union %type% %var% ;"))
|
|
||||||
{
|
|
||||||
isClass = true;
|
|
||||||
vartok = tok->tokAt(2);
|
|
||||||
typetok = vartok->previous();
|
|
||||||
tok = vartok->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer?
|
|
||||||
else if (Token::Match(tok, "%type% * %var% ;"))
|
|
||||||
{
|
|
||||||
vartok = tok->tokAt(2);
|
|
||||||
typetok = tok;
|
|
||||||
tok = vartok->next();
|
|
||||||
}
|
|
||||||
else if (Token::Match(tok, "%type% %type% * %var% ;"))
|
|
||||||
{
|
|
||||||
vartok = tok->tokAt(3);
|
|
||||||
typetok = vartok->tokAt(-2);
|
|
||||||
tok = vartok->next();
|
|
||||||
}
|
|
||||||
else if (Token::Match(tok, "%type% :: %type% * %var% ;"))
|
|
||||||
{
|
|
||||||
vartok = tok->tokAt(4);
|
|
||||||
typetok = vartok->tokAt(-2);
|
|
||||||
tok = vartok->next();
|
|
||||||
}
|
|
||||||
else if (Token::Match(tok, "%type% :: %type% :: %type% * %var% ;"))
|
|
||||||
{
|
|
||||||
vartok = tok->tokAt(6);
|
|
||||||
typetok = vartok->tokAt(-2);
|
|
||||||
tok = vartok->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array?
|
// Array?
|
||||||
else if (Token::Match(tok, "%type% %var% [") && tok->next()->str() != "operator")
|
else if (Token::Match(tok, "%type% %var% [") && tok->next()->str() != "operator")
|
||||||
{
|
{
|
||||||
|
@ -1276,20 +1245,50 @@ void SymbolDatabase::SpaceInfo::getVarList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SymbolDatabase::SpaceInfo::isVariableDeclaration(const Token* tok, const Token*& vartok) const
|
const Token* skipScopeIdentifiers(const Token* tok)
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(tok, "::"))
|
const Token* ret = tok;
|
||||||
|
|
||||||
|
if (Token::simpleMatch(ret, "::"))
|
||||||
{
|
{
|
||||||
tok = tok->next();
|
ret = ret->next();
|
||||||
}
|
}
|
||||||
while (Token::Match(tok, "%type% :: "))
|
while (Token::Match(ret, "%type% :: "))
|
||||||
{
|
{
|
||||||
tok = tok->tokAt(2);
|
ret = ret->tokAt(2);
|
||||||
}
|
}
|
||||||
if (Token::Match(tok, "%type% %var% ;"))
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token* skipPointers(const Token* tok)
|
||||||
|
{
|
||||||
|
const Token* ret = tok;
|
||||||
|
|
||||||
|
while (Token::simpleMatch(ret, "*"))
|
||||||
{
|
{
|
||||||
vartok = tok->next();
|
ret = ret->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SymbolDatabase::SpaceInfo::isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const
|
||||||
|
{
|
||||||
|
tok = skipScopeIdentifiers(tok);
|
||||||
|
if (Token::Match(tok, "%type%"))
|
||||||
|
{
|
||||||
|
const Token* potentialTypetok = tok;
|
||||||
|
|
||||||
|
tok = skipPointers(tok->next());
|
||||||
|
|
||||||
|
if (Token::Match(tok, "%var% ;"))
|
||||||
|
{
|
||||||
|
vartok = tok;
|
||||||
|
typetok = potentialTypetok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL != vartok;
|
return NULL != vartok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,10 +240,10 @@ public:
|
||||||
* @brief helper function for getVarList()
|
* @brief helper function for getVarList()
|
||||||
* @param tok pointer to token to check
|
* @param tok pointer to token to check
|
||||||
* @param vartok populated with pointer to the variable token, if found
|
* @param vartok populated with pointer to the variable token, if found
|
||||||
|
* @param typetok populated with pointer to the type token, if found
|
||||||
* @return true if tok points to a variable declaration, false otherwise
|
* @return true if tok points to a variable declaration, false otherwise
|
||||||
*/
|
*/
|
||||||
bool isVariableDeclaration(const Token* tok, const Token*& vartok) const;
|
bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isMemberVar(const SpaceInfo *info, const Token *tok);
|
bool isMemberVar(const SpaceInfo *info, const Token *tok);
|
||||||
|
|
|
@ -160,6 +160,7 @@ private:
|
||||||
TEST_CASE(const41); // ticket #2255
|
TEST_CASE(const41); // ticket #2255
|
||||||
TEST_CASE(const42); // ticket #2282
|
TEST_CASE(const42); // ticket #2282
|
||||||
TEST_CASE(const43); // ticket #2377
|
TEST_CASE(const43); // ticket #2377
|
||||||
|
TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
|
||||||
TEST_CASE(constoperator1); // operator< can often be const
|
TEST_CASE(constoperator1); // operator< can often be const
|
||||||
TEST_CASE(constoperator2); // operator<<
|
TEST_CASE(constoperator2); // operator<<
|
||||||
TEST_CASE(constoperator3);
|
TEST_CASE(constoperator3);
|
||||||
|
@ -4859,6 +4860,20 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assigningPointerToPointerIsNotAConstOperation()
|
||||||
|
{
|
||||||
|
checkConst("struct s\n"
|
||||||
|
"{\n"
|
||||||
|
" int** v;\n"
|
||||||
|
" void f()\n"
|
||||||
|
" {\n"
|
||||||
|
" v = 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
// increment/decrement => not const
|
// increment/decrement => not const
|
||||||
void constincdec()
|
void constincdec()
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,11 +28,19 @@ public:
|
||||||
:TestFixture("TestSymbolDatabase")
|
:TestFixture("TestSymbolDatabase")
|
||||||
,si(NULL, NULL, NULL)
|
,si(NULL, NULL, NULL)
|
||||||
,vartok(NULL)
|
,vartok(NULL)
|
||||||
|
,typetok(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SymbolDatabase::SpaceInfo si;
|
const SymbolDatabase::SpaceInfo si;
|
||||||
const Token* vartok;
|
const Token* vartok;
|
||||||
|
const Token* typetok;
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
vartok = NULL;
|
||||||
|
typetok = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
@ -42,89 +50,132 @@ private:
|
||||||
TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration);
|
TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration);
|
||||||
TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration);
|
TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration);
|
||||||
TEST_CASE(test_isVariableDeclarationIdentifiesManyScopes);
|
TEST_CASE(test_isVariableDeclarationIdentifiesManyScopes);
|
||||||
TEST_CASE(test_isVariableDeclarationDoesNotIdentifyPointers);
|
TEST_CASE(test_isVariableDeclarationIdentifiesPointers);
|
||||||
TEST_CASE(test_isVariableDeclarationDoesNotIdentifyConstness);
|
TEST_CASE(test_isVariableDeclarationDoesNotIdentifyConstness);
|
||||||
TEST_CASE(test_isVariableDeclarationIdentifiesFirstOfManyVariables);
|
TEST_CASE(test_isVariableDeclarationIdentifiesFirstOfManyVariables);
|
||||||
|
TEST_CASE(test_isVariableDeclarationIdentifiesScopedPointerDeclaration);
|
||||||
|
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithIndirection);
|
||||||
|
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationCanHandleNull()
|
void test_isVariableDeclarationCanHandleNull()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
bool result = si.isVariableDeclaration(NULL, vartok);
|
bool result = si.isVariableDeclaration(NULL, vartok, typetok);
|
||||||
ASSERT_EQUALS(false, result);
|
ASSERT_EQUALS(false, result);
|
||||||
ASSERT(NULL == vartok);
|
ASSERT(NULL == vartok);
|
||||||
|
ASSERT(NULL == typetok);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationIdentifiesSimpleDeclaration()
|
void test_isVariableDeclarationIdentifiesSimpleDeclaration()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize simpleDeclaration("int x;");
|
givenACodeSampleToTokenize simpleDeclaration("int x;");
|
||||||
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok);
|
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(true, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT_EQUALS("x", vartok->str());
|
ASSERT_EQUALS("x", vartok->str());
|
||||||
|
ASSERT_EQUALS("int", typetok->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationIdentifiesScopedDeclaration()
|
void test_isVariableDeclarationIdentifiesScopedDeclaration()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize ScopedDeclaration("::int x;");
|
givenACodeSampleToTokenize ScopedDeclaration("::int x;");
|
||||||
bool result = si.isVariableDeclaration(ScopedDeclaration.tokens(), vartok);
|
bool result = si.isVariableDeclaration(ScopedDeclaration.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(true, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT_EQUALS("x", vartok->str());
|
ASSERT_EQUALS("x", vartok->str());
|
||||||
|
ASSERT_EQUALS("int", typetok->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationIdentifiesStdDeclaration()
|
void test_isVariableDeclarationIdentifiesStdDeclaration()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize StdDeclaration("std::string x;");
|
givenACodeSampleToTokenize StdDeclaration("std::string x;");
|
||||||
bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok);
|
bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(true, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT_EQUALS("x", vartok->str());
|
ASSERT_EQUALS("x", vartok->str());
|
||||||
|
ASSERT_EQUALS("string", typetok->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationIdentifiesScopedStdDeclaration()
|
void test_isVariableDeclarationIdentifiesScopedStdDeclaration()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize StdDeclaration("::std::string x;");
|
givenACodeSampleToTokenize StdDeclaration("::std::string x;");
|
||||||
bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok);
|
bool result = si.isVariableDeclaration(StdDeclaration.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(true, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT_EQUALS("x", vartok->str());
|
ASSERT_EQUALS("x", vartok->str());
|
||||||
|
ASSERT_EQUALS("string", typetok->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationIdentifiesManyScopes()
|
void test_isVariableDeclarationIdentifiesManyScopes()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE x;");
|
givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE x;");
|
||||||
bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok);
|
bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(true, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT_EQUALS("x", vartok->str());
|
ASSERT_EQUALS("x", vartok->str());
|
||||||
|
ASSERT_EQUALS("EE", typetok->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationDoesNotIdentifyPointers()
|
void test_isVariableDeclarationIdentifiesPointers()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize pointer("int* p;");
|
givenACodeSampleToTokenize pointer("int* p;");
|
||||||
bool result = si.isVariableDeclaration(pointer.tokens(), vartok);
|
bool result = si.isVariableDeclaration(pointer.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(false, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT(NULL == vartok);
|
ASSERT_EQUALS("p", vartok->str());
|
||||||
|
ASSERT_EQUALS("int", typetok->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationDoesNotIdentifyConstness()
|
void test_isVariableDeclarationDoesNotIdentifyConstness()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize constness("const int* cp;");
|
givenACodeSampleToTokenize constness("const int* cp;");
|
||||||
bool result = si.isVariableDeclaration(constness.tokens(), vartok);
|
bool result = si.isVariableDeclaration(constness.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(false, result);
|
ASSERT_EQUALS(false, result);
|
||||||
ASSERT(NULL == vartok);
|
ASSERT(NULL == vartok);
|
||||||
|
ASSERT(NULL == typetok);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationIdentifiesFirstOfManyVariables()
|
void test_isVariableDeclarationIdentifiesFirstOfManyVariables()
|
||||||
{
|
{
|
||||||
vartok = NULL;
|
reset();
|
||||||
givenACodeSampleToTokenize multipleDeclaration("int first, second;");
|
givenACodeSampleToTokenize multipleDeclaration("int first, second;");
|
||||||
bool result = si.isVariableDeclaration(multipleDeclaration.tokens(), vartok);
|
bool result = si.isVariableDeclaration(multipleDeclaration.tokens(), vartok, typetok);
|
||||||
ASSERT_EQUALS(true, result);
|
ASSERT_EQUALS(true, result);
|
||||||
ASSERT_EQUALS("first", vartok->str());
|
ASSERT_EQUALS("first", vartok->str());
|
||||||
|
ASSERT_EQUALS("int", typetok->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_isVariableDeclarationIdentifiesScopedPointerDeclaration()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE* p;");
|
||||||
|
bool result = si.isVariableDeclaration(manyScopes.tokens(), vartok, typetok);
|
||||||
|
ASSERT_EQUALS(true, result);
|
||||||
|
ASSERT_EQUALS("p", vartok->str());
|
||||||
|
ASSERT_EQUALS("EE", typetok->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_isVariableDeclarationIdentifiesDeclarationWithIndirection()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
givenACodeSampleToTokenize pointerToPointer("int** pp;");
|
||||||
|
bool result = si.isVariableDeclaration(pointerToPointer.tokens(), vartok, typetok);
|
||||||
|
ASSERT_EQUALS(true, result);
|
||||||
|
ASSERT_EQUALS("pp", vartok->str());
|
||||||
|
ASSERT_EQUALS("int", typetok->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
givenACodeSampleToTokenize pointerToPointer("int***** p;");
|
||||||
|
bool result = si.isVariableDeclaration(pointerToPointer.tokens(), vartok, typetok);
|
||||||
|
ASSERT_EQUALS(true, result);
|
||||||
|
ASSERT_EQUALS("p", vartok->str());
|
||||||
|
ASSERT_EQUALS("int", typetok->str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue