Support C++11 style initialization with {}:
-> Support in setVarId and SymbolDatabase (#4344) -> Fixed false positives in unused variable checking (#5491, #5494) Side-effect: Support global variables initialized with brackets (C++03 style) in SymbolDatabase
This commit is contained in:
parent
f5730a7d12
commit
f3e0df7501
|
@ -698,7 +698,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
|
|||
for (; defValTok; defValTok = defValTok->next()) {
|
||||
if (defValTok->str() == "[")
|
||||
defValTok = defValTok->link();
|
||||
else if (defValTok->str() == "(" || defValTok->str() == "=") {
|
||||
else if (defValTok->str() == "(" || defValTok->str() == "{" || defValTok->str() == "=") {
|
||||
variables.addVar(&*i, type, true);
|
||||
break;
|
||||
} else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") {
|
||||
|
@ -718,8 +718,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
|
|||
variables.read(tok->varId(), i->nameToken());
|
||||
} else
|
||||
doAssignment(variables, i->nameToken(), false, scope);
|
||||
} else if (Token::Match(defValTok, "( %var% )")) // Variables used to initialize the variable read.
|
||||
variables.readAll(defValTok->next()->varId(), i->nameToken()); // ReadAll?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,7 +740,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
|
|||
if (!tok)
|
||||
break;
|
||||
}
|
||||
if (tok->str() == "{" && tok != scope->classStart) {
|
||||
if (tok->str() == "{" && tok != scope->classStart && !tok->previous()->varId()) {
|
||||
for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
|
||||
if ((*i)->classStart == tok) { // Find associated scope
|
||||
checkFunctionVariableUsage_iterateScopes(*i, variables, false); // Scan child scope
|
||||
|
|
|
@ -766,7 +766,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
else if (scope->type == Scope::eCatch)
|
||||
scope->checkVariable(tok->tokAt(2), Throw); // check for variable declaration and add it to new scope if found
|
||||
tok = tok1;
|
||||
} else if (tok->str() == "{") {
|
||||
} else if (tok->str() == "{" && !tok->previous()->varId()) {
|
||||
if (!Token::Match(tok->previous(), "=|,")) {
|
||||
scopeList.push_back(Scope(this, tok, scope, Scope::eUnconditional, tok));
|
||||
scope->nestedList.push_back(&scopeList.back());
|
||||
|
@ -2605,7 +2605,7 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
|
|||
if (tok && isVariableDeclaration(tok, vartok, typetok)) {
|
||||
// If the vartok was set in the if-blocks above, create a entry for this variable..
|
||||
tok = vartok->next();
|
||||
while (tok && tok->str() == "[")
|
||||
while (tok && (tok->str() == "[" || tok->str() == "{"))
|
||||
tok = tok->link()->next();
|
||||
|
||||
if (vartok->varId() == 0) {
|
||||
|
@ -2689,9 +2689,9 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
|
|||
if (closeTok) {
|
||||
localVarTok = skipPointers(closeTok->next());
|
||||
|
||||
if (Token::Match(localVarTok, ":: %type% %var% ;|=|(")) {
|
||||
if (Token::Match(localVarTok, ":: %type% %var% [;=({]")) {
|
||||
if (localVarTok->strAt(3) != "(" ||
|
||||
Token::simpleMatch(localVarTok->linkAt(3), ") ;")) {
|
||||
Token::Match(localVarTok->linkAt(3), "[)}] ;")) {
|
||||
localTypeTok = localVarTok->next();
|
||||
localVarTok = localVarTok->tokAt(2);
|
||||
}
|
||||
|
@ -2710,9 +2710,8 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
|
|||
} else if (Token::Match(localVarTok, "%var% )|[") && localVarTok->str() != "operator") {
|
||||
vartok = localVarTok;
|
||||
typetok = localTypeTok;
|
||||
} else if ((isLocal() || type == Scope::eFunction) &&
|
||||
Token::Match(localVarTok, "%var% (") &&
|
||||
Token::simpleMatch(localVarTok->next()->link(), ") ;") && localVarTok->varId()) {
|
||||
} else if (localVarTok && localVarTok->varId() && Token::Match(localVarTok, "%var% (|{") &&
|
||||
Token::Match(localVarTok->next()->link(), ")|} ;")) {
|
||||
vartok = localVarTok;
|
||||
typetok = localTypeTok;
|
||||
} else if (type == eCatch &&
|
||||
|
|
|
@ -2276,6 +2276,8 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
|
|||
bool bracket = false;
|
||||
while (tok2) {
|
||||
if (tok2->isName()) {
|
||||
if (cpp && tok2->str() == "namespace")
|
||||
return false;
|
||||
if (tok2->str() == "struct" || tok2->str() == "union" || (cpp && (tok2->str() == "class" || tok2->str() == "typename"))) {
|
||||
hasstruct = true;
|
||||
typeCount = 0;
|
||||
|
@ -2315,7 +2317,7 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
|
|||
// In executable scopes, references must be assigned
|
||||
// Catching by reference is an exception
|
||||
if (executableScope && ref) {
|
||||
if (tok2->str() == "(" || tok2->str() == "=")
|
||||
if (tok2->str() == "(" || tok2->str() == "=" || tok2->str() == "{")
|
||||
; // reference is assigned => ok
|
||||
else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
|
||||
return false; // not catching by reference => not declaration
|
||||
|
@ -2594,11 +2596,19 @@ void Tokenizer::setVarId()
|
|||
continue;
|
||||
|
||||
const Token *tok3 = tok2->next();
|
||||
if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && (notstart.find(tok3->str()) != notstart.end() ||!setVarIdParseDeclaration(&tok3, variableId, executableScope.top(), isCPP()))) {
|
||||
if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && (notstart.find(tok3->str()) != notstart.end() || !setVarIdParseDeclaration(&tok3, variableId, executableScope.top(), isCPP()))) {
|
||||
variableId[tok2->previous()->str()] = ++_varId;
|
||||
tok = tok2->previous();
|
||||
}
|
||||
}
|
||||
|
||||
else if (decl && isCPP() && Token::Match(tok2->previous(), "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
|
||||
if (Token::Match(tok2->previous(), "do|try|else"))
|
||||
continue;
|
||||
|
||||
variableId[tok2->previous()->str()] = ++_varId;
|
||||
tok = tok2->previous();
|
||||
}
|
||||
}
|
||||
|
||||
if (tok->isName()) {
|
||||
|
|
|
@ -106,6 +106,8 @@ private:
|
|||
|
||||
TEST_CASE(test_isVariableDeclarationCanHandleNull);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesSimpleDeclaration);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesInitialization);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesCpp11Initialization);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesScopedDeclaration);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration);
|
||||
TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration);
|
||||
|
@ -221,6 +223,7 @@ private:
|
|||
TEST_CASE(symboldatabase41); // ticket #5197 (unknown macro)
|
||||
TEST_CASE(symboldatabase42); // only put variables in variable list
|
||||
TEST_CASE(symboldatabase43); // #4738
|
||||
TEST_CASE(symboldatabase44);
|
||||
|
||||
TEST_CASE(isImplicitlyVirtual);
|
||||
|
||||
|
@ -282,6 +285,34 @@ private:
|
|||
ASSERT(false == v.isReference());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesInitialization() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize simpleDeclaration("int x (1);");
|
||||
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
ASSERT_EQUALS("x", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0);
|
||||
ASSERT(false == v.isArray());
|
||||
ASSERT(false == v.isPointer());
|
||||
ASSERT(false == v.isReference());
|
||||
ASSERT(true == v.isIntegralType());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesCpp11Initialization() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize simpleDeclaration("int x {1};");
|
||||
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok);
|
||||
ASSERT_EQUALS(true, result);
|
||||
ASSERT_EQUALS("x", vartok->str());
|
||||
ASSERT_EQUALS("int", typetok->str());
|
||||
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0);
|
||||
ASSERT(false == v.isArray());
|
||||
ASSERT(false == v.isPointer());
|
||||
ASSERT(false == v.isReference());
|
||||
ASSERT(true == v.isIntegralType());
|
||||
}
|
||||
|
||||
void test_isVariableDeclarationIdentifiesScopedDeclaration() {
|
||||
reset();
|
||||
givenACodeSampleToTokenize ScopedDeclaration("::int x;");
|
||||
|
@ -1879,6 +1910,20 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void symboldatabase44() {
|
||||
GET_SYMBOL_DB("int i { 1 };\n"
|
||||
"int j ( i );\n"
|
||||
"void foo() {\n"
|
||||
" int k { 1 };\n"
|
||||
" int l ( 1 );\n"
|
||||
"}");
|
||||
ASSERT(db != nullptr);
|
||||
ASSERT_EQUALS(4U, db->getVariableListSize() - 1);
|
||||
ASSERT_EQUALS(2U, db->scopeList.size());
|
||||
for (std::size_t i = 1U; i < db->getVariableListSize(); i++)
|
||||
ASSERT(db->getVariableFromVarId(i) != nullptr);
|
||||
}
|
||||
|
||||
void isImplicitlyVirtual() {
|
||||
{
|
||||
GET_SYMBOL_DB("class Base {\n"
|
||||
|
|
|
@ -317,6 +317,7 @@ private:
|
|||
TEST_CASE(varid_sizeofPassed); // #5295
|
||||
TEST_CASE(varid_classInFunction); // #5293
|
||||
TEST_CASE(varid_pointerToArray); // #2645
|
||||
TEST_CASE(varid_cpp11initialization); // #4344
|
||||
|
||||
TEST_CASE(varidclass1);
|
||||
TEST_CASE(varidclass2);
|
||||
|
@ -4923,6 +4924,18 @@ private:
|
|||
"int f4(int(&a6)[10], int i) { return a6[i]; }"));
|
||||
}
|
||||
|
||||
void varid_cpp11initialization() {
|
||||
ASSERT_EQUALS("\n\n##file 0\n"
|
||||
"1: int i@1 { 1 } ;\n"
|
||||
"2: std :: vector < int > vec@2 { 1 , 2 , 3 } ;\n"
|
||||
"3: namespace n { int z@3 ; } ;\n"
|
||||
"4: int & j@4 { i@1 } ;\n",
|
||||
tokenizeDebugListing("int i{1};\n"
|
||||
"std::vector<int> vec{1, 2, 3};\n"
|
||||
"namespace n { int z; };\n"
|
||||
"int& j{i};\n"));
|
||||
}
|
||||
|
||||
void varidclass1() {
|
||||
const std::string actual = tokenizeDebugListing(
|
||||
"class Fred\n"
|
||||
|
|
|
@ -96,6 +96,7 @@ private:
|
|||
TEST_CASE(localvar44); // ticket #3602
|
||||
TEST_CASE(localvar45); // ticket #4020
|
||||
TEST_CASE(localvar46); // ticket #4899
|
||||
TEST_CASE(localvar47); // ticket #5491 (C++11 style initialization)
|
||||
TEST_CASE(localvaralias1);
|
||||
TEST_CASE(localvaralias2); // ticket #1637
|
||||
TEST_CASE(localvaralias3); // ticket #1639
|
||||
|
@ -1875,6 +1876,22 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void localvar47() { // #5491/#5494
|
||||
functionVariableUsage("int func() {\n"
|
||||
" int i = 0;\n"
|
||||
" int j{i};\n"
|
||||
" return j;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("int func() {\n"
|
||||
" std::mutex m;\n"
|
||||
" std::unique_lock<std::mutex> l{ m };\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void localvaralias1() {
|
||||
functionVariableUsage("void foo()\n"
|
||||
"{\n"
|
||||
|
|
Loading…
Reference in New Issue