Skip to content

Commit f3e0df7

Browse files
committed
Support C++11 style initialization with {}:
-> Support in setVarId and SymbolDatabase (cppcheck-opensource#4344) -> Fixed false positives in unused variable checking (cppcheck-opensource#5491, cppcheck-opensource#5494) Side-effect: Support global variables initialized with brackets (C++03 style) in SymbolDatabase
1 parent f5730a7 commit f3e0df7

6 files changed

Lines changed: 96 additions & 13 deletions

File tree

lib/checkunusedvar.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
698698
for (; defValTok; defValTok = defValTok->next()) {
699699
if (defValTok->str() == "[")
700700
defValTok = defValTok->link();
701-
else if (defValTok->str() == "(" || defValTok->str() == "=") {
701+
else if (defValTok->str() == "(" || defValTok->str() == "{" || defValTok->str() == "=") {
702702
variables.addVar(&*i, type, true);
703703
break;
704704
} else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") {
@@ -718,8 +718,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
718718
variables.read(tok->varId(), i->nameToken());
719719
} else
720720
doAssignment(variables, i->nameToken(), false, scope);
721-
} else if (Token::Match(defValTok, "( %var% )")) // Variables used to initialize the variable read.
722-
variables.readAll(defValTok->next()->varId(), i->nameToken()); // ReadAll?
721+
}
723722
}
724723
}
725724

@@ -741,7 +740,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
741740
if (!tok)
742741
break;
743742
}
744-
if (tok->str() == "{" && tok != scope->classStart) {
743+
if (tok->str() == "{" && tok != scope->classStart && !tok->previous()->varId()) {
745744
for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
746745
if ((*i)->classStart == tok) { // Find associated scope
747746
checkFunctionVariableUsage_iterateScopes(*i, variables, false); // Scan child scope

lib/symboldatabase.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
766766
else if (scope->type == Scope::eCatch)
767767
scope->checkVariable(tok->tokAt(2), Throw); // check for variable declaration and add it to new scope if found
768768
tok = tok1;
769-
} else if (tok->str() == "{") {
769+
} else if (tok->str() == "{" && !tok->previous()->varId()) {
770770
if (!Token::Match(tok->previous(), "=|,")) {
771771
scopeList.push_back(Scope(this, tok, scope, Scope::eUnconditional, tok));
772772
scope->nestedList.push_back(&scopeList.back());
@@ -2605,7 +2605,7 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
26052605
if (tok && isVariableDeclaration(tok, vartok, typetok)) {
26062606
// If the vartok was set in the if-blocks above, create a entry for this variable..
26072607
tok = vartok->next();
2608-
while (tok && tok->str() == "[")
2608+
while (tok && (tok->str() == "[" || tok->str() == "{"))
26092609
tok = tok->link()->next();
26102610

26112611
if (vartok->varId() == 0) {
@@ -2689,9 +2689,9 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
26892689
if (closeTok) {
26902690
localVarTok = skipPointers(closeTok->next());
26912691

2692-
if (Token::Match(localVarTok, ":: %type% %var% ;|=|(")) {
2692+
if (Token::Match(localVarTok, ":: %type% %var% [;=({]")) {
26932693
if (localVarTok->strAt(3) != "(" ||
2694-
Token::simpleMatch(localVarTok->linkAt(3), ") ;")) {
2694+
Token::Match(localVarTok->linkAt(3), "[)}] ;")) {
26952695
localTypeTok = localVarTok->next();
26962696
localVarTok = localVarTok->tokAt(2);
26972697
}
@@ -2710,9 +2710,8 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
27102710
} else if (Token::Match(localVarTok, "%var% )|[") && localVarTok->str() != "operator") {
27112711
vartok = localVarTok;
27122712
typetok = localTypeTok;
2713-
} else if ((isLocal() || type == Scope::eFunction) &&
2714-
Token::Match(localVarTok, "%var% (") &&
2715-
Token::simpleMatch(localVarTok->next()->link(), ") ;") && localVarTok->varId()) {
2713+
} else if (localVarTok && localVarTok->varId() && Token::Match(localVarTok, "%var% (|{") &&
2714+
Token::Match(localVarTok->next()->link(), ")|} ;")) {
27162715
vartok = localVarTok;
27172716
typetok = localTypeTok;
27182717
} else if (type == eCatch &&

lib/tokenize.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,6 +2276,8 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
22762276
bool bracket = false;
22772277
while (tok2) {
22782278
if (tok2->isName()) {
2279+
if (cpp && tok2->str() == "namespace")
2280+
return false;
22792281
if (tok2->str() == "struct" || tok2->str() == "union" || (cpp && (tok2->str() == "class" || tok2->str() == "typename"))) {
22802282
hasstruct = true;
22812283
typeCount = 0;
@@ -2315,7 +2317,7 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
23152317
// In executable scopes, references must be assigned
23162318
// Catching by reference is an exception
23172319
if (executableScope && ref) {
2318-
if (tok2->str() == "(" || tok2->str() == "=")
2320+
if (tok2->str() == "(" || tok2->str() == "=" || tok2->str() == "{")
23192321
; // reference is assigned => ok
23202322
else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
23212323
return false; // not catching by reference => not declaration
@@ -2594,11 +2596,19 @@ void Tokenizer::setVarId()
25942596
continue;
25952597

25962598
const Token *tok3 = tok2->next();
2597-
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()))) {
2599+
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()))) {
25982600
variableId[tok2->previous()->str()] = ++_varId;
25992601
tok = tok2->previous();
26002602
}
26012603
}
2604+
2605+
else if (decl && isCPP() && Token::Match(tok2->previous(), "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
2606+
if (Token::Match(tok2->previous(), "do|try|else"))
2607+
continue;
2608+
2609+
variableId[tok2->previous()->str()] = ++_varId;
2610+
tok = tok2->previous();
2611+
}
26022612
}
26032613

26042614
if (tok->isName()) {

test/testsymboldatabase.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ class TestSymbolDatabase: public TestFixture {
106106

107107
TEST_CASE(test_isVariableDeclarationCanHandleNull);
108108
TEST_CASE(test_isVariableDeclarationIdentifiesSimpleDeclaration);
109+
TEST_CASE(test_isVariableDeclarationIdentifiesInitialization);
110+
TEST_CASE(test_isVariableDeclarationIdentifiesCpp11Initialization);
109111
TEST_CASE(test_isVariableDeclarationIdentifiesScopedDeclaration);
110112
TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration);
111113
TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration);
@@ -221,6 +223,7 @@ class TestSymbolDatabase: public TestFixture {
221223
TEST_CASE(symboldatabase41); // ticket #5197 (unknown macro)
222224
TEST_CASE(symboldatabase42); // only put variables in variable list
223225
TEST_CASE(symboldatabase43); // #4738
226+
TEST_CASE(symboldatabase44);
224227

225228
TEST_CASE(isImplicitlyVirtual);
226229

@@ -282,6 +285,34 @@ class TestSymbolDatabase: public TestFixture {
282285
ASSERT(false == v.isReference());
283286
}
284287

288+
void test_isVariableDeclarationIdentifiesInitialization() {
289+
reset();
290+
givenACodeSampleToTokenize simpleDeclaration("int x (1);");
291+
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok);
292+
ASSERT_EQUALS(true, result);
293+
ASSERT_EQUALS("x", vartok->str());
294+
ASSERT_EQUALS("int", typetok->str());
295+
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0);
296+
ASSERT(false == v.isArray());
297+
ASSERT(false == v.isPointer());
298+
ASSERT(false == v.isReference());
299+
ASSERT(true == v.isIntegralType());
300+
}
301+
302+
void test_isVariableDeclarationIdentifiesCpp11Initialization() {
303+
reset();
304+
givenACodeSampleToTokenize simpleDeclaration("int x {1};");
305+
bool result = si.isVariableDeclaration(simpleDeclaration.tokens(), vartok, typetok);
306+
ASSERT_EQUALS(true, result);
307+
ASSERT_EQUALS("x", vartok->str());
308+
ASSERT_EQUALS("int", typetok->str());
309+
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0);
310+
ASSERT(false == v.isArray());
311+
ASSERT(false == v.isPointer());
312+
ASSERT(false == v.isReference());
313+
ASSERT(true == v.isIntegralType());
314+
}
315+
285316
void test_isVariableDeclarationIdentifiesScopedDeclaration() {
286317
reset();
287318
givenACodeSampleToTokenize ScopedDeclaration("::int x;");
@@ -1879,6 +1910,20 @@ class TestSymbolDatabase: public TestFixture {
18791910
ASSERT_EQUALS("", errout.str());
18801911
}
18811912

1913+
void symboldatabase44() {
1914+
GET_SYMBOL_DB("int i { 1 };\n"
1915+
"int j ( i );\n"
1916+
"void foo() {\n"
1917+
" int k { 1 };\n"
1918+
" int l ( 1 );\n"
1919+
"}");
1920+
ASSERT(db != nullptr);
1921+
ASSERT_EQUALS(4U, db->getVariableListSize() - 1);
1922+
ASSERT_EQUALS(2U, db->scopeList.size());
1923+
for (std::size_t i = 1U; i < db->getVariableListSize(); i++)
1924+
ASSERT(db->getVariableFromVarId(i) != nullptr);
1925+
}
1926+
18821927
void isImplicitlyVirtual() {
18831928
{
18841929
GET_SYMBOL_DB("class Base {\n"

test/testtokenize.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ class TestTokenizer : public TestFixture {
317317
TEST_CASE(varid_sizeofPassed); // #5295
318318
TEST_CASE(varid_classInFunction); // #5293
319319
TEST_CASE(varid_pointerToArray); // #2645
320+
TEST_CASE(varid_cpp11initialization); // #4344
320321

321322
TEST_CASE(varidclass1);
322323
TEST_CASE(varidclass2);
@@ -4923,6 +4924,18 @@ class TestTokenizer : public TestFixture {
49234924
"int f4(int(&a6)[10], int i) { return a6[i]; }"));
49244925
}
49254926

4927+
void varid_cpp11initialization() {
4928+
ASSERT_EQUALS("\n\n##file 0\n"
4929+
"1: int i@1 { 1 } ;\n"
4930+
"2: std :: vector < int > vec@2 { 1 , 2 , 3 } ;\n"
4931+
"3: namespace n { int z@3 ; } ;\n"
4932+
"4: int & j@4 { i@1 } ;\n",
4933+
tokenizeDebugListing("int i{1};\n"
4934+
"std::vector<int> vec{1, 2, 3};\n"
4935+
"namespace n { int z; };\n"
4936+
"int& j{i};\n"));
4937+
}
4938+
49264939
void varidclass1() {
49274940
const std::string actual = tokenizeDebugListing(
49284941
"class Fred\n"

test/testunusedvar.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class TestUnusedVar : public TestFixture {
9696
TEST_CASE(localvar44); // ticket #3602
9797
TEST_CASE(localvar45); // ticket #4020
9898
TEST_CASE(localvar46); // ticket #4899
99+
TEST_CASE(localvar47); // ticket #5491 (C++11 style initialization)
99100
TEST_CASE(localvaralias1);
100101
TEST_CASE(localvaralias2); // ticket #1637
101102
TEST_CASE(localvaralias3); // ticket #1639
@@ -1875,6 +1876,22 @@ class TestUnusedVar : public TestFixture {
18751876
ASSERT_EQUALS("", errout.str());
18761877
}
18771878

1879+
void localvar47() { // #5491/#5494
1880+
functionVariableUsage("int func() {\n"
1881+
" int i = 0;\n"
1882+
" int j{i};\n"
1883+
" return j;\n"
1884+
"}");
1885+
ASSERT_EQUALS("", errout.str());
1886+
1887+
functionVariableUsage("int func() {\n"
1888+
" std::mutex m;\n"
1889+
" std::unique_lock<std::mutex> l{ m };\n"
1890+
" return 0;\n"
1891+
"}");
1892+
ASSERT_EQUALS("", errout.str());
1893+
}
1894+
18781895
void localvaralias1() {
18791896
functionVariableUsage("void foo()\n"
18801897
"{\n"

0 commit comments

Comments
 (0)