Cppcheck
fwdanalysis.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "fwdanalysis.h"
20 
21 #include "astutils.h"
22 #include "config.h"
23 #include "library.h"
24 #include "settings.h"
25 #include "symboldatabase.h"
26 #include "token.h"
27 #include "vfvalue.h"
28 
29 #include <list>
30 #include <map>
31 #include <string>
32 
33 static bool isUnchanged(const Token *startToken, const Token *endToken, const std::set<nonneg int> &exprVarIds, bool local)
34 {
35  for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
36  if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {"))
37  // TODO: this is a quick bailout
38  return false;
39  if (tok->varId() == 0 || exprVarIds.find(tok->varId()) == exprVarIds.end())
40  continue;
41  const Token *parent = tok;
42  while (parent->astParent() && !parent->astParent()->isAssignmentOp() && parent->astParent()->tokType() != Token::Type::eIncDecOp) {
43  if (parent->str() == "," || parent->isUnaryOp("&"))
44  // TODO: This is a quick bailout
45  return false;
46  parent = parent->astParent();
47  }
48  if (parent->astParent()) {
49  if (parent->astParent()->tokType() == Token::Type::eIncDecOp)
50  return false;
51  if (parent->astParent()->isAssignmentOp() && parent == parent->astParent()->astOperand1())
52  return false;
53  }
54  }
55  return true;
56 }
57 
58 static bool hasFunctionCall(const Token *tok)
59 {
60  if (!tok)
61  return false;
62  if (Token::Match(tok, "%name% ("))
63  // todo, const/pure function?
64  return true;
65  return hasFunctionCall(tok->astOperand1()) || hasFunctionCall(tok->astOperand2());
66 }
67 
68 static bool hasGccCompoundStatement(const Token *tok)
69 {
70  if (!tok)
71  return false;
72  if (tok->str() == "{" && Token::simpleMatch(tok->previous(), "( {"))
73  return true;
75 }
76 
77 static bool nonLocal(const Variable* var, bool deref)
78 {
79  return !var || (!var->isLocal() && !var->isArgument()) || (deref && var->isArgument() && var->isPointer()) || var->isStatic() || var->isReference() || var->isExtern();
80 }
81 
82 static bool hasVolatileCastOrVar(const Token *expr)
83 {
84  bool ret = false;
85  visitAstNodes(expr,
86  [&ret](const Token *tok) {
87  if (tok->variable() && tok->variable()->isVolatile())
88  ret = true;
89  else if (Token::simpleMatch(tok, "( volatile"))
90  ret = true;
92  });
93  return ret;
94 }
95 
96 FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<nonneg int> &exprVarIds, bool local, bool inInnerClass, int depth)
97 {
98  // Parse the given tokens
99  if (++depth > 1000)
101 
102  for (const Token* tok = startToken; precedes(tok, endToken); tok = tok->next()) {
103  if (Token::simpleMatch(tok, "try {")) {
104  // TODO: handle try
106  }
107 
108  if (Token::simpleMatch(tok, "break ;")) {
109  return Result(Result::Type::BREAK, tok);
110  }
111 
112  if (Token::simpleMatch(tok, "goto"))
114 
115  if (!inInnerClass && tok->str() == "{" && tok->scope()->isClassOrStruct()) {
116  // skip returns from local class definition
117  FwdAnalysis::Result result = checkRecursive(expr, tok, tok->link(), exprVarIds, local, true, depth);
118  if (result.type != Result::Type::NONE)
119  return result;
120  tok=tok->link();
121  }
122 
123  if (tok->str() == "continue")
124  // TODO
126 
127  if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
128  tok = lambdaEndToken;
129  const Result lambdaResult = checkRecursive(expr, lambdaEndToken->link()->next(), lambdaEndToken, exprVarIds, local, inInnerClass, depth);
130  if (lambdaResult.type == Result::Type::READ || lambdaResult.type == Result::Type::BAILOUT)
131  return lambdaResult;
132  }
133 
134  if (Token::Match(tok, "return|throw")) {
135  // TODO: Handle these better
136  // Is expr variable used in expression?
137 
138  const Token* opTok = tok->astOperand1();
139  if (!opTok)
140  opTok = tok->next();
141  std::pair<const Token*, const Token*> startEndTokens = opTok->findExpressionStartEndTokens();
142  FwdAnalysis::Result result =
143  checkRecursive(expr, startEndTokens.first, startEndTokens.second->next(), exprVarIds, local, true, depth);
144  if (result.type != Result::Type::NONE)
145  return result;
146 
147  // #9167: if the return is inside an inner class, it does not tell us anything
148  if (!inInnerClass) {
149  if (!local && mWhat == What::Reassign)
151 
153  }
154  }
155 
156  if (tok->str() == "}") {
157  // Known value => possible value
158  if (tok->scope() == expr->scope())
159  mValueFlowKnown = false;
160 
161  if (tok->scope()->isLoopScope()) {
162  // check condition
163  const Token *conditionStart = nullptr;
164  const Token *conditionEnd = nullptr;
165  if (Token::simpleMatch(tok->link()->previous(), ") {")) {
166  conditionEnd = tok->link()->previous();
167  conditionStart = conditionEnd->link();
168  } else if (Token::simpleMatch(tok->link()->previous(), "do {") && Token::simpleMatch(tok, "} while (")) {
169  conditionStart = tok->tokAt(2);
170  conditionEnd = conditionStart->link();
171  }
172  if (conditionStart && conditionEnd) {
173  bool used = false;
174  for (const Token *condTok = conditionStart; condTok != conditionEnd; condTok = condTok->next()) {
175  if (exprVarIds.find(condTok->varId()) != exprVarIds.end()) {
176  used = true;
177  break;
178  }
179  }
180  if (used)
182  }
183 
184  // check loop body again..
185  const FwdAnalysis::Result &result = checkRecursive(expr, tok->link(), tok, exprVarIds, local, inInnerClass, depth);
186  if (result.type == Result::Type::BAILOUT || result.type == Result::Type::READ)
187  return result;
188  }
189  }
190 
191  if (Token::simpleMatch(tok, "else {"))
192  tok = tok->linkAt(1);
193 
194  if (Token::simpleMatch(tok, "asm ("))
196 
197  if (mWhat == What::ValueFlow && (Token::Match(tok, "while|for (") || Token::simpleMatch(tok, "do {"))) {
198  const Token *bodyStart = nullptr;
199  const Token *conditionStart = nullptr;
200  if (Token::simpleMatch(tok, "do {")) {
201  bodyStart = tok->next();
202  if (Token::simpleMatch(bodyStart->link(), "} while ("))
203  conditionStart = bodyStart->link()->tokAt(2);
204  } else {
205  conditionStart = tok->next();
206  if (Token::simpleMatch(conditionStart->link(), ") {"))
207  bodyStart = conditionStart->link()->next();
208  }
209 
210  if (!bodyStart || !conditionStart)
212 
213  // Is expr changed in condition?
214  if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local))
216 
217  // Is expr changed in loop body?
218  if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local))
220  }
221 
222  if (mWhat == What::ValueFlow && Token::simpleMatch(tok, "if (") && Token::simpleMatch(tok->linkAt(1), ") {")) {
223  const Token *bodyStart = tok->linkAt(1)->next();
224  const Token *conditionStart = tok->next();
225  const Token *condTok = conditionStart->astOperand2();
226  if (condTok->hasKnownIntValue()) {
227  const bool cond = condTok->values().front().intvalue;
228  if (cond) {
229  FwdAnalysis::Result result = checkRecursive(expr, bodyStart, bodyStart->link(), exprVarIds, local, true, depth);
230  if (result.type != Result::Type::NONE)
231  return result;
232  } else if (Token::simpleMatch(bodyStart->link(), "} else {")) {
233  bodyStart = bodyStart->link()->tokAt(2);
234  FwdAnalysis::Result result = checkRecursive(expr, bodyStart, bodyStart->link(), exprVarIds, local, true, depth);
235  if (result.type != Result::Type::NONE)
236  return result;
237  }
238  }
239  tok = bodyStart->link();
240  if (isReturnScope(tok, mSettings.library))
242  if (Token::simpleMatch(tok, "} else {"))
243  tok = tok->linkAt(2);
244  if (!tok)
246 
247  // Is expr changed in condition?
248  if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local))
250 
251  // Is expr changed in condition body?
252  if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local))
254  }
255 
256  if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
257  // TODO: this is a quick bailout
259  }
260 
261  if (mWhat == What::Reassign &&
262  Token::simpleMatch(tok, ";") &&
263  Token::simpleMatch(tok->astParent(), ";") &&
264  Token::simpleMatch(tok->astParent()->astParent(), "(") &&
265  Token::simpleMatch(tok->astParent()->astParent()->previous(), "for (") &&
266  !isUnchanged(tok, tok->astParent()->astParent()->link(), exprVarIds, local))
267  // TODO: This is a quick bailout to avoid FP #9420, there are false negatives (TODO_ASSERT_EQUALS)
269 
270  if (expr->isName() && Token::Match(tok, "%name% (") && tok->str().find('<') != std::string::npos && tok->str().find(expr->str()) != std::string::npos)
272 
273  if (exprVarIds.find(tok->varId()) != exprVarIds.end()) {
274  const Token *parent = tok;
275  bool other = false;
276  bool same = tok->astParent() && isSameExpression(false, expr, tok, mSettings, true, false, nullptr);
277  while (!same && Token::Match(parent->astParent(), "*|.|::|[|(|%cop%")) {
278  parent = parent->astParent();
279  if (parent->str() == "(" && !parent->isCast())
280  break;
281  if (isSameExpression(false, expr, parent, mSettings, true, false, nullptr)) {
282  same = true;
283  if (mWhat == What::ValueFlow) {
284  KnownAndToken v;
286  v.token = parent;
287  mValueFlow.push_back(v);
288  }
289  }
290  if (Token::Match(parent, ". %var%") && parent->next()->varId() && exprVarIds.find(parent->next()->varId()) == exprVarIds.end() &&
291  isSameExpression(false, expr->astOperand1(), parent->astOperand1(), mSettings, true, false, nullptr)) {
292  other = true;
293  break;
294  }
295  }
296  if (mWhat != What::ValueFlow && same && Token::simpleMatch(parent->astParent(), "[") && parent == parent->astParent()->astOperand2()) {
297  return Result(Result::Type::READ);
298  }
299  if (other)
300  continue;
301  if (Token::simpleMatch(parent->astParent(), "=") && parent == parent->astParent()->astOperand1()) {
302  if (!local && hasFunctionCall(parent->astParent()->astOperand2())) {
303  // TODO: this is a quick bailout
305  }
306  if (hasOperand(parent->astParent()->astOperand2(), expr)) {
307  if (mWhat == What::Reassign)
308  return Result(Result::Type::READ);
309  continue;
310  }
311  const auto startEnd = parent->astParent()->astOperand2()->findExpressionStartEndTokens();
312  for (const Token* tok2 = startEnd.first; tok2 != startEnd.second; tok2 = tok2->next()) {
313  if (tok2->tokType() == Token::eLambda)
315  // TODO: analyze usage in lambda
316  }
317  // ({ .. })
318  if (hasGccCompoundStatement(parent->astParent()->astOperand2()))
320  // cppcheck-suppress shadowFunction - TODO: fix this
321  const bool reassign = isSameExpression(false, expr, parent, mSettings, false, false, nullptr);
322  if (reassign)
323  return Result(Result::Type::WRITE, parent->astParent());
324  return Result(Result::Type::READ);
325  }
326  if (mWhat == What::Reassign && parent->valueType() && parent->valueType()->pointer && Token::Match(parent->astParent(), "%assign%") && parent == parent->astParent()->astOperand1())
327  return Result(Result::Type::READ);
328 
329  if (Token::Match(parent->astParent(), "%assign%") && !parent->astParent()->astParent() && parent == parent->astParent()->astOperand1()) {
330  if (mWhat == What::Reassign)
331  return Result(Result::Type::BAILOUT, parent->astParent());
332  if (mWhat == What::UnusedValue && (!parent->valueType() || parent->valueType()->reference != Reference::None))
333  return Result(Result::Type::BAILOUT, parent->astParent());
334  continue;
335  }
336  if (mWhat == What::UnusedValue && parent->isUnaryOp("&") && Token::Match(parent->astParent(), "[,(]")) {
337  // Pass variable to function the writes it
338  const Token *ftok = parent->astParent();
339  while (Token::simpleMatch(ftok, ","))
340  ftok = ftok->astParent();
341  if (ftok && Token::Match(ftok->previous(), "%name% (")) {
342  const std::vector<const Token *> args = getArguments(ftok);
343  int argnr = 0;
344  while (argnr < args.size() && args[argnr] != parent)
345  argnr++;
346  if (argnr < args.size()) {
347  const Library::Function* functionInfo = mSettings.library.getFunction(ftok->astOperand1());
348  if (functionInfo) {
349  const auto it = functionInfo->argumentChecks.find(argnr + 1);
350  if (it != functionInfo->argumentChecks.end() && it->second.direction == Library::ArgumentChecks::Direction::DIR_OUT)
351  continue;
352  }
353  }
354  }
355  return Result(Result::Type::BAILOUT, parent->astParent());
356  }
357  // TODO: this is a quick bailout
358  return Result(Result::Type::BAILOUT, parent->astParent());
359  }
360 
361  if (Token::Match(tok, ")|do {")) {
362  if (tok->str() == ")" && Token::simpleMatch(tok->link()->previous(), "switch ("))
363  // TODO: parse switch
365  const Result &result1 = checkRecursive(expr, tok->tokAt(2), tok->linkAt(1), exprVarIds, local, inInnerClass, depth);
366  if (result1.type == Result::Type::READ || result1.type == Result::Type::BAILOUT)
367  return result1;
368  if (mWhat == What::UnusedValue && result1.type == Result::Type::WRITE && expr->variable() && expr->variable()->isReference())
369  return result1;
370  if (mWhat == What::ValueFlow && result1.type == Result::Type::WRITE)
371  mValueFlowKnown = false;
372  if (mWhat == What::Reassign && result1.type == Result::Type::BREAK) {
373  const Token *scopeEndToken = findNextTokenFromBreak(result1.token);
374  if (scopeEndToken) {
375  const Result &result2 = checkRecursive(expr, scopeEndToken->next(), endToken, exprVarIds, local, inInnerClass, depth);
376  if (result2.type == Result::Type::BAILOUT)
377  return result2;
378  }
379  }
380  if (Token::simpleMatch(tok->linkAt(1), "} else {")) {
381  const Token *elseStart = tok->linkAt(1)->tokAt(2);
382  const Result &result2 = checkRecursive(expr, elseStart, elseStart->link(), exprVarIds, local, inInnerClass, depth);
383  if (mWhat == What::ValueFlow && result2.type == Result::Type::WRITE)
384  mValueFlowKnown = false;
385  if (result2.type == Result::Type::READ || result2.type == Result::Type::BAILOUT)
386  return result2;
387  if (result1.type == Result::Type::WRITE && result2.type == Result::Type::WRITE)
388  return result1;
389  tok = elseStart->link();
390  } else {
391  tok = tok->linkAt(1);
392  }
393  }
394  }
395 
396  return Result(Result::Type::NONE);
397 }
398 
399 std::set<nonneg int> FwdAnalysis::getExprVarIds(const Token* expr, bool* localOut, bool* unknownVarIdOut) const
400 {
401  // all variable ids in expr.
402  std::set<nonneg int> exprVarIds;
403  bool local = true;
404  bool unknownVarId = false;
405  visitAstNodes(expr,
406  [&](const Token *tok) {
407  if (tok->str() == "[" && mWhat == What::UnusedValue)
408  return ChildrenToVisit::op1;
409  if (tok->varId() == 0 && tok->isName() && tok->previous()->str() != ".") {
410  // unknown variable
411  unknownVarId = true;
412  return ChildrenToVisit::none;
413  }
414  if (tok->varId() > 0) {
415  exprVarIds.insert(tok->varId());
416  if (!Token::simpleMatch(tok->previous(), ".")) {
417  const Variable *var = tok->variable();
418  if (var && var->isReference() && var->isLocal() && Token::Match(var->nameToken(), "%var% [=(]") && !isGlobalData(var->nameToken()->next()->astOperand2()))
419  return ChildrenToVisit::none;
420  const bool deref = tok->astParent() && (tok->astParent()->isUnaryOp("*") || (tok->astParent()->str() == "[" && tok == tok->astParent()->astOperand1()));
421  local &= !nonLocal(tok->variable(), deref);
422  }
423  }
425  });
426  if (localOut)
427  *localOut = local;
428  if (unknownVarIdOut)
429  *unknownVarIdOut = unknownVarId;
430  return exprVarIds;
431 }
432 
433 FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToken, const Token* endToken)
434 {
435  // all variable ids in expr.
436  bool local = true;
437  bool unknownVarId = false;
438  std::set<nonneg int> exprVarIds = getExprVarIds(expr, &local, &unknownVarId);
439 
440  if (unknownVarId)
442 
443  if (mWhat == What::Reassign && isGlobalData(expr))
444  local = false;
445 
446  // In unused values checking we do not want to check assignments to
447  // global data.
448  if (mWhat == What::UnusedValue && isGlobalData(expr))
450 
451  Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local, false);
452 
453  // Break => continue checking in outer scope
455  const Token *scopeEndToken = findNextTokenFromBreak(result.token);
456  if (!scopeEndToken)
457  break;
458  result = checkRecursive(expr, scopeEndToken->next(), endToken, exprVarIds, local, false);
459  }
460 
461  return result;
462 }
463 
464 bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const
465 {
466  if (!tok)
467  return false;
468  if (isSameExpression(false, tok, lhs, mSettings, false, false, nullptr))
469  return true;
470  return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs);
471 }
472 
473 const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, const Token *endToken)
474 {
475  if (hasVolatileCastOrVar(expr))
476  return nullptr;
478  Result result = check(expr, startToken, endToken);
479  return result.type == FwdAnalysis::Result::Type::WRITE ? result.token : nullptr;
480 }
481 
482 bool FwdAnalysis::unusedValue(const Token *expr, const Token *startToken, const Token *endToken)
483 {
484  if (isEscapedAlias(expr))
485  return false;
486  if (hasVolatileCastOrVar(expr))
487  return false;
488  if (Token::simpleMatch(expr, "[") && astIsContainerView(expr->astOperand1()))
489  return false;
491  Result result = check(expr, startToken, endToken);
492  return (result.type == FwdAnalysis::Result::Type::NONE || result.type == FwdAnalysis::Result::Type::RETURN) && !possiblyAliased(expr, startToken);
493 }
494 
495 bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) const
496 {
497  if (expr->isUnaryOp("*") && !expr->astOperand1()->isUnaryOp("&"))
498  return true;
499  if (Token::simpleMatch(expr, ". *"))
500  return true;
501 
502  const bool macro = false;
503  const bool pure = false;
504  const bool followVar = false;
505  for (const Token *tok = startToken; tok; tok = tok->previous()) {
506 
507  if (Token::Match(tok, "%name% (") && !Token::Match(tok, "if|while|for")) {
508  // Is argument passed by reference?
509  const std::vector<const Token*> args = getArguments(tok);
510  for (int argnr = 0; argnr < args.size(); ++argnr) {
511  if (!Token::Match(args[argnr], "%name%|.|::"))
512  continue;
513  if (tok->function() && tok->function()->getArgumentVar(argnr) && !tok->function()->getArgumentVar(argnr)->isReference() && !tok->function()->isConst())
514  continue;
515  for (const Token *subexpr = expr; subexpr; subexpr = subexpr->astOperand1()) {
516  if (isSameExpression(macro, subexpr, args[argnr], mSettings, pure, followVar)) {
517  const Scope* scope = expr->scope(); // if there is no other variable, assume no aliasing
518  if (scope->varlist.size() > 1)
519  return true;
520  }
521  }
522  }
523  continue;
524  }
525 
526  const Token *addrOf = nullptr;
527  if (Token::Match(tok, "& %name% ="))
528  addrOf = tok->tokAt(2)->astOperand2();
529  else if (tok->isUnaryOp("&"))
530  addrOf = tok->astOperand1();
531  else if (Token::simpleMatch(tok, "std :: ref ("))
532  addrOf = tok->tokAt(3)->astOperand2();
533  else if (tok->valueType() && tok->valueType()->pointer &&
534  (Token::Match(tok, "%var% = %var% ;") || Token::Match(tok, "%var% {|( %var% }|)")) &&
535  Token::Match(expr->previous(), "%varid% [", tok->tokAt(2)->varId()))
536  addrOf = tok->tokAt(2);
537  else
538  continue;
539 
540  for (const Token *subexpr = expr; subexpr; subexpr = subexpr->astOperand1()) {
541  if (subexpr != addrOf && isSameExpression(macro, subexpr, addrOf, mSettings, pure, followVar))
542  return true;
543  }
544  }
545  return false;
546 }
547 
549 {
550  for (const Token *subexpr = expr; subexpr; subexpr = subexpr->astOperand1()) {
551  for (const ValueFlow::Value &val : subexpr->values()) {
552  if (!val.isLocalLifetimeValue())
553  continue;
554  const Variable* var = val.tokvalue->variable();
555  if (!var)
556  continue;
557  if (!var->isLocal())
558  return true;
559  if (var->isArgument())
560  return true;
561 
562  }
563  }
564  return false;
565 }
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3078
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Definition: astutils.cpp:1549
bool astIsContainerView(const Token *tok)
Definition: astutils.cpp:254
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:987
bool isGlobalData(const Token *expr)
Definition: astutils.cpp:3509
const Token * findNextTokenFromBreak(const Token *breakToken)
For a "break" token, locate the next token to execute.
Definition: astutils.cpp:905
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
Definition: astutils.cpp:3190
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
Definition: astutils.cpp:2197
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
Definition: astutils.h:54
const Settings & mSettings
Definition: fwdanalysis.h:85
bool possiblyAliased(const Token *expr, const Token *startToken) const
Is there some possible alias for given expression.
std::vector< KnownAndToken > mValueFlow
Definition: fwdanalysis.h:87
bool hasOperand(const Token *tok, const Token *lhs) const
enum FwdAnalysis::What mWhat
bool mValueFlowKnown
Definition: fwdanalysis.h:88
static bool isEscapedAlias(const Token *expr)
Result check(const Token *expr, const Token *startToken, const Token *endToken)
Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set< nonneg int > &exprVarIds, bool local, bool inInnerClass, int depth=0)
Definition: fwdanalysis.cpp:96
std::set< nonneg int > getExprVarIds(const Token *expr, bool *localOut=nullptr, bool *unknownVarIdOut=nullptr) const
const Token * reassign(const Token *expr, const Token *startToken, const Token *endToken)
Check if "expr" is reassigned.
bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken)
Check if "expr" is used.
const Function * getFunction(const Token *ftok) const
Definition: library.cpp:1458
std::list< Variable > varlist
Library library
Library.
Definition: settings.h:237
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
void str(T &&s)
Definition: token.h:179
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:722
bool isName() const
Definition: token.h:361
bool hasKnownIntValue() const
Definition: token.cpp:2553
const ValueType * valueType() const
Definition: token.h:331
void astOperand1(Token *tok)
Definition: token.cpp:1490
std::pair< const Token *, const Token * > findExpressionStartEndTokens() const
Definition: token.cpp:1548
nonneg int varId() const
Definition: token.h:870
bool isCast() const
Definition: token.h:458
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
const Token * tokAt(int index) const
Definition: token.cpp:427
void astOperand2(Token *tok)
Definition: token.cpp:1502
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:447
@ eLambda
Definition: token.h:165
Token * previous()
Definition: token.h:862
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
Token * next()
Definition: token.h:830
const std::list< ValueFlow::Value > & values() const
Definition: token.h:1197
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:252
void astParent(Token *tok)
Definition: token.cpp:1471
Reference reference
Is the outermost indirection of this type a reference or rvalue.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isExtern() const
Is variable extern.
bool isReference() const
Is reference variable.
bool isLocal() const
Is variable local.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
static bool hasFunctionCall(const Token *tok)
Definition: fwdanalysis.cpp:58
static bool hasVolatileCastOrVar(const Token *expr)
Definition: fwdanalysis.cpp:82
static bool nonLocal(const Variable *var, bool deref)
Definition: fwdanalysis.cpp:77
static bool isUnchanged(const Token *startToken, const Token *endToken, const std::set< nonneg int > &exprVarIds, bool local)
Definition: fwdanalysis.cpp:33
static bool hasGccCompoundStatement(const Token *tok)
Definition: fwdanalysis.cpp:68
Result of forward analysis.
Definition: fwdanalysis.h:75
enum FwdAnalysis::Result::Type type
const Token * token
Definition: fwdanalysis.h:79
@ DIR_OUT
Output to caller. Data is passed by reference or address and is potentially written.
std::map< int, ArgumentChecks > argumentChecks
Definition: library.h:314