diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 65f6cb1f3..3900dc2ba 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -942,7 +942,7 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, settings, inconclusive); } -static bool isScopeBracket(const Token *tok) +bool isScopeBracket(const Token* tok) { if (!Token::Match(tok, "{|}")) return false; @@ -1222,30 +1222,17 @@ int numberOfArguments(const Token *start) return arguments; } -static void getArgumentsRecursive(const Token *tok, std::vector *arguments, nonneg int depth) -{ - ++depth; - if (!tok || depth >= 100) - return; - if (tok->str() == ",") { - getArgumentsRecursive(tok->astOperand1(), arguments, depth); - getArgumentsRecursive(tok->astOperand2(), arguments, depth); - } else { - arguments->push_back(tok); - } -} - std::vector getArguments(const Token *ftok) { - std::vector arguments; - const Token *tok = ftok->next(); - if (!Token::Match(tok, "(|{")) - tok = ftok; + const Token* tok = ftok; + if (Token::Match(tok, "%name% (|{")) + tok = ftok->next(); + if (!Token::Match(tok, "(|{|[")) + return std::vector{}; const Token *startTok = tok->astOperand2(); - if (!startTok && Token::simpleMatch(tok->astOperand1(), ",")) + if (!startTok && tok->next() != tok->link()) startTok = tok->astOperand1(); - getArgumentsRecursive(startTok, &arguments, 0); - return arguments; + return astFlatten(startTok, ","); } const Token *findLambdaStartToken(const Token *last) diff --git a/lib/astutils.h b/lib/astutils.h index 89f10afe6..29619b945 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -191,6 +191,8 @@ bool isConstVarExpression(const Token *tok); const Variable *getLHSVariable(const Token *tok); +bool isScopeBracket(const Token* tok); + struct PathAnalysis { enum class Progress { Continue, diff --git a/lib/token.cpp b/lib/token.cpp index fa4f92cf1..5d5caab13 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1936,6 +1936,8 @@ const ::Type *Token::typeOf(const Token *tok) return Token::typeOf(tok->astOperand1()); } else if (Token::simpleMatch(tok, ".")) { return Token::typeOf(tok->astOperand2()); + } else if (Token::simpleMatch(tok, "[")) { + return Token::typeOf(tok->astOperand1()); } return nullptr; } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 7c97af3de..0a7767d4a 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3324,11 +3324,13 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog settings); } // Constructor - } else if (Token::Match(parent->previous(), "=|return|%type%|%var% {")) { + } else if (Token::simpleMatch(parent, "{") && !isScopeBracket(parent)) { valueFlowLifetimeConstructor(parent, tokenlist, errorLogger, settings); + valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings); // Function call } else if (Token::Match(parent->previous(), "%name% (")) { valueFlowLifetimeFunction(parent->previous(), tokenlist, errorLogger, settings); + valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings); // Variable } else if (tok->variable()) { const Variable *var = tok->variable(); @@ -3567,37 +3569,55 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog } } -static void valueFlowLifetimeConstructor(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) +static void valueFlowLifetimeConstructor(Token* tok, + const Type* t, + TokenList* tokenlist, + ErrorLogger* errorLogger, + const Settings* settings) +{ + if (!t) + return; + if (!Token::Match(tok, "(|{")) + return; + const Scope* scope = t->classScope; + if (!scope) + return; + // Only support aggregate constructors for now + if (scope->numConstructors == 0 && t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) { + std::vector args = getArguments(tok); + std::size_t i = 0; + for (const Variable& var : scope->varlist) { + if (i >= args.size()) + break; + const Token* argtok = args[i]; + LifetimeStore ls{ + argtok, "Passed to constructor of '" + t->name() + "'.", ValueFlow::Value::LifetimeKind::Object}; + if (var.isReference() || var.isRValueReference()) { + ls.byRef(tok, tokenlist, errorLogger, settings); + } else { + ls.byVal(tok, tokenlist, errorLogger, settings); + } + i++; + } + } +} +static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) { if (!Token::Match(tok, "(|{")) return; - if (const Type *t = Token::typeOf(tok->previous())) { - const Scope *scope = t->classScope; - if (!scope) - return; - // Only support aggregate constructors for now - if (scope->numConstructors == 0 && t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) { - std::vector args = getArguments(tok); - std::size_t i = 0; - for (const Variable &var : scope->varlist) { - if (i >= args.size()) - break; - const Token *argtok = args[i]; - LifetimeStore ls{argtok, "Passed to constructor of '" + t->name() + "'.", ValueFlow::Value::LifetimeKind::Object}; - if (var.isReference() || var.isRValueReference()) { - ls.byRef(tok, tokenlist, errorLogger, settings); - } else { - ls.byVal(tok, tokenlist, errorLogger, settings); - } - i++; - } - } - } else if (Token::simpleMatch(tok, "{") && (astIsContainer(tok->astParent()) || astIsPointer(tok->astParent()))) { + Token* parent = tok->astParent(); + while (Token::simpleMatch(parent, ",")) + parent = parent->astParent(); + if (Token::simpleMatch(parent, "{") && (astIsContainer(parent->astParent()) || astIsPointer(parent->astParent()))) { + valueFlowLifetimeConstructor(tok, Token::typeOf(parent->previous()), tokenlist, errorLogger, settings); + } else if (Token::simpleMatch(tok, "{") && (astIsContainer(parent) || astIsPointer(parent))) { std::vector args = getArguments(tok); for (const Token *argtok : args) { LifetimeStore ls{argtok, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::Object}; ls.byVal(tok, tokenlist, errorLogger, settings); } + } else if (const Type* t = Token::typeOf(tok->previous())) { + valueFlowLifetimeConstructor(tok, t, tokenlist, errorLogger, settings); } } diff --git a/test/testcondition.cpp b/test/testcondition.cpp index dd55d2d75..c00615784 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -3351,6 +3351,21 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + // #9311 + check("struct c {\n" + " int* p;\n" + "};\n" + "void g(struct c* v);\n" + "void f() {\n" + " int a = 0;\n" + " int b = 0;\n" + " struct c d[] = {{&a}, {&b}};\n" + " g(d);\n" + " if (a) {}\n" + " if (b) {}\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + // #8993 check("void f(const std::string& x) {\n" " auto y = x;\n"