Revert "Revert "Skip forwarding values for unique expressions (#5103)"" (#5124)

This commit is contained in:
chrchr-github 2023-06-07 11:11:48 +02:00 committed by GitHub
parent 7d4472616b
commit ac86eda6b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 91 additions and 18 deletions

View File

@ -181,6 +181,9 @@ struct Analyzer {
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0;
/// Return analyzer for expression at token
virtual ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg = emptyString) const = 0;
virtual bool invalid() const {
return false;
}
virtual ~Analyzer() {}
Analyzer(const Analyzer&) = default;
protected:

View File

@ -894,6 +894,8 @@ struct ForwardTraversal {
Analyzer::Result valueFlowGenericForward(Token* start, const Token* end, const ValuePtr<Analyzer>& a, const Settings& settings)
{
if (a->invalid())
return Analyzer::Result{Analyzer::Action::None, Analyzer::Terminate::Bail};
ForwardTraversal ft{a, settings};
ft.updateRange(start, end);
return Analyzer::Result{ ft.actions, ft.terminate };
@ -903,6 +905,8 @@ Analyzer::Result valueFlowGenericForward(Token* start, const ValuePtr<Analyzer>&
{
if (Settings::terminated())
throw TerminateException();
if (a->invalid())
return Analyzer::Result{Analyzer::Action::None, Analyzer::Terminate::Bail};
ForwardTraversal ft{a, settings};
ft.updateRecursive(start);
return Analyzer::Result{ ft.actions, ft.terminate };

View File

@ -390,6 +390,8 @@ struct ReverseTraversal {
void valueFlowGenericReverse(Token* start, const Token* end, const ValuePtr<Analyzer>& a, const Settings& settings)
{
if (a->invalid())
return;
ReverseTraversal rt{a, settings};
rt.traverse(start, end);
}

View File

@ -1625,7 +1625,7 @@ void SymbolDatabase::createSymbolDatabaseExprIds()
exprs[tok->str()].push_back(tok);
tok->exprId(id++);
if (id == std::numeric_limits<nonneg int>::max()) {
if (id == std::numeric_limits<nonneg int>::max() / 4) {
throw InternalError(nullptr, "Ran out of expression ids.", InternalError::INTERNAL);
}
} else if (isCPP() && Token::simpleMatch(tok, "this")) {
@ -1653,6 +1653,27 @@ void SymbolDatabase::createSymbolDatabaseExprIds()
}
}
}
// Mark expressions that are unique
std::unordered_map<nonneg int, Token*> exprMap;
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (tok->exprId() == 0)
continue;
auto p = exprMap.emplace(tok->exprId(), tok);
// Already exists so set it to null
if (!p.second) {
p.first->second = nullptr;
}
}
for (const auto& p : exprMap) {
if (!p.second)
continue;
if (p.second->variable()) {
const Variable* var = p.second->variable();
if (var->nameToken() != p.second)
continue;
}
p.second->setUniqueExprId();
}
}
}

View File

@ -901,6 +901,20 @@ public:
mImpl->mExprId = id;
}
void setUniqueExprId()
{
assert(mImpl->mExprId > 0);
mImpl->mExprId |= 1 << efIsUnique;
}
bool isUniqueExprId() const
{
if (mImpl->mExprId > 0) {
return (mImpl->mExprId & (1 << efIsUnique)) != 0;
}
return false;
}
/**
* For debugging purposes, prints token and all tokens
* followed by it.
@ -1327,6 +1341,11 @@ private:
fIsFinalType = (1ULL << 40), // Is this a type with final specifier
};
enum : uint64_t {
efMaxSize = sizeof(nonneg int) * 8,
efIsUnique = efMaxSize - 2,
};
Token::Type mTokType;
uint64_t mFlags;

View File

@ -2438,10 +2438,6 @@ struct ValueFlowAnalyzer : Analyzer {
return false;
}
virtual bool invalid() const {
return false;
}
bool isCPP() const {
return tokenlist->isCPP();
}
@ -3134,11 +3130,20 @@ struct ExpressionAnalyzer : SingleValueFlowAnalyzer {
bool local;
bool unknown;
bool dependOnThis;
bool uniqueExprId;
ExpressionAnalyzer() : SingleValueFlowAnalyzer(), expr(nullptr), local(true), unknown(false), dependOnThis(false) {}
ExpressionAnalyzer()
: SingleValueFlowAnalyzer(), expr(nullptr), local(true), unknown(false), dependOnThis(false), uniqueExprId(false)
{}
ExpressionAnalyzer(const Token* e, ValueFlow::Value val, const TokenList* t, const Settings* s)
: SingleValueFlowAnalyzer(std::move(val), t, s), expr(e), local(true), unknown(false), dependOnThis(false) {
: SingleValueFlowAnalyzer(std::move(val), t, s),
expr(e),
local(true),
unknown(false),
dependOnThis(false),
uniqueExprId(false)
{
assert(e && e->exprId() != 0 && "Not a valid expression");
dependOnThis = exprDependsOnThis(expr);
@ -3147,6 +3152,8 @@ struct ExpressionAnalyzer : SingleValueFlowAnalyzer {
dependOnThis |= exprDependsOnThis(value.tokvalue);
setupExprVarIds(value.tokvalue);
}
uniqueExprId =
expr->isUniqueExprId() && (Token::Match(expr, "%cop%") || !isVariableChanged(expr, 0, s, t->isCPP()));
}
static bool nonLocal(const Variable* var, bool deref) {
@ -3196,7 +3203,13 @@ struct ExpressionAnalyzer : SingleValueFlowAnalyzer {
});
}
virtual bool skipUniqueExprIds() const {
return true;
}
bool invalid() const override {
if (skipUniqueExprIds() && uniqueExprId)
return true;
return unknown;
}
@ -3231,6 +3244,10 @@ struct SameExpressionAnalyzer : ExpressionAnalyzer {
: ExpressionAnalyzer(e, std::move(val), t, s)
{}
bool skipUniqueExprIds() const override {
return false;
}
bool match(const Token* tok) const override
{
return isSameExpression(isCPP(), true, expr, tok, getSettings()->library, true, true);
@ -3246,6 +3263,10 @@ struct OppositeExpressionAnalyzer : ExpressionAnalyzer {
: ExpressionAnalyzer(e, std::move(val), t, s), isNot(pIsNot)
{}
bool skipUniqueExprIds() const override {
return false;
}
bool match(const Token* tok) const override {
return isOppositeCond(isNot, isCPP(), expr, tok, getSettings()->library, true, true);
}

View File

@ -1602,7 +1602,9 @@ private:
"}";
checkSimplifyTypedef(code);
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
"[test.cpp:3]: (debug) valueflow.cpp:6541:(valueFlow) bailout: valueFlowAfterCondition: bailing in conditional block\n",
errout.str());
}
void simplifyTypedef46() {

View File

@ -3749,14 +3749,15 @@ private:
" return x + y + a.y + b.y;\n"
"}\n");
const char expected[] = "1: struct A {\n"
"2: int x ; int y ;\n"
"3: } ;\n"
"4: int f ( A a , A b ) {\n"
"5: int x@5 ; x@5 =@9 a@3 .@10 x@6 +@11 b@4 .@12 x@7 ;\n"
"6: int y@8 ; y@8 =@13 b@4 .@12 x@7 +@11 a@3 .@10 x@6 ;\n"
"7: return x@5 +@17 y@8 +@18 a@3 .@19 y@9 +@20 b@4 .@21 y@10 ;\n"
"8: }\n";
const char expected[] =
"1: struct A {\n"
"2: int x ; int y ;\n"
"3: } ;\n"
"4: int f ( A a , A b ) {\n"
"5: int x@5 ; x@5 =@9 a@3 .@10 x@6 +@11 b@4 .@12 x@7 ;\n"
"6: int y@8 ; y@8 =@1073741837 b@4 .@12 x@7 +@11 a@3 .@10 x@6 ;\n"
"7: return x@5 +@1073741841 y@8 +@1073741842 a@3 .@1073741843 y@9 +@1073741844 b@4 .@1073741845 y@10 ;\n"
"8: }\n";
ASSERT_EQUALS(expected, actual);
}
@ -3772,8 +3773,8 @@ private:
const char expected[] = "1: struct S { std :: unique_ptr < int > u ; } ;\n"
"2: auto f ; f = [ ] ( const S & s ) . std :: unique_ptr < int > {\n"
"3: if (@5 auto p@4 =@6 s@3 .@7 u@5 .@8 get (@9 ) ) {\n"
"4: return std ::@10 make_unique < int > (@11 *@12 p@4 ) ; }\n"
"3: if (@5 auto p@4 =@1073741830 s@3 .@1073741831 u@5 .@1073741832 get (@1073741833 ) ) {\n"
"4: return std ::@1073741834 make_unique < int > (@1073741835 *@1073741836 p@4 ) ; }\n"
"5: return nullptr ;\n"
"6: } ;\n";