This takes a token that refers to a variable and it will return the token to the expression that the variable is assigned to. If its not valid to make such substitution then it will return the original token.
| 1187 | /// to the expression that the variable is assigned to. If its not valid to |
| 1188 | /// make such substitution then it will return the original token. |
| 1189 | static const Token * followVariableExpression(const Settings& settings, const Token * tok, const Token * end = nullptr) |
| 1190 | { |
| 1191 | if (!tok) |
| 1192 | return tok; |
| 1193 | // Skip following variables that is across multiple files |
| 1194 | if (end && end->fileIndex() != tok->fileIndex()) |
| 1195 | return tok; |
| 1196 | // Skip array access |
| 1197 | if (Token::Match(tok, "%var% [")) |
| 1198 | return tok; |
| 1199 | // Skip pointer indirection |
| 1200 | if (tok->astParent() && tok->isUnaryOp("*")) |
| 1201 | return tok; |
| 1202 | // Skip following variables if it is used in an assignment |
| 1203 | if (Token::Match(tok->next(), "%assign%")) |
| 1204 | return tok; |
| 1205 | const Variable * var = tok->variable(); |
| 1206 | const Token * varTok = getVariableInitExpression(var); |
| 1207 | if (!varTok) |
| 1208 | return tok; |
| 1209 | if (hasUnknownVars(varTok)) |
| 1210 | return tok; |
| 1211 | if (astIsRangeBasedForDecl(var->nameToken())) |
| 1212 | return tok; |
| 1213 | if (var->isVolatile()) |
| 1214 | return tok; |
| 1215 | if (!var->isLocal() && !var->isConst()) |
| 1216 | return tok; |
| 1217 | if (var->isStatic() && !var->isConst()) |
| 1218 | return tok; |
| 1219 | if (var->isArgument()) |
| 1220 | return tok; |
| 1221 | if (isStructuredBindingVariable(var)) |
| 1222 | return tok; |
| 1223 | // assigning a floating point value to an integer does not preserve the value |
| 1224 | if (var->valueType() && var->valueType()->isIntegral() && varTok->valueType() && varTok->valueType()->isFloat()) |
| 1225 | return tok; |
| 1226 | const Token * lastTok = precedes(tok, end) ? end : tok; |
| 1227 | // If this is in a loop then check if variables are modified in the entire scope |
| 1228 | const Token * endToken = (isInLoopCondition(tok) || isInLoopCondition(varTok) || var->scope() != tok->scope()) ? var->scope()->bodyEnd : lastTok; |
| 1229 | const int indirect = var->isArray() ? var->dimensions().size() : 0; |
| 1230 | if (!var->isConst() && (!precedes(varTok, endToken) || isVariableChanged(varTok, endToken, indirect, tok->varId(), false, settings))) |
| 1231 | return tok; |
| 1232 | if (precedes(varTok, endToken) && isAliased(varTok, endToken, tok->varId())) |
| 1233 | return tok; |
| 1234 | const Token* startToken = nextAfterAstRightmostLeaf(varTok); |
| 1235 | if (!startToken) |
| 1236 | startToken = varTok; |
| 1237 | if (varTok->exprId() == 0) { |
| 1238 | if (!varTok->isLiteral()) |
| 1239 | return tok; |
| 1240 | } else if (!precedes(startToken, endToken)) { |
| 1241 | return tok; |
| 1242 | } else if (findExpressionChanged(varTok, startToken, endToken, settings)) { |
| 1243 | return tok; |
| 1244 | } |
| 1245 | return varTok; |
| 1246 | } |
no test coverage detected