Fix 11673: FP uninitvar when capturing by reference (#4984)
* Fix 11673: FP uninitvar when capturing by reference * Format * Fix tests
This commit is contained in:
parent
b5ce2c708b
commit
9770dd7e0b
|
@ -7751,23 +7751,115 @@ static void addToErrorPath(ValueFlow::Value& value, const ValueFlow::Value& from
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<Token*> findAllUsages(const Variable* var, Token* start) // cppcheck-suppress constParameterPointer // FP
|
template<class Found, class Predicate>
|
||||||
|
bool findTokenSkipDeadCodeImpl(const Library* library, Token* start, const Token* end, Predicate pred, Found found)
|
||||||
|
{
|
||||||
|
for (Token* tok = start; precedes(tok, end); tok = tok->next()) {
|
||||||
|
if (pred(tok)) {
|
||||||
|
if (found(tok))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Token::simpleMatch(tok, "if (")) {
|
||||||
|
const Token* condTok = tok->next()->astOperand2();
|
||||||
|
if (!condTok)
|
||||||
|
continue;
|
||||||
|
if (!condTok->hasKnownIntValue())
|
||||||
|
continue;
|
||||||
|
if (!Token::simpleMatch(tok->linkAt(1), ") {"))
|
||||||
|
continue;
|
||||||
|
if (findTokenSkipDeadCodeImpl(library, tok->next(), tok->linkAt(1), pred, found))
|
||||||
|
return true;
|
||||||
|
Token* thenStart = tok->linkAt(1)->next();
|
||||||
|
Token* elseStart = nullptr;
|
||||||
|
if (Token::simpleMatch(thenStart->link(), "} else {"))
|
||||||
|
elseStart = thenStart->link()->tokAt(2);
|
||||||
|
|
||||||
|
int r = condTok->values().front().intvalue;
|
||||||
|
if (r == 0) {
|
||||||
|
if (elseStart) {
|
||||||
|
if (findTokenSkipDeadCodeImpl(library, elseStart, elseStart->link(), pred, found))
|
||||||
|
return true;
|
||||||
|
if (isReturnScope(elseStart->link(), library))
|
||||||
|
return true;
|
||||||
|
tok = elseStart->link();
|
||||||
|
} else {
|
||||||
|
tok = thenStart->link();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (findTokenSkipDeadCodeImpl(library, thenStart, thenStart->link(), pred, found))
|
||||||
|
return true;
|
||||||
|
if (isReturnScope(thenStart->link(), library))
|
||||||
|
return true;
|
||||||
|
tok = thenStart->link();
|
||||||
|
}
|
||||||
|
} else if (Token::Match(tok->astParent(), "&&|?|%oror%") && astIsLHS(tok) && tok->hasKnownIntValue()) {
|
||||||
|
int r = tok->values().front().intvalue;
|
||||||
|
Token* next = nullptr;
|
||||||
|
if ((r == 0 && Token::simpleMatch(tok->astParent(), "||")) ||
|
||||||
|
(r != 0 && Token::simpleMatch(tok->astParent(), "&&"))) {
|
||||||
|
next = nextAfterAstRightmostLeaf(tok->astParent());
|
||||||
|
} else if (Token::simpleMatch(tok->astParent(), "?")) {
|
||||||
|
Token* colon = tok->astParent()->astOperand2();
|
||||||
|
if (r == 0) {
|
||||||
|
next = colon;
|
||||||
|
} else {
|
||||||
|
if (findTokenSkipDeadCodeImpl(library, tok->astParent()->next(), colon, pred, found))
|
||||||
|
return true;
|
||||||
|
next = nextAfterAstRightmostLeaf(colon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next)
|
||||||
|
tok = next;
|
||||||
|
} else if (Token::simpleMatch(tok, "} else {")) {
|
||||||
|
const Token* condTok = getCondTokFromEnd(tok);
|
||||||
|
if (!condTok)
|
||||||
|
continue;
|
||||||
|
if (!condTok->hasKnownIntValue())
|
||||||
|
continue;
|
||||||
|
if (isReturnScope(tok->link(), library))
|
||||||
|
return true;
|
||||||
|
int r = condTok->values().front().intvalue;
|
||||||
|
if (r != 0) {
|
||||||
|
tok = tok->linkAt(1);
|
||||||
|
}
|
||||||
|
} else if (Token::simpleMatch(tok, "[") && Token::Match(tok->link(), "] (|{")) {
|
||||||
|
Token* afterCapture = tok->link()->next();
|
||||||
|
if (Token::simpleMatch(afterCapture, "(") && afterCapture->link())
|
||||||
|
tok = afterCapture->link()->next();
|
||||||
|
else
|
||||||
|
tok = afterCapture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Predicate>
|
||||||
|
std::vector<Token*> findTokensSkipDeadCode(const Library* library, Token* start, const Token* end, Predicate pred)
|
||||||
{
|
{
|
||||||
std::vector<Token*> result;
|
std::vector<Token*> result;
|
||||||
const Scope* scope = var->scope();
|
findTokenSkipDeadCodeImpl(library, start, end, pred, [&](Token* tok) {
|
||||||
if (!scope)
|
result.push_back(tok);
|
||||||
return result;
|
return false;
|
||||||
Token* tok2 = Token::findmatch(start, "%varid%", scope->bodyEnd, var->declarationId());
|
});
|
||||||
while (tok2) {
|
|
||||||
result.push_back(tok2);
|
|
||||||
tok2 = Token::findmatch(tok2->next(), "%varid%", scope->bodyEnd, var->declarationId());
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token* findStartToken(const Variable* var, Token* start)
|
static std::vector<Token*> findAllUsages(const Variable* var,
|
||||||
|
Token* start, // cppcheck-suppress constParameterPointer // FP
|
||||||
|
const Library* library)
|
||||||
{
|
{
|
||||||
std::vector<Token*> uses = findAllUsages(var, start);
|
// std::vector<Token*> result;
|
||||||
|
const Scope* scope = var->scope();
|
||||||
|
if (!scope)
|
||||||
|
return {};
|
||||||
|
return findTokensSkipDeadCode(library, start, scope->bodyEnd, [&](const Token* tok) {
|
||||||
|
return tok->varId() == var->declarationId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token* findStartToken(const Variable* var, Token* start, const Library* library)
|
||||||
|
{
|
||||||
|
std::vector<Token*> uses = findAllUsages(var, start, library);
|
||||||
if (uses.empty())
|
if (uses.empty())
|
||||||
return start;
|
return start;
|
||||||
Token* first = uses.front();
|
Token* first = uses.front();
|
||||||
|
@ -7823,7 +7915,7 @@ static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDataba
|
||||||
|
|
||||||
bool partial = false;
|
bool partial = false;
|
||||||
|
|
||||||
Token* start = findStartToken(var, tok->next());
|
Token* start = findStartToken(var, tok->next(), &settings->library);
|
||||||
|
|
||||||
std::map<Token*, ValueFlow::Value> partialReads;
|
std::map<Token*, ValueFlow::Value> partialReads;
|
||||||
if (const Scope* scope = var->typeScope()) {
|
if (const Scope* scope = var->typeScope()) {
|
||||||
|
|
|
@ -3498,7 +3498,7 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"}",
|
"}",
|
||||||
"test.cpp");
|
"test.cpp");
|
||||||
TODO_ASSERT_EQUALS("", "[test.cpp:6]: (error) Uninitialized variable: i\n", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
valueFlowUninit("void f() {\n"
|
valueFlowUninit("void f() {\n"
|
||||||
" int i, y;\n"
|
" int i, y;\n"
|
||||||
|
@ -3509,7 +3509,7 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"}",
|
"}",
|
||||||
"test.cpp");
|
"test.cpp");
|
||||||
TODO_ASSERT_EQUALS("", "[test.cpp:6]: (error) Uninitialized variable: i\n", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
valueFlowUninit("void f() {\n"
|
valueFlowUninit("void f() {\n"
|
||||||
" int i, y;\n"
|
" int i, y;\n"
|
||||||
|
@ -5970,6 +5970,15 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
// #11673
|
||||||
|
valueFlowUninit("void f() {\n"
|
||||||
|
" bool b;\n"
|
||||||
|
" auto g = [&b]() {\n"
|
||||||
|
" b = true;\n"
|
||||||
|
" };\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// #6619
|
// #6619
|
||||||
valueFlowUninit("void f() {\n"
|
valueFlowUninit("void f() {\n"
|
||||||
" int nok, i;\n"
|
" int nok, i;\n"
|
||||||
|
@ -5979,7 +5988,7 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
" printf(\"nok = %d\\n\", nok);\n"
|
" printf(\"nok = %d\\n\", nok);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:7]: (warning) Uninitialized variable: nok\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: nok\n", errout.str());
|
||||||
|
|
||||||
// #7475
|
// #7475
|
||||||
valueFlowUninit("struct S {\n"
|
valueFlowUninit("struct S {\n"
|
||||||
|
|
|
@ -5445,7 +5445,7 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
values = tokenValues(code, "i ++", ValueFlow::Value::ValueType::UNINIT);
|
values = tokenValues(code, "i ++", ValueFlow::Value::ValueType::UNINIT);
|
||||||
TODO_ASSERT_EQUALS(0, 1, values.size());
|
ASSERT_EQUALS(0, values.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowConditionExpressions() {
|
void valueFlowConditionExpressions() {
|
||||||
|
|
Loading…
Reference in New Issue