Cppcheck
findtoken.h
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 //---------------------------------------------------------------------------
20 #ifndef findtokenH
21 #define findtokenH
22 //---------------------------------------------------------------------------
23 
24 #include <functional>
25 #include <stack>
26 #include <string>
27 #include <type_traits>
28 #include <vector>
29 
30 #include "config.h"
31 #include "errortypes.h"
32 #include "library.h"
33 #include "smallvector.h"
34 #include "symboldatabase.h"
35 #include "token.h"
36 
37 inline std::vector<MathLib::bigint> evaluateKnownValues(const Token* tok)
38 {
39  if (!tok->hasKnownIntValue())
40  return {};
41  return {tok->getKnownIntValue()};
42 }
43 
44 template<class T, class Predicate, class Found, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
45 void findTokensImpl(T* start, const Token* end, const Predicate& pred, Found found)
46 {
47  for (T* tok = start; precedes(tok, end); tok = tok->next()) {
48  if (pred(tok)) {
49  if (found(tok))
50  break;
51  }
52  }
53 }
54 
55 template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
56 std::vector<T*> findTokens(T* start, const Token* end, const Predicate& pred)
57 {
58  std::vector<T*> result;
59  findTokensImpl(start, end, pred, [&](T* tok) {
60  result.push_back(tok);
61  return false;
62  });
63  return result;
64 }
65 
66 template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
67 T* findToken(T* start, const Token* end, const Predicate& pred)
68 {
69  T* result = nullptr;
70  findTokensImpl(start, end, pred, [&](T* tok) {
71  result = tok;
72  return true;
73  });
74  return result;
75 }
76 
77 template<class T,
78  class Predicate,
79  class Found,
80  class Evaluate,
81  REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
82 bool findTokensSkipDeadCodeImpl(const Library& library,
83  T* start,
84  const Token* end,
85  const Predicate& pred,
86  Found found,
87  const Evaluate& evaluate)
88 {
89  for (T* tok = start; precedes(tok, end); tok = tok->next()) {
90  if (pred(tok)) {
91  if (found(tok))
92  return true;
93  }
94  if (Token::Match(tok, "if|for|while (") && Token::simpleMatch(tok->next()->link(), ") {")) {
95  const Token* condTok = getCondTok(tok);
96  if (!condTok)
97  continue;
98  auto result = evaluate(condTok);
99  if (result.empty())
100  continue;
101  if (findTokensSkipDeadCodeImpl(library, tok->next(), tok->linkAt(1), pred, found, evaluate))
102  return true;
103  T* thenStart = tok->linkAt(1)->next();
104  T* elseStart = nullptr;
105  if (Token::simpleMatch(thenStart->link(), "} else {"))
106  elseStart = thenStart->link()->tokAt(2);
107 
108  int r = result.front();
109  if (r == 0) {
110  if (elseStart) {
111  if (findTokensSkipDeadCodeImpl(library, elseStart, elseStart->link(), pred, found, evaluate))
112  return true;
113  if (isReturnScope(elseStart->link(), library))
114  return true;
115  tok = elseStart->link();
116  } else {
117  tok = thenStart->link();
118  }
119  } else {
120  if (findTokensSkipDeadCodeImpl(library, thenStart, thenStart->link(), pred, found, evaluate))
121  return true;
122  if (isReturnScope(thenStart->link(), library))
123  return true;
124  tok = thenStart->link();
125  }
126  } else if (Token::Match(tok->astParent(), "&&|?|%oror%") && astIsLHS(tok)) {
127  auto result = evaluate(tok);
128  if (result.empty())
129  continue;
130  const bool cond = result.front() != 0;
131  T* next = nullptr;
132  if ((cond && Token::simpleMatch(tok->astParent(), "||")) ||
133  (!cond && Token::simpleMatch(tok->astParent(), "&&"))) {
134  next = nextAfterAstRightmostLeaf(tok->astParent());
135  } else if (Token::simpleMatch(tok->astParent(), "?")) {
136  T* colon = tok->astParent()->astOperand2();
137  if (!cond) {
138  next = colon;
139  } else {
140  if (findTokensSkipDeadCodeImpl(library, tok->astParent()->next(), colon, pred, found, evaluate))
141  return true;
142  next = nextAfterAstRightmostLeaf(colon);
143  }
144  }
145  if (next)
146  tok = next;
147  } else if (Token::simpleMatch(tok, "} else {")) {
148  const Token* condTok = getCondTokFromEnd(tok);
149  if (!condTok)
150  continue;
151  auto result = evaluate(condTok);
152  if (result.empty())
153  continue;
154  if (isReturnScope(tok->link(), library))
155  return true;
156  int r = result.front();
157  if (r != 0) {
158  tok = tok->linkAt(2);
159  }
160  } else if (Token::simpleMatch(tok, "[") && Token::Match(tok->link(), "] (|{")) {
161  T* afterCapture = tok->link()->next();
162  if (Token::simpleMatch(afterCapture, "(") && afterCapture->link())
163  tok = afterCapture->link()->next();
164  else
165  tok = afterCapture;
166  }
167  }
168  return false;
169 }
170 
171 template<class T, class Predicate, class Evaluate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
172 std::vector<T*> findTokensSkipDeadCode(const Library& library,
173  T* start,
174  const Token* end,
175  const Predicate& pred,
176  const Evaluate& evaluate)
177 {
178  std::vector<T*> result;
180  library,
181  start,
182  end,
183  pred,
184  [&](T* tok) {
185  result.push_back(tok);
186  return false;
187  },
188  evaluate);
189  return result;
190 }
191 
192 template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
193 std::vector<T*> findTokensSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred)
194 {
195  return findTokensSkipDeadCode(library, start, end, pred, &evaluateKnownValues);
196 }
197 
198 template<class T, class Predicate, class Evaluate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
199 T* findTokenSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred, const Evaluate& evaluate)
200 {
201  T* result = nullptr;
203  library,
204  start,
205  end,
206  pred,
207  [&](T* tok) {
208  result = tok;
209  return true;
210  },
211  evaluate);
212  return result;
213 }
214 
215 template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
216 T* findTokenSkipDeadCode(const Library& library, T* start, const Token* end, const Predicate& pred)
217 {
218  return findTokenSkipDeadCode(library, start, end, pred, &evaluateKnownValues);
219 }
220 
221 #endif // findtokenH
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:987
bool astIsLHS(const Token *tok)
Definition: astutils.cpp:784
Token * getCondTokFromEnd(Token *endBlock)
Definition: astutils.cpp:882
Token * getCondTok(Token *tok)
Definition: astutils.cpp:873
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Definition: astutils.cpp:548
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
Library definitions handling.
Definition: library.h:52
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
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 hasKnownIntValue() const
Definition: token.cpp:2553
MathLib::bigint getKnownIntValue() const
Definition: token.h:1218
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
#define REQUIRES(msg,...)
Definition: config.h:124
T * findToken(T *start, const Token *end, const Predicate &pred)
Definition: findtoken.h:67
T * findTokenSkipDeadCode(const Library &library, T *start, const Token *end, const Predicate &pred, const Evaluate &evaluate)
Definition: findtoken.h:199
void findTokensImpl(T *start, const Token *end, const Predicate &pred, Found found)
Definition: findtoken.h:45
std::vector< MathLib::bigint > evaluateKnownValues(const Token *tok)
Definition: findtoken.h:37
std::vector< T * > findTokensSkipDeadCode(const Library &library, T *start, const Token *end, const Predicate &pred, const Evaluate &evaluate)
Definition: findtoken.h:172
bool findTokensSkipDeadCodeImpl(const Library &library, T *start, const Token *end, const Predicate &pred, Found found, const Evaluate &evaluate)
Definition: findtoken.h:82
std::vector< T * > findTokens(T *start, const Token *end, const Predicate &pred)
Definition: findtoken.h:56
static ValueFlow::Value evaluate(const std::string &op, const ValueFlow::Value &lhs, const ValueFlow::Value &rhs)