|
114 | 114 | #include <string> |
115 | 115 | #include <tuple> |
116 | 116 | #include <type_traits> |
| 117 | +#include <unordered_set> |
117 | 118 | #include <vector> |
118 | 119 |
|
119 | 120 | static void bailoutInternal(const std::string& type, TokenList *tokenlist, ErrorLogger *errorLogger, const Token *tok, const std::string &what, const std::string &file, int line, std::string function) |
@@ -1996,6 +1997,103 @@ struct ValueFlowAnalyzer : Analyzer { |
1996 | 1997 | return tokenlist->getSettings(); |
1997 | 1998 | } |
1998 | 1999 |
|
| 2000 | + struct ConditionState { |
| 2001 | + bool dependent = true; |
| 2002 | + bool unknown = true; |
| 2003 | + |
| 2004 | + bool isUnknownDependent() const { |
| 2005 | + return unknown && dependent; |
| 2006 | + } |
| 2007 | + }; |
| 2008 | + |
| 2009 | + std::unordered_map<nonneg int, const Token*> getSymbols(const Token* tok) const |
| 2010 | + { |
| 2011 | + std::unordered_map<nonneg int, const Token*> result; |
| 2012 | + if (!tok) |
| 2013 | + return result; |
| 2014 | + for (const ValueFlow::Value& v : tok->values()) { |
| 2015 | + if (!v.isSymbolicValue()) |
| 2016 | + continue; |
| 2017 | + if (v.isImpossible()) |
| 2018 | + continue; |
| 2019 | + if (!v.tokvalue) |
| 2020 | + continue; |
| 2021 | + if (v.tokvalue->exprId() == 0) |
| 2022 | + continue; |
| 2023 | + if (match(v.tokvalue)) |
| 2024 | + continue; |
| 2025 | + result[v.tokvalue->exprId()] = v.tokvalue; |
| 2026 | + } |
| 2027 | + return result; |
| 2028 | + } |
| 2029 | + |
| 2030 | + ConditionState analyzeCondition(const Token* tok, int depth = 20) const |
| 2031 | + { |
| 2032 | + ConditionState result; |
| 2033 | + if (!tok) |
| 2034 | + return result; |
| 2035 | + if (depth < 0) |
| 2036 | + return result; |
| 2037 | + depth--; |
| 2038 | + if (analyze(tok, Direction::Forward).isRead()) { |
| 2039 | + result.dependent = true; |
| 2040 | + result.unknown = false; |
| 2041 | + return result; |
| 2042 | + } else if (tok->hasKnownIntValue() || tok->isLiteral()) { |
| 2043 | + result.dependent = false; |
| 2044 | + result.unknown = false; |
| 2045 | + return result; |
| 2046 | + } else if (Token::Match(tok, "%cop%")) { |
| 2047 | + if (isLikelyStream(isCPP(), tok->astOperand1())) { |
| 2048 | + result.dependent = false; |
| 2049 | + return result; |
| 2050 | + } |
| 2051 | + ConditionState lhs = analyzeCondition(tok->astOperand1(), depth - 1); |
| 2052 | + if (lhs.isUnknownDependent()) |
| 2053 | + return lhs; |
| 2054 | + ConditionState rhs = analyzeCondition(tok->astOperand2(), depth - 1); |
| 2055 | + if (rhs.isUnknownDependent()) |
| 2056 | + return rhs; |
| 2057 | + if (Token::Match(tok, "%comp%")) |
| 2058 | + result.dependent = lhs.dependent && rhs.dependent; |
| 2059 | + else |
| 2060 | + result.dependent = lhs.dependent || rhs.dependent; |
| 2061 | + result.unknown = lhs.unknown || rhs.unknown; |
| 2062 | + return result; |
| 2063 | + } else if (Token::Match(tok->previous(), "%name% (")) { |
| 2064 | + std::vector<const Token*> args = getArguments(tok->previous()); |
| 2065 | + if (Token::Match(tok->tokAt(-2), ". %name% (")) { |
| 2066 | + args.push_back(tok->tokAt(-2)->astOperand1()); |
| 2067 | + } |
| 2068 | + result.dependent = std::any_of(args.begin(), args.end(), [&](const Token* arg) { |
| 2069 | + ConditionState cs = analyzeCondition(arg, depth - 1); |
| 2070 | + return cs.dependent; |
| 2071 | + }); |
| 2072 | + if (result.dependent) { |
| 2073 | + // Check if we can evaluate the function |
| 2074 | + if (!evaluate(Evaluate::Integral, tok).empty()) |
| 2075 | + result.unknown = false; |
| 2076 | + } |
| 2077 | + return result; |
| 2078 | + } else { |
| 2079 | + std::unordered_map<nonneg int, const Token*> symbols = getSymbols(tok); |
| 2080 | + result.dependent = false; |
| 2081 | + for (auto&& p : symbols) { |
| 2082 | + const Token* arg = p.second; |
| 2083 | + ConditionState cs = analyzeCondition(arg, depth - 1); |
| 2084 | + result.dependent = cs.dependent; |
| 2085 | + if (result.dependent) |
| 2086 | + break; |
| 2087 | + } |
| 2088 | + if (result.dependent) { |
| 2089 | + // Check if we can evaluate the token |
| 2090 | + if (!evaluate(Evaluate::Integral, tok).empty()) |
| 2091 | + result.unknown = false; |
| 2092 | + } |
| 2093 | + return result; |
| 2094 | + } |
| 2095 | + } |
| 2096 | + |
1999 | 2097 | virtual Action isModified(const Token* tok) const { |
2000 | 2098 | Action read = Action::Read; |
2001 | 2099 | bool inconclusive = false; |
@@ -2411,6 +2509,18 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer { |
2411 | 2509 | return false; |
2412 | 2510 | } |
2413 | 2511 |
|
| 2512 | + virtual bool stopOnCondition(const Token* condTok) const OVERRIDE |
| 2513 | + { |
| 2514 | + if (value.isNonValue()) |
| 2515 | + return false; |
| 2516 | + if (value.isImpossible()) |
| 2517 | + return false; |
| 2518 | + if (isConditional() && !value.isKnown() && !value.isImpossible()) |
| 2519 | + return true; |
| 2520 | + ConditionState cs = analyzeCondition(condTok); |
| 2521 | + return cs.isUnknownDependent(); |
| 2522 | + } |
| 2523 | + |
2414 | 2524 | virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE { |
2415 | 2525 | const Scope* scope = endBlock->scope(); |
2416 | 2526 | if (!scope) |
@@ -5807,6 +5917,10 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer { |
5807 | 5917 | return false; |
5808 | 5918 | } |
5809 | 5919 |
|
| 5920 | + virtual bool stopOnCondition(const Token*) const OVERRIDE { |
| 5921 | + return isConditional(); |
| 5922 | + } |
| 5923 | + |
5810 | 5924 | virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE { |
5811 | 5925 | const Scope* scope = endBlock->scope(); |
5812 | 5926 | if (!scope) |
|
0 commit comments