| 1242 | }; |
| 1243 | |
| 1244 | struct ExpressionAnalyzer : SingleValueFlowAnalyzer { |
| 1245 | const Token* expr; |
| 1246 | bool local = true; |
| 1247 | bool unknown{}; |
| 1248 | bool dependOnThis{}; |
| 1249 | bool uniqueExprId{}; |
| 1250 | |
| 1251 | ExpressionAnalyzer(const Token* e, ValueFlow::Value val, const Settings& s) |
| 1252 | : SingleValueFlowAnalyzer(std::move(val), s), |
| 1253 | expr(e) |
| 1254 | { |
| 1255 | |
| 1256 | assert(e && e->exprId() != 0 && "Not a valid expression"); |
| 1257 | dependOnThis = exprDependsOnThis(expr); |
| 1258 | setupExprVarIds(expr); |
| 1259 | if (value.isSymbolicValue()) { |
| 1260 | dependOnThis |= exprDependsOnThis(value.tokvalue); |
| 1261 | setupExprVarIds(value.tokvalue); |
| 1262 | } |
| 1263 | uniqueExprId = |
| 1264 | expr->isUniqueExprId() && (Token::Match(expr, "%cop%") || !isVariableChanged(expr, 0, s)); |
| 1265 | } |
| 1266 | |
| 1267 | static bool nonLocal(const Variable* var, bool deref) { |
| 1268 | return !var || (!var->isLocal() && !var->isArgument()) || (deref && var->isArgument() && var->isPointer()) || |
| 1269 | var->isStatic() || var->isReference() || var->isExtern(); |
| 1270 | } |
| 1271 | |
| 1272 | void setupExprVarIds(const Token* start, int depth = 0) { |
| 1273 | if (depth > settings.vfOptions.maxExprVarIdDepth) { |
| 1274 | // TODO: add bailout message |
| 1275 | return; |
| 1276 | } |
| 1277 | visitAstNodes(start, [&](const Token* tok) { |
| 1278 | const bool top = depth == 0 && tok == start; |
| 1279 | const bool ispointer = astIsPointer(tok) || astIsSmartPointer(tok) || astIsIterator(tok); |
| 1280 | if (!top || !ispointer || value.indirect != 0) { |
| 1281 | for (const ValueFlow::Value& v : tok->values()) { |
| 1282 | if (!(v.isLocalLifetimeValue() || (ispointer && v.isSymbolicValue() && v.isKnown()))) |
| 1283 | continue; |
| 1284 | if (!v.tokvalue) |
| 1285 | continue; |
| 1286 | if (v.tokvalue == tok) |
| 1287 | continue; |
| 1288 | setupExprVarIds(v.tokvalue, depth + 1); |
| 1289 | } |
| 1290 | } |
| 1291 | if (depth == 0 && tok->isIncompleteVar()) { |
| 1292 | // TODO: Treat incomplete var as global, but we need to update |
| 1293 | // the alias variables to just expr ids instead of requiring |
| 1294 | // Variable |
| 1295 | unknown = true; |
| 1296 | return ChildrenToVisit::none; |
| 1297 | } |
| 1298 | if (tok->varId() > 0) { |
| 1299 | varids[tok->varId()] = tok->variable(); |
| 1300 | if (!Token::simpleMatch(tok->previous(), ".")) { |
| 1301 | const Variable* var = tok->variable(); |
no outgoing calls
no test coverage detected