diff --git a/lib/astutils.cpp b/lib/astutils.cpp index ed9c1e849..438ec487b 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1457,6 +1457,8 @@ const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, c bool FwdAnalysis::unusedValue(const Token *expr, const Token *startToken, const Token *endToken) { + if (isEscapedAlias(expr)) + return false; mWhat = What::UnusedValue; Result result = check(expr, startToken, endToken); return (result.type == FwdAnalysis::Result::Type::NONE || result.type == FwdAnalysis::Result::Type::RETURN) && !possiblyAliased(expr, startToken); @@ -1516,6 +1518,25 @@ bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) co return false; } +bool FwdAnalysis::isEscapedAlias(const Token* expr) +{ + for (const Token *subexpr = expr; subexpr; subexpr = subexpr->astOperand1()) { + for (const ValueFlow::Value &val : subexpr->values()) { + if (!val.isLocalLifetimeValue()) + continue; + const Variable* var = val.tokvalue->variable(); + if (!var) + continue; + if (!var->isLocal()) + return true; + if (var->isArgument()) + return true; + + } + } + return false; +} + bool FwdAnalysis::isNullOperand(const Token *expr) { if (!expr) diff --git a/lib/astutils.h b/lib/astutils.h index d4884bd6c..7e012445c 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -206,6 +206,8 @@ public: /** Is there some possible alias for given expression */ bool possiblyAliased(const Token *expr, const Token *startToken) const; + bool isEscapedAlias(const Token* expr); + static bool isNullOperand(const Token *expr); private: /** Result of forward analysis */ diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index c0151c9e6..9220239b0 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3342,7 +3342,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); } // container lifetimes - else if (tok->variable() && Token::Match(tok, "%var% . begin|cbegin|rbegin|crbegin|end|cend|rend|crend|data|c_str (")) { + else if (tok->variable() && Token::Match(tok, "%var% . begin|cbegin|rbegin|crbegin|end|cend|rend|crend|data|c_str|find (")) { ErrorPath errorPath; const Library::Container * container = settings->library.detectContainer(tok->variable()->typeStartToken()); if (!container) diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index d3cc96c20..42f2f8329 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -33,6 +33,7 @@ private: void run() OVERRIDE { settings.addEnabled("style"); + LOAD_LIB_2(settings.library, "std.cfg"); TEST_CASE(emptyclass); // #5355 - False positive: Variable is not assigned a value. TEST_CASE(emptystruct); // #5355 - False positive: Variable is not assigned a value. @@ -197,6 +198,7 @@ private: TEST_CASE(bracesInitCpp11);// #7895 - "int var{123}" initialization TEST_CASE(argument); + TEST_CASE(escapeAlias); // #9150 } void checkStructMemberUsage(const char code[]) { @@ -4538,6 +4540,22 @@ private: ); ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'foo.x' is assigned a value that is never used.\n", errout.str()); } + + void escapeAlias() { + functionVariableUsage( + "struct A {\n" + " std::map m;\n" + " void f(int key, int number) {\n" + " auto pos = m.find(key);\n" + " if (pos == m.end())\n" + " m.insert(std::map::value_type(key, number));\n" + " else\n" + " (*pos).second = number;\n" + " }\n" + "};\n" + ); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestUnusedVar)