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;
|
||||
|
||||
if (isVariableDeclaration(tok, vartok))
|
||||
if (Token::Match(tok, "struct|union"))
|
||||
{
|
||||
tok = tok->next();
|
||||
}
|
||||
|
||||
if (isVariableDeclaration(tok, vartok, typetok))
|
||||
{
|
||||
typetok = vartok->previous();
|
||||
isClass = (!typetok->isStandardType());
|
||||
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?
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -240,10 +240,10 @@ public:
|
|||
* @brief helper function for getVarList()
|
||||
* @param tok pointer to token to check
|
||||
* @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
|
||||
*/
|
||||
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);
|
||||
|
|
|
@ -160,6 +160,7 @@ private:
|
|||
TEST_CASE(const41); // ticket #2255
|
||||
TEST_CASE(const42); // ticket #2282
|
||||
TEST_CASE(const43); // ticket #2377
|
||||
TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
|
||||
TEST_CASE(constoperator1); // operator< can often be const
|
||||
TEST_CASE(constoperator2); // operator<<
|
||||
TEST_CASE(constoperator3);
|
||||
|
@ -4859,6 +4860,20 @@ private:
|
|||
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
|
||||
void constincdec()
|
||||
{
|
||||
|
|
|
@ -28,11 +28,19 @@ public:
|
|||
:TestFixture("TestSymbolDatabase")
|
||||
,si(NULL, NULL, NULL)
|
||||
,vartok(NULL)
|
||||
,typetok(NULL)
|
||||
{}
|
||||
|
||||
private:
|
||||
const SymbolDatabase::SpaceInfo si;
|
||||
const Token* vartok;
|
||||
const Token* typetok;
|
||||
|
||||
void reset()
|
||||
{
|
||||
vartok = NULL;
|
||||
typetok = NULL;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
|
@ -42,89 +50,132 @@ private:
|
|||
TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesManyScopes);
|
||||
TEST_CASE(test_isVariableDeclarationDoesNotIdentifyPointers);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesPointers);
|
||||
TEST_CASE(test_isVariableDeclarationDoesNotIdentifyConstness);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesFirstOfManyVariables);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesScopedPointerDeclaration);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithIndirection);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection);
|
||||
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationCanHandleNull()
|
||||
{
|
||||
vartok = NULL;
|
||||
bool result = si.isVariableDeclaration(NULL, vartok);
|
||||
reset();
|
||||
bool result = si.isVariableDeclaration(NULL, vartok, typetok);
|
||||
ASSERT_EQUALS(false, result);
|
||||
ASSERT(NULL == vartok);
|
||||
ASSERT(NULL == typetok);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesSimpleDeclaration()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesScopedDeclaration()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesStdDeclaration()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("string", typetok->str());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesScopedStdDeclaration()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("string", typetok->str());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesManyScopes()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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("x", vartok->str());
|
||||
ASSERT_EQUALS("EE", typetok->str());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationDoesNotIdentifyPointers()
|
||||
void test_isVariableDeclarationIdentifiesPointers()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
givenACodeSampleToTokenize pointer("int* p;");
|
||||
bool result = si.isVariableDeclaration(pointer.tokens(), vartok);
|
||||
ASSERT_EQUALS(false, result);
|
||||
ASSERT(NULL == vartok);
|
||||
bool result = si.isVariableDeclaration(pointer.tokens(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
ASSERT_EQUALS("p", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationDoesNotIdentifyConstness()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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(NULL == vartok);
|
||||
ASSERT(NULL == typetok);
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesFirstOfManyVariables()
|
||||
{
|
||||
vartok = NULL;
|
||||
reset();
|
||||
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("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