From e4525d56a0bfcc738974f5945b1aaa874bf58d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 7 Jan 2019 21:26:58 +0100 Subject: [PATCH] Fixed #8111 (performance warning - member variable at constructor) --- lib/checkclass.cpp | 70 +++++++++++++++++++++++++++------------------- test/testclass.cpp | 10 +++++++ 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index c13cd5385..5d2bdad5c 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -930,37 +930,51 @@ void CheckClass::initializationListUsage() break; if (Token::Match(tok, "try|do {")) break; - if (Token::Match(tok, "%var% =") && tok->strAt(-1) != "*") { - const Variable* var = tok->variable(); - if (var && var->scope() == owner && !var->isStatic()) { - if (var->isPointer() || var->isReference() || var->isEnumType() || var->valueType()->type > ValueType::Type::ITERATOR) - continue; + if (!Token::Match(tok, "%var% =") || tok->strAt(-1) == "*") + continue; - bool allowed = true; - for (const Token* tok2 = tok->tokAt(2); tok2 && tok2->str() != ";"; tok2 = tok2->next()) { - const Variable* var2 = tok2->variable(); - if (var2) { - if (var2->scope() == owner && tok2->strAt(-1)!=".") { // Is there a dependency between two member variables? - allowed = false; - break; - } else if (var2->isArray() && var2->isLocal()) { // Can't initialize with a local array - allowed = false; - break; - } - } else if (tok2->str() == "this") { // 'this' instance is not completely constructed in initialization list - allowed = false; - break; - } else if (Token::Match(tok2, "%name% (") && tok2->strAt(-1) != "." && isMemberFunc(owner, tok2)) { // Member function called? - allowed = false; - break; - } + const Variable* var = tok->variable(); + if (!var || var->scope() != owner || var->isStatic()) + continue; + if (var->isPointer() || var->isReference() || var->isEnumType() || var->valueType()->type > ValueType::Type::ITERATOR) + continue; + + // Access local var member in rhs => do not warn + bool localmember = false; + visitAstNodes(tok->next()->astOperand2(), + [&](const Token *rhs) { + if (rhs->str() == "." && rhs->astOperand1() && rhs->astOperand1()->variable() && rhs->astOperand1()->variable()->isLocal()) + localmember = true; + return ChildrenToVisit::op1_and_op2; + }); + if (localmember) + continue; + + bool allowed = true; + visitAstNodes(tok->next()->astOperand2(), + [&](const Token *tok2) { + const Variable* var2 = tok2->variable(); + if (var2) { + if (var2->scope() == owner && tok2->strAt(-1)!=".") { // Is there a dependency between two member variables? + allowed = false; + return ChildrenToVisit::done; + } else if (var2->isArray() && var2->isLocal()) { // Can't initialize with a local array + allowed = false; + return ChildrenToVisit::done; } - if (!allowed) - continue; - - suggestInitializationList(tok, tok->str()); + } else if (tok2->str() == "this") { // 'this' instance is not completely constructed in initialization list + allowed = false; + return ChildrenToVisit::done; + } else if (Token::Match(tok2, "%name% (") && tok2->strAt(-1) != "." && isMemberFunc(owner, tok2)) { // Member function called? + allowed = false; + return ChildrenToVisit::done; } - } + return ChildrenToVisit::op1_and_op2; + }); + if (!allowed) + continue; + + suggestInitializationList(tok, tok->str()); } } } diff --git a/test/testclass.cpp b/test/testclass.cpp index 5c97ebe07..a9c03f327 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -6625,6 +6625,16 @@ private: " Foo(int a, const std::string& b) : Foo(a, bar(b)) {}\n" "};"); ASSERT_EQUALS("", errout.str()); + + checkInitializationListUsage("class Fred {\n" // #8111 + " std::string a;\n" + " Fred() {\n" + " std::ostringstream ostr;\n" + " ostr << x;\n" + " a = ostr.str();\n" + " }\n" + "};"); + ASSERT_EQUALS("", errout.str()); }