/src/cppcheck/oss-fuzz/build/token.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "matchcompiler.h" |
2 | | #include <string> |
3 | | #include <cstring> |
4 | | #include "errorlogger.h" |
5 | | #include "token.h" |
6 | | // pattern: (|{|[|< |
7 | 887 | static inline bool match1(const Token* tok) { |
8 | 887 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))) |
9 | 721 | return false; |
10 | 166 | return true; |
11 | 887 | } |
12 | | // pattern: )|; |
13 | 3.91k | static inline bool match2(const Token* tok) { |
14 | 3.91k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString(";")))) |
15 | 3.18k | return false; |
16 | 721 | return true; |
17 | 3.91k | } |
18 | | // pattern: (|{|[ |
19 | 0 | static inline bool match3(const Token* tok) { |
20 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))) |
21 | 0 | return false; |
22 | 0 | return true; |
23 | 0 | } |
24 | | // pattern: >|; |
25 | 0 | static inline bool match4(const Token* tok) { |
26 | 0 | if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || (tok->str() == MatchCompiler::makeConstString(";")))) |
27 | 0 | return false; |
28 | 0 | return true; |
29 | 0 | } |
30 | | // pattern: ] |
31 | 64 | static inline bool match5(const Token* tok) { |
32 | 64 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]"))) |
33 | 64 | return false; |
34 | 0 | return true; |
35 | 64 | } |
36 | | // pattern: operator %op% < |
37 | 64 | static inline bool match6(const Token* tok) { |
38 | 64 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("operator"))) |
39 | 64 | return false; |
40 | 0 | tok = tok->next(); |
41 | 0 | if (!tok || !tok->isOp()) |
42 | 0 | return false; |
43 | 0 | tok = tok->next(); |
44 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
45 | 0 | return false; |
46 | 0 | return true; |
47 | 0 | } |
48 | | // pattern: operator [([] [)]] < |
49 | 64 | static inline bool match7(const Token* tok) { |
50 | 64 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("operator"))) |
51 | 64 | return false; |
52 | 0 | tok = tok->next(); |
53 | 0 | if (!tok || tok->str().size() != 1U || !strchr("([", tok->str()[0])) |
54 | 0 | return false; |
55 | 0 | tok = tok->next(); |
56 | 0 | if (!tok || tok->str().size() != 1U || !strchr(")]", tok->str()[0])) |
57 | 0 | return false; |
58 | 0 | tok = tok->next(); |
59 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
60 | 0 | return false; |
61 | 0 | return true; |
62 | 0 | } |
63 | | // pattern: template < |
64 | 2.94k | static inline bool match8(const Token* tok) { |
65 | 2.94k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("template"))) |
66 | 2.94k | return false; |
67 | 0 | tok = tok->next(); |
68 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
69 | 0 | return false; |
70 | 0 | return true; |
71 | 0 | } |
72 | | // pattern: [;{}] |
73 | 2.94k | static inline bool match9(const Token* tok) { |
74 | 2.94k | if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0])) |
75 | 2.44k | return false; |
76 | 508 | return true; |
77 | 2.94k | } |
78 | | // pattern: {|[|( |
79 | 2.05k | static inline bool match10(const Token* tok) { |
80 | 2.05k | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))) |
81 | 1.99k | return false; |
82 | 59 | return true; |
83 | 2.05k | } |
84 | | // pattern: }|]|)|; |
85 | 1.99k | static inline bool match11(const Token* tok) { |
86 | 1.99k | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString(";")))) |
87 | 1.52k | return false; |
88 | 475 | return true; |
89 | 1.99k | } |
90 | | // pattern: [,=] |
91 | 0 | static inline bool match12(const Token* tok) { |
92 | 0 | if (!tok || tok->str().size() != 1U || !strchr(",=", tok->str()[0])) |
93 | 0 | return false; |
94 | 0 | return true; |
95 | 0 | } |
96 | | // pattern: class|typename|. |
97 | 0 | static inline bool match13(const Token* tok) { |
98 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("typename")) || (tok->str() == MatchCompiler::makeConstString(".")))) |
99 | 0 | return false; |
100 | 0 | return true; |
101 | 0 | } |
102 | | // pattern: =|:: |
103 | 0 | static inline bool match14(const Token* tok) { |
104 | 0 | if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || (tok->str() == MatchCompiler::makeConstString("::")))) |
105 | 0 | return false; |
106 | 0 | return true; |
107 | 0 | } |
108 | | // pattern: }|]|) |
109 | 0 | static inline bool match15(const Token* tok) { |
110 | 0 | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))) |
111 | 0 | return false; |
112 | 0 | return true; |
113 | 0 | } |
114 | | // pattern: {|{|(|; |
115 | 0 | static inline bool match16(const Token* tok) { |
116 | 0 | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString(";")))) |
117 | 0 | return false; |
118 | 0 | return true; |
119 | 0 | } |
120 | | // pattern: const|volatile|final|override|&|&&|noexcept |
121 | 0 | static inline bool match17(const Token* tok) { |
122 | 0 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("final")) || (tok->str() == MatchCompiler::makeConstString("override")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->str() == MatchCompiler::makeConstString("noexcept")))) |
123 | 0 | return false; |
124 | 0 | return true; |
125 | 0 | } |
126 | | // pattern: throw|noexcept |
127 | 0 | static inline bool match18(const Token* tok) { |
128 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("throw")) || (tok->str() == MatchCompiler::makeConstString("noexcept")))) |
129 | 0 | return false; |
130 | 0 | return true; |
131 | 0 | } |
132 | | // pattern: :|, %name% |
133 | 0 | static inline bool match19(const Token* tok) { |
134 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))) |
135 | 0 | return false; |
136 | 0 | tok = tok->next(); |
137 | 0 | if (!tok || !tok->isName()) |
138 | 0 | return false; |
139 | 0 | return true; |
140 | 0 | } |
141 | | // pattern: %name% :: %name% |
142 | 0 | static inline bool match20(const Token* tok) { |
143 | 0 | if (!tok || !tok->isName()) |
144 | 0 | return false; |
145 | 0 | tok = tok->next(); |
146 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
147 | 0 | return false; |
148 | 0 | tok = tok->next(); |
149 | 0 | if (!tok || !tok->isName()) |
150 | 0 | return false; |
151 | 0 | return true; |
152 | 0 | } |
153 | | // pattern: :: %name% |
154 | 0 | static inline bool match21(const Token* tok) { |
155 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
156 | 0 | return false; |
157 | 0 | tok = tok->next(); |
158 | 0 | if (!tok || !tok->isName()) |
159 | 0 | return false; |
160 | 0 | return true; |
161 | 0 | } |
162 | | // pattern: %name%|> |
163 | 0 | static inline bool match22(const Token* tok) { |
164 | 0 | if (!tok || !(tok->isName() || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))) |
165 | 0 | return false; |
166 | 0 | return true; |
167 | 0 | } |
168 | | // pattern: namespace|class|struct|union %name% {|::|:|< |
169 | 0 | static inline bool match23(const Token* tok) { |
170 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("namespace")) || (tok->str() == MatchCompiler::makeConstString("class")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("struct")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union")))) |
171 | 0 | return false; |
172 | 0 | tok = tok->next(); |
173 | 0 | if (!tok || !tok->isName()) |
174 | 0 | return false; |
175 | 0 | tok = tok->next(); |
176 | 0 | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("::")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))) |
177 | 0 | return false; |
178 | 0 | return true; |
179 | 0 | } |
180 | | // pattern: {|:|< |
181 | 0 | static inline bool match24(const Token* tok) { |
182 | 0 | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))) |
183 | 0 | return false; |
184 | 0 | return true; |
185 | 0 | } |
186 | | // pattern: { |
187 | 19.7k | static inline bool match25(const Token* tok) { |
188 | 19.7k | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
189 | 19.7k | return false; |
190 | 0 | return true; |
191 | 19.7k | } |
192 | | // pattern: } |
193 | 0 | static inline bool match26(const Token* tok) { |
194 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))) |
195 | 0 | return false; |
196 | 0 | return true; |
197 | 0 | } |
198 | | // pattern: ;|{ |
199 | 0 | static inline bool match27(const Token* tok) { |
200 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
201 | 0 | return false; |
202 | 0 | return true; |
203 | 0 | } |
204 | | // pattern: using namespace %name% ::|; |
205 | 0 | static inline bool match28(const Token* tok) { |
206 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("using"))) |
207 | 0 | return false; |
208 | 0 | tok = tok->next(); |
209 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("namespace"))) |
210 | 0 | return false; |
211 | 0 | tok = tok->next(); |
212 | 0 | if (!tok || !tok->isName()) |
213 | 0 | return false; |
214 | 0 | tok = tok->next(); |
215 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString(";")))) |
216 | 0 | return false; |
217 | 0 | return true; |
218 | 0 | } |
219 | | // pattern: (|[|{ |
220 | 12.8k | static inline bool match29(const Token* tok) { |
221 | 12.8k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
222 | 12.8k | return false; |
223 | 0 | return true; |
224 | 12.8k | } |
225 | | // pattern: ( ::| %type% |
226 | 0 | static inline bool match30(const Token* tok) { |
227 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
228 | 0 | return false; |
229 | 0 | tok = tok->next(); |
230 | 0 | if (tok && ((tok->str() == MatchCompiler::makeConstString("::")))) |
231 | 0 | tok = tok->next(); |
232 | 0 | if (!tok || !(tok->isName() && tok->varId() == 0U)) |
233 | 0 | return false; |
234 | 0 | return true; |
235 | 0 | } |
236 | | // pattern: %cop%|++|-- |
237 | 0 | static inline bool match31(const Token* tok) { |
238 | 0 | if (!tok || !(tok->isConstOp() || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")))) |
239 | 0 | return false; |
240 | 0 | return true; |
241 | 0 | } |
242 | | // pattern: *|& |
243 | 0 | static inline bool match32(const Token* tok) { |
244 | 0 | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))) |
245 | 0 | return false; |
246 | 0 | return true; |
247 | 0 | } |
248 | | // pattern: %name%|%num% %name%|%num% |
249 | 42.3k | static inline bool match33(const Token* tok) { |
250 | 42.3k | if (!tok || !(tok->isName() || tok->isNumber())) |
251 | 18.4k | return false; |
252 | 23.9k | tok = tok->next(); |
253 | 23.9k | if (!tok || !(tok->isName() || tok->isNumber())) |
254 | 23.9k | return false; |
255 | 0 | return true; |
256 | 23.9k | } |
257 | | // pattern: ,|( |
258 | 0 | static inline bool match34(const Token* tok) { |
259 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))) |
260 | 0 | return false; |
261 | 0 | return true; |
262 | 0 | } |
263 | | // pattern: return |
264 | 5.97k | static inline bool match35(const Token* tok) { |
265 | 5.97k | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return"))) |
266 | 5.97k | return false; |
267 | 2 | return true; |
268 | 5.97k | } |
269 | | // pattern: %type%|= (|{ |
270 | 3.98k | static inline bool match36(const Token* tok) { |
271 | 3.98k | if (!tok || !((tok->isName() && tok->varId() == 0U) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))) |
272 | 3.64k | return false; |
273 | 336 | tok = tok->next(); |
274 | 336 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
275 | 336 | return false; |
276 | 0 | return true; |
277 | 336 | } |
278 | | // pattern: = |
279 | 5.97k | static inline bool match37(const Token* tok) { |
280 | 5.97k | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
281 | 5.97k | return false; |
282 | 0 | return true; |
283 | 5.97k | } |
284 | | // pattern: . |
285 | 5.97k | static inline bool match38(const Token* tok) { |
286 | 5.97k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
287 | 5.97k | return false; |
288 | 0 | return true; |
289 | 5.97k | } |
290 | | // pattern: [ |
291 | 3.98k | static inline bool match39(const Token* tok) { |
292 | 3.98k | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))) |
293 | 3.98k | return false; |
294 | 0 | return true; |
295 | 3.98k | } |
296 | | // pattern: auto |
297 | 1.47k | static inline bool match40(const Token* tok) { |
298 | 1.47k | if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("auto"))) |
299 | 1.47k | return false; |
300 | 0 | return true; |
301 | 1.47k | } |
302 | | // pattern: ; %varid% = |
303 | 0 | static inline bool match41(const Token* tok, const int varid) { |
304 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
305 | 0 | return false; |
306 | 0 | tok = tok->next(); |
307 | 0 | if (varid==0U) |
308 | 0 | throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers"); |
309 | 0 | if (!tok || !(tok->isName() && tok->varId() == varid)) |
310 | 0 | return false; |
311 | 0 | tok = tok->next(); |
312 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
313 | 0 | return false; |
314 | 0 | return true; |
315 | 0 | } |
316 | | // pattern: !!= |
317 | 0 | static inline bool match42(const Token* tok) { |
318 | 0 | if (tok && tok->str() == MatchCompiler::makeConstString("=")) |
319 | 0 | return false; |
320 | 0 | return true; |
321 | 0 | } |
322 | | // pattern: %name% :: |
323 | 0 | static inline bool match43(const Token* tok) { |
324 | 0 | if (!tok || !tok->isName()) |
325 | 0 | return false; |
326 | 0 | tok = tok->next(); |
327 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
328 | 0 | return false; |
329 | 0 | return true; |
330 | 0 | } |
331 | | // pattern: new |
332 | 0 | static inline bool match44(const Token* tok) { |
333 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("new"))) |
334 | 0 | return false; |
335 | 0 | return true; |
336 | 0 | } |
337 | | // pattern: ( |
338 | 0 | static inline bool match45(const Token* tok) { |
339 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
340 | 0 | return false; |
341 | 0 | return true; |
342 | 0 | } |
343 | | // pattern: < |
344 | 0 | static inline bool match46(const Token* tok) { |
345 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
346 | 0 | return false; |
347 | 0 | return true; |
348 | 0 | } |
349 | | // pattern: %name%|.|::|*|&|&&|<|(|template|decltype|sizeof |
350 | 0 | static inline bool match47(const Token* tok) { |
351 | 0 | if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("::")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("template")) || (tok->str() == MatchCompiler::makeConstString("decltype")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof")))) |
352 | 0 | return false; |
353 | 0 | return true; |
354 | 0 | } |
355 | | // pattern: (|< |
356 | 0 | static inline bool match48(const Token* tok) { |
357 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))) |
358 | 0 | return false; |
359 | 0 | return true; |
360 | 0 | } |
361 | | // pattern: ] (|{ |
362 | 0 | static inline bool match49(const Token* tok) { |
363 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]"))) |
364 | 0 | return false; |
365 | 0 | tok = tok->next(); |
366 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
367 | 0 | return false; |
368 | 0 | return true; |
369 | 0 | } |
370 | | // pattern: ) { |
371 | 0 | static inline bool match50(const Token* tok) { |
372 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
373 | 0 | return false; |
374 | 0 | tok = tok->next(); |
375 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
376 | 0 | return false; |
377 | 0 | return true; |
378 | 0 | } |
379 | | // pattern: ) |
380 | 0 | static inline bool match51(const Token* tok) { |
381 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
382 | 0 | return false; |
383 | 0 | return true; |
384 | 0 | } |
385 | | // pattern: mutable|constexpr|consteval|noexcept|. |
386 | 0 | static inline bool match52(const Token* tok) { |
387 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("mutable")) || (tok->str() == MatchCompiler::makeConstString("constexpr")) || (tok->str() == MatchCompiler::makeConstString("consteval")) || (tok->str() == MatchCompiler::makeConstString("noexcept")) || (tok->str() == MatchCompiler::makeConstString(".")))) |
388 | 0 | return false; |
389 | 0 | return true; |
390 | 0 | } |
391 | | // pattern: noexcept ( |
392 | 0 | static inline bool match53(const Token* tok) { |
393 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("noexcept"))) |
394 | 0 | return false; |
395 | 0 | tok = tok->next(); |
396 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
397 | 0 | return false; |
398 | 0 | return true; |
399 | 0 | } |
400 | | /* |
401 | | * Cppcheck - A tool for static C/C++ code analysis |
402 | | * Copyright (C) 2007-2024 Cppcheck team. |
403 | | * |
404 | | * This program is free software: you can redistribute it and/or modify |
405 | | * it under the terms of the GNU General Public License as published by |
406 | | * the Free Software Foundation, either version 3 of the License, or |
407 | | * (at your option) any later version. |
408 | | * |
409 | | * This program is distributed in the hope that it will be useful, |
410 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
411 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
412 | | * GNU General Public License for more details. |
413 | | * |
414 | | * You should have received a copy of the GNU General Public License |
415 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
416 | | */ |
417 | | |
418 | | #include "token.h" |
419 | | |
420 | | #include "astutils.h" |
421 | | #include "errortypes.h" |
422 | | #include "library.h" |
423 | | #include "settings.h" |
424 | | #include "simplecpp.h" |
425 | | #include "symboldatabase.h" |
426 | | #include "tokenlist.h" |
427 | | #include "utils.h" |
428 | | #include "tokenrange.h" |
429 | | #include "valueflow.h" |
430 | | |
431 | | #include <algorithm> |
432 | | #include <cassert> |
433 | | #include <cctype> |
434 | | #include <climits> |
435 | | #include <cstdio> |
436 | | #include <cstring> |
437 | | #include <functional> |
438 | | #include <iostream> |
439 | | #include <iterator> |
440 | | #include <map> |
441 | | #include <set> |
442 | | #include <sstream> |
443 | | #include <stack> |
444 | | #include <type_traits> |
445 | | #include <unordered_set> |
446 | | #include <utility> |
447 | | |
448 | | namespace { |
449 | | struct less { |
450 | | template<class T, class U> |
451 | 126 | bool operator()(const T &x, const U &y) const { |
452 | 126 | return x < y; |
453 | 126 | } token.cpp:bool (anonymous namespace)::less::operator()<long long, long long>(long long const&, long long const&) const Line | Count | Source | 451 | 126 | bool operator()(const T &x, const U &y) const { | 452 | 126 | return x < y; | 453 | 126 | } |
Unexecuted instantiation: token.cpp:bool (anonymous namespace)::less::operator()<long long, double>(long long const&, double const&) const Unexecuted instantiation: token.cpp:bool (anonymous namespace)::less::operator()<double, long long>(double const&, long long const&) const Unexecuted instantiation: token.cpp:bool (anonymous namespace)::less::operator()<double, double>(double const&, double const&) const |
454 | | }; |
455 | | } |
456 | | |
457 | | const std::list<ValueFlow::Value> TokenImpl::mEmptyValueList; |
458 | | |
459 | | Token::Token(TokensFrontBack &tokensFrontBack) |
460 | 64.1k | : mTokensFrontBack(tokensFrontBack) |
461 | 64.1k | , mIsC(mTokensFrontBack.list.isC()) |
462 | 64.1k | , mIsCpp(mTokensFrontBack.list.isCPP()) |
463 | 64.1k | { |
464 | 64.1k | mImpl = new TokenImpl(); |
465 | 64.1k | } |
466 | | |
467 | | Token::Token(const Token* tok) |
468 | 0 | : Token(const_cast<Token*>(tok)->mTokensFrontBack) |
469 | 0 | { |
470 | 0 | fileIndex(tok->fileIndex()); |
471 | 0 | linenr(tok->linenr()); |
472 | 0 | } |
473 | | |
474 | | Token::~Token() |
475 | 64.1k | { |
476 | 64.1k | delete mImpl; |
477 | 64.1k | } |
478 | | |
479 | | /* |
480 | | * Get a TokenRange which starts at this token and contains every token following it in order up to but not including 't' |
481 | | * e.g. for the sequence of tokens A B C D E, C.until(E) would yield the Range C D |
482 | | * note t can be nullptr to iterate all the way to the end. |
483 | | */ |
484 | | // cppcheck-suppress unusedFunction // only used in testtokenrange.cpp |
485 | | ConstTokenRange Token::until(const Token* t) const |
486 | 0 | { |
487 | 0 | return ConstTokenRange(this, t); |
488 | 0 | } |
489 | | |
490 | | static const std::unordered_set<std::string> controlFlowKeywords = { |
491 | | "goto", |
492 | | "do", |
493 | | "if", |
494 | | "else", |
495 | | "for", |
496 | | "while", |
497 | | "switch", |
498 | | "case", |
499 | | "break", |
500 | | "continue", |
501 | | "return" |
502 | | }; |
503 | | |
504 | | void Token::update_property_info() |
505 | 100k | { |
506 | 100k | setFlag(fIsControlFlowKeyword, controlFlowKeywords.find(mStr) != controlFlowKeywords.end()); |
507 | 100k | isStandardType(false); |
508 | | |
509 | 100k | if (!mStr.empty()) { |
510 | 100k | if (mStr == MatchCompiler::makeConstString("true") || mStr == MatchCompiler::makeConstString("false")) |
511 | 0 | tokType(eBoolean); |
512 | 100k | else if (isStringLiteral(mStr)) { |
513 | 2 | tokType(eString); |
514 | 2 | isLong(isPrefixStringCharLiteral(mStr, '"', "L")); |
515 | 2 | } |
516 | 100k | else if (isCharLiteral(mStr)) { |
517 | 0 | tokType(eChar); |
518 | 0 | isLong(isPrefixStringCharLiteral(mStr, '\'', "L")); |
519 | 0 | } |
520 | 100k | else if (std::isalpha((unsigned char)mStr[0]) || mStr[0] == '_' || mStr[0] == '$') { // Name |
521 | 53.2k | if (mImpl->mVarId) |
522 | 0 | tokType(eVariable); |
523 | 53.2k | else if (mTokensFrontBack.list.isKeyword(mStr) || mStr == MatchCompiler::makeConstString("asm")) // TODO: not a keyword |
524 | 15.4k | tokType(eKeyword); |
525 | 37.7k | else if (mTokType != eVariable && mTokType != eFunction && mTokType != eType && mTokType != eKeyword) |
526 | 37.7k | tokType(eName); |
527 | 53.2k | } else if (simplecpp::Token::isNumberLike(mStr)) { |
528 | 6.06k | if ((MathLib::isInt(mStr) || MathLib::isFloat(mStr)) && mStr.find('_') == std::string::npos) |
529 | 6.06k | tokType(eNumber); |
530 | 0 | else |
531 | 0 | tokType(eName); // assume it is a user defined literal |
532 | 40.9k | } else if (mStr == MatchCompiler::makeConstString("=") || mStr == MatchCompiler::makeConstString("<<=") || mStr == MatchCompiler::makeConstString(">>=") || |
533 | 40.9k | (mStr.size() == 2U && mStr[1] == '=' && std::strchr("+-*/%&^|", mStr[0]))) |
534 | 14.8k | tokType(eAssignmentOp); |
535 | 26.1k | else if (mStr.size() == 1 && mStr.find_first_of(",[]()?:") != std::string::npos) |
536 | 5.29k | tokType(eExtendedOp); |
537 | 20.8k | else if (mStr==MatchCompiler::makeConstString("<<") || mStr==MatchCompiler::makeConstString(">>") || (mStr.size()==1 && mStr.find_first_of("+-*/%") != std::string::npos)) |
538 | 1.47k | tokType(eArithmeticalOp); |
539 | 19.3k | else if (mStr.size() == 1 && mStr.find_first_of("&|^~") != std::string::npos) |
540 | 553 | tokType(eBitOp); |
541 | 18.8k | else if (mStr.size() <= 2 && |
542 | 18.8k | (mStr == MatchCompiler::makeConstString("&&") || |
543 | 18.8k | mStr == MatchCompiler::makeConstString("||") || |
544 | 18.8k | mStr == MatchCompiler::makeConstString("!"))) |
545 | 0 | tokType(eLogicalOp); |
546 | 18.8k | else if (mStr.size() <= 2 && !mLink && |
547 | 18.8k | (mStr == MatchCompiler::makeConstString("==") || |
548 | 18.8k | mStr == MatchCompiler::makeConstString("!=") || |
549 | 18.8k | mStr == MatchCompiler::makeConstString("<") || |
550 | 18.8k | mStr == MatchCompiler::makeConstString("<=") || |
551 | 18.8k | mStr == MatchCompiler::makeConstString(">") || |
552 | 18.8k | mStr == MatchCompiler::makeConstString(">="))) |
553 | 1.17k | tokType(eComparisonOp); |
554 | 17.6k | else if (mStr == MatchCompiler::makeConstString("<=>")) |
555 | 0 | tokType(eComparisonOp); |
556 | 17.6k | else if (mStr.size() == 2 && |
557 | 17.6k | (mStr == MatchCompiler::makeConstString("++") || |
558 | 807 | mStr == MatchCompiler::makeConstString("--"))) |
559 | 807 | tokType(eIncDecOp); |
560 | 16.8k | else if (mStr.size() == 1 && (mStr.find_first_of("{}") != std::string::npos || (mLink && mStr.find_first_of("<>") != std::string::npos))) |
561 | 4.84k | tokType(eBracket); |
562 | 12.0k | else if (mStr == MatchCompiler::makeConstString("...")) |
563 | 0 | tokType(eEllipsis); |
564 | 12.0k | else |
565 | 12.0k | tokType(eOther); |
566 | | |
567 | 100k | update_property_isStandardType(); |
568 | 100k | } else { |
569 | 0 | tokType(eNone); |
570 | 0 | } |
571 | 100k | } |
572 | | |
573 | | static const std::unordered_set<std::string> stdTypes = { "bool" |
574 | | , "_Bool" |
575 | | , "char" |
576 | | , "double" |
577 | | , "float" |
578 | | , "int" |
579 | | , "long" |
580 | | , "short" |
581 | | , "size_t" |
582 | | , "void" |
583 | | , "wchar_t" |
584 | | , "signed" |
585 | | , "unsigned" |
586 | | }; |
587 | | |
588 | | bool Token::isStandardType(const std::string& str) |
589 | 50.3k | { |
590 | 50.3k | return stdTypes.find(str) != stdTypes.end(); |
591 | 50.3k | } |
592 | | |
593 | | void Token::update_property_isStandardType() |
594 | 100k | { |
595 | 100k | if (mStr.size() < 3 || mStr.size() > 7) |
596 | 50.1k | return; |
597 | | |
598 | 50.1k | if (isStandardType(mStr)) { |
599 | 10.7k | isStandardType(true); |
600 | 10.7k | tokType(eType); |
601 | 10.7k | } |
602 | 50.1k | } |
603 | | |
604 | | bool Token::isUpperCaseName() const |
605 | 14.4k | { |
606 | 14.4k | if (!isName()) |
607 | 0 | return false; |
608 | 14.4k | return std::none_of(mStr.begin(), mStr.end(), [](char c) { |
609 | 14.4k | return std::islower(c); |
610 | 14.4k | }); |
611 | 14.4k | } |
612 | | |
613 | | void Token::concatStr(std::string const& b) |
614 | 0 | { |
615 | 0 | mStr.pop_back(); |
616 | 0 | mStr.append(getStringLiteral(b) + "\""); |
617 | |
|
618 | 0 | if (isCChar() && isStringLiteral(b) && b[0] != '"') { |
619 | 0 | mStr.insert(0, b.substr(0, b.find('"'))); |
620 | 0 | } |
621 | 0 | update_property_info(); |
622 | 0 | } |
623 | | |
624 | | std::string Token::strValue() const |
625 | 0 | { |
626 | 0 | assert(mTokType == eString); |
627 | 0 | std::string ret(getStringLiteral(mStr)); |
628 | 0 | std::string::size_type pos = 0U; |
629 | 0 | while ((pos = ret.find('\\', pos)) != std::string::npos) { |
630 | 0 | ret.erase(pos,1U); |
631 | 0 | if (ret[pos] >= 'a') { |
632 | 0 | if (ret[pos] == 'n') |
633 | 0 | ret[pos] = '\n'; |
634 | 0 | else if (ret[pos] == 'r') |
635 | 0 | ret[pos] = '\r'; |
636 | 0 | else if (ret[pos] == 't') |
637 | 0 | ret[pos] = '\t'; |
638 | 0 | } |
639 | 0 | if (ret[pos] == '0') |
640 | 0 | return ret.substr(0,pos); |
641 | 0 | pos++; |
642 | 0 | } |
643 | 0 | return ret; |
644 | 0 | } |
645 | | |
646 | | void Token::deleteNext(nonneg int count) |
647 | 983 | { |
648 | 1.96k | while (mNext && count > 0) { |
649 | 983 | Token *n = mNext; |
650 | | |
651 | | // #8154 we are about to be unknown -> destroy the link to us |
652 | 983 | if (n->mLink && n->mLink->mLink == n) |
653 | 0 | n->mLink->link(nullptr); |
654 | | |
655 | 983 | mNext = n->next(); |
656 | 983 | delete n; |
657 | 983 | --count; |
658 | 983 | } |
659 | | |
660 | 983 | if (mNext) |
661 | 983 | mNext->previous(this); |
662 | 0 | else |
663 | 0 | mTokensFrontBack.back = this; |
664 | 983 | } |
665 | | |
666 | | void Token::deletePrevious(nonneg int count) |
667 | 0 | { |
668 | 0 | while (mPrevious && count > 0) { |
669 | 0 | Token *p = mPrevious; |
670 | | |
671 | | // #8154 we are about to be unknown -> destroy the link to us |
672 | 0 | if (p->mLink && p->mLink->mLink == p) |
673 | 0 | p->mLink->link(nullptr); |
674 | |
|
675 | 0 | mPrevious = p->previous(); |
676 | 0 | delete p; |
677 | 0 | --count; |
678 | 0 | } |
679 | |
|
680 | 0 | if (mPrevious) |
681 | 0 | mPrevious->next(this); |
682 | 0 | else |
683 | 0 | mTokensFrontBack.front = this; |
684 | 0 | } |
685 | | |
686 | | void Token::swapWithNext() |
687 | 0 | { |
688 | 0 | if (mNext) { |
689 | 0 | std::swap(mStr, mNext->mStr); |
690 | 0 | std::swap(mTokType, mNext->mTokType); |
691 | 0 | std::swap(mFlags, mNext->mFlags); |
692 | 0 | std::swap(mImpl, mNext->mImpl); |
693 | 0 | if (mImpl->mTemplateSimplifierPointers) |
694 | | // cppcheck-suppress shadowFunction - TODO: fix this |
695 | 0 | for (auto *templateSimplifierPointer : *mImpl->mTemplateSimplifierPointers) { |
696 | 0 | templateSimplifierPointer->token(this); |
697 | 0 | } |
698 | |
|
699 | 0 | if (mNext->mImpl->mTemplateSimplifierPointers) |
700 | | // cppcheck-suppress shadowFunction - TODO: fix this |
701 | 0 | for (auto *templateSimplifierPointer : *mNext->mImpl->mTemplateSimplifierPointers) { |
702 | 0 | templateSimplifierPointer->token(mNext); |
703 | 0 | } |
704 | 0 | if (mNext->mLink) |
705 | 0 | mNext->mLink->mLink = this; |
706 | 0 | if (this->mLink) |
707 | 0 | this->mLink->mLink = mNext; |
708 | 0 | std::swap(mLink, mNext->mLink); |
709 | 0 | } |
710 | 0 | } |
711 | | |
712 | | void Token::takeData(Token *fromToken) |
713 | 188 | { |
714 | 188 | mStr = fromToken->mStr; |
715 | 188 | tokType(fromToken->mTokType); |
716 | 188 | mFlags = fromToken->mFlags; |
717 | 188 | delete mImpl; |
718 | 188 | mImpl = fromToken->mImpl; |
719 | 188 | fromToken->mImpl = nullptr; |
720 | 188 | if (mImpl->mTemplateSimplifierPointers) |
721 | | // cppcheck-suppress shadowFunction - TODO: fix this |
722 | 0 | for (auto *templateSimplifierPointer : *mImpl->mTemplateSimplifierPointers) { |
723 | 0 | templateSimplifierPointer->token(this); |
724 | 0 | } |
725 | 188 | mLink = fromToken->mLink; |
726 | 188 | if (mLink) |
727 | 42 | mLink->link(this); |
728 | 188 | } |
729 | | |
730 | | void Token::deleteThis() |
731 | 188 | { |
732 | 188 | if (mNext) { // Copy next to this and delete next |
733 | 188 | takeData(mNext); |
734 | 188 | mNext->link(nullptr); // mark as unlinked |
735 | 188 | deleteNext(); |
736 | 188 | } else if (mPrevious) { // Copy previous to this and delete previous |
737 | 0 | takeData(mPrevious); |
738 | 0 | mPrevious->link(nullptr); |
739 | 0 | deletePrevious(); |
740 | 0 | } else { |
741 | | // We are the last token in the list, we can't delete |
742 | | // ourselves, so just make us empty |
743 | 0 | str(";"); |
744 | 0 | } |
745 | 188 | } |
746 | | |
747 | | void Token::replace(Token *replaceThis, Token *start, Token *end) |
748 | 0 | { |
749 | | // Fix the whole in the old location of start and end |
750 | 0 | if (start->previous()) |
751 | 0 | start->previous()->next(end->next()); |
752 | |
|
753 | 0 | if (end->next()) |
754 | 0 | end->next()->previous(start->previous()); |
755 | | |
756 | | // Move start and end to their new location |
757 | 0 | if (replaceThis->previous()) |
758 | 0 | replaceThis->previous()->next(start); |
759 | |
|
760 | 0 | if (replaceThis->next()) |
761 | 0 | replaceThis->next()->previous(end); |
762 | |
|
763 | 0 | start->previous(replaceThis->previous()); |
764 | 0 | end->next(replaceThis->next()); |
765 | |
|
766 | 0 | if (end->mTokensFrontBack.back == end) { |
767 | 0 | while (end->next()) |
768 | 0 | end = end->next(); |
769 | 0 | end->mTokensFrontBack.back = end; |
770 | 0 | } |
771 | | |
772 | | // Update mProgressValue, fileIndex and linenr |
773 | 0 | for (Token *tok = start; tok != end->next(); tok = tok->next()) |
774 | 0 | tok->mImpl->mProgressValue = replaceThis->mImpl->mProgressValue; |
775 | | |
776 | | // Delete old token, which is replaced |
777 | 0 | delete replaceThis; |
778 | 0 | } |
779 | | |
780 | | static |
781 | | #if defined(__GNUC__) |
782 | | // GCC does not inline this by itself |
783 | | // need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here |
784 | | inline __attribute__((always_inline)) |
785 | | #endif |
786 | | int multiComparePercent(const Token *tok, const char*& haystack, nonneg int varid) |
787 | 0 | { |
788 | 0 | ++haystack; |
789 | | // Compare only the first character of the string for optimization reasons |
790 | 0 | switch (haystack[0]) { |
791 | 0 | case 'v': |
792 | 0 | if (haystack[3] == '%') { // %var% |
793 | 0 | haystack += 4; |
794 | 0 | if (tok->varId() != 0) |
795 | 0 | return 1; |
796 | 0 | } else { // %varid% |
797 | 0 | if (varid == 0) { |
798 | 0 | throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers"); |
799 | 0 | } |
800 | | |
801 | 0 | haystack += 6; |
802 | |
|
803 | 0 | if (tok->varId() == varid) |
804 | 0 | return 1; |
805 | 0 | } |
806 | 0 | break; |
807 | 0 | case 't': |
808 | | // Type (%type%) |
809 | 0 | { |
810 | 0 | haystack += 5; |
811 | 0 | if (tok->isName() && tok->varId() == 0) |
812 | 0 | return 1; |
813 | 0 | } |
814 | 0 | break; |
815 | 0 | case 'a': |
816 | | // Accept any token (%any%) or assign (%assign%) |
817 | 0 | { |
818 | 0 | if (haystack[3] == '%') { // %any% |
819 | 0 | haystack += 4; |
820 | 0 | return 1; |
821 | 0 | } |
822 | | // %assign% |
823 | 0 | haystack += 7; |
824 | 0 | if (tok->isAssignmentOp()) |
825 | 0 | return 1; |
826 | 0 | } |
827 | 0 | break; |
828 | 0 | case 'n': |
829 | | // Number (%num%) or name (%name%) |
830 | 0 | { |
831 | 0 | if (haystack[4] == '%') { // %name% |
832 | 0 | haystack += 5; |
833 | 0 | if (tok->isName()) |
834 | 0 | return 1; |
835 | 0 | } else { |
836 | 0 | haystack += 4; |
837 | 0 | if (tok->isNumber()) |
838 | 0 | return 1; |
839 | 0 | } |
840 | 0 | } |
841 | 0 | break; |
842 | 0 | case 'c': { |
843 | 0 | haystack += 1; |
844 | | // Character (%char%) |
845 | 0 | if (haystack[0] == 'h') { |
846 | 0 | haystack += 4; |
847 | 0 | if (tok->tokType() == Token::eChar) |
848 | 0 | return 1; |
849 | 0 | } |
850 | | // Const operator (%cop%) |
851 | 0 | else if (haystack[1] == 'p') { |
852 | 0 | haystack += 3; |
853 | 0 | if (tok->isConstOp()) |
854 | 0 | return 1; |
855 | 0 | } |
856 | | // Comparison operator (%comp%) |
857 | 0 | else { |
858 | 0 | haystack += 4; |
859 | 0 | if (tok->isComparisonOp()) |
860 | 0 | return 1; |
861 | 0 | } |
862 | 0 | } |
863 | 0 | break; |
864 | 0 | case 's': |
865 | | // String (%str%) |
866 | 0 | { |
867 | 0 | haystack += 4; |
868 | 0 | if (tok->tokType() == Token::eString) |
869 | 0 | return 1; |
870 | 0 | } |
871 | 0 | break; |
872 | 0 | case 'b': |
873 | | // Bool (%bool%) |
874 | 0 | { |
875 | 0 | haystack += 5; |
876 | 0 | if (tok->isBoolean()) |
877 | 0 | return 1; |
878 | 0 | } |
879 | 0 | break; |
880 | 0 | case 'o': { |
881 | 0 | ++haystack; |
882 | 0 | if (haystack[1] == '%') { |
883 | | // Op (%op%) |
884 | 0 | if (haystack[0] == 'p') { |
885 | 0 | haystack += 2; |
886 | 0 | if (tok->isOp()) |
887 | 0 | return 1; |
888 | 0 | } |
889 | | // Or (%or%) |
890 | 0 | else { |
891 | 0 | haystack += 2; |
892 | 0 | if (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|")) |
893 | 0 | return 1; |
894 | 0 | } |
895 | 0 | } |
896 | | |
897 | | // Oror (%oror%) |
898 | 0 | else { |
899 | 0 | haystack += 4; |
900 | 0 | if (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) |
901 | 0 | return 1; |
902 | 0 | } |
903 | 0 | } |
904 | 0 | break; |
905 | 0 | default: |
906 | | //unknown %cmd%, abort |
907 | 0 | throw InternalError(tok, "Unexpected command"); |
908 | 0 | } |
909 | | |
910 | 0 | if (*haystack == '|') |
911 | 0 | haystack += 1; |
912 | 0 | else |
913 | 0 | return -1; |
914 | | |
915 | 0 | return 0xFFFF; |
916 | 0 | } |
917 | | |
918 | | static |
919 | | #if defined(__GNUC__) |
920 | | // need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here |
921 | | inline __attribute__((always_inline)) |
922 | | #endif |
923 | | int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid) |
924 | 0 | { |
925 | 0 | const char *needle = tok->str().c_str(); |
926 | 0 | const char *needlePointer = needle; |
927 | 0 | for (;;) { |
928 | 0 | if (needlePointer == needle && haystack[0] == '%' && haystack[1] != '|' && haystack[1] != '\0' && haystack[1] != ' ') { |
929 | 0 | const int ret = multiComparePercent(tok, haystack, varid); |
930 | 0 | if (ret < 2) |
931 | 0 | return ret; |
932 | 0 | } else if (*haystack == '|') { |
933 | 0 | if (*needlePointer == 0) { |
934 | | // If needle is at the end, we have a match. |
935 | 0 | return 1; |
936 | 0 | } |
937 | | |
938 | 0 | needlePointer = needle; |
939 | 0 | ++haystack; |
940 | 0 | } else if (*needlePointer == *haystack) { |
941 | 0 | if (*needlePointer == '\0') |
942 | 0 | return 1; |
943 | 0 | ++needlePointer; |
944 | 0 | ++haystack; |
945 | 0 | } else if (*haystack == ' ' || *haystack == '\0') { |
946 | 0 | if (needlePointer == needle) |
947 | 0 | return 0; |
948 | 0 | break; |
949 | 0 | } |
950 | | // If haystack and needle don't share the same character, |
951 | | // find next '|' character. |
952 | 0 | else { |
953 | 0 | needlePointer = needle; |
954 | |
|
955 | 0 | do { |
956 | 0 | ++haystack; |
957 | |
|
958 | 0 | if (*haystack == ' ' || *haystack == '\0') { |
959 | 0 | return -1; |
960 | 0 | } |
961 | 0 | if (*haystack == '|') { |
962 | 0 | break; |
963 | 0 | } |
964 | 0 | } while (true); |
965 | | |
966 | 0 | ++haystack; |
967 | 0 | } |
968 | 0 | } |
969 | | |
970 | 0 | if (*needlePointer == '\0') |
971 | 0 | return 1; |
972 | | |
973 | 0 | return -1; |
974 | 0 | } |
975 | | |
976 | | // cppcheck-suppress unusedFunction - used in tests only |
977 | | int Token::multiCompare(const Token *tok, const char *haystack, nonneg int varid) |
978 | 0 | { |
979 | 0 | return multiCompareImpl(tok, haystack, varid); |
980 | 0 | } |
981 | | |
982 | | bool Token::simpleMatch(const Token *tok, const char pattern[], size_t pattern_len) |
983 | 4.20k | { |
984 | 4.20k | if (!tok) |
985 | 0 | return false; // shortcut |
986 | 4.20k | const char *current = pattern; |
987 | 4.20k | const char *end = pattern + pattern_len; |
988 | | // cppcheck-suppress shadowFunction - TODO: fix this |
989 | 4.20k | const char *next = static_cast<const char*>(std::memchr(pattern, ' ', pattern_len)); |
990 | 4.20k | if (!next) |
991 | 4.20k | next = end; |
992 | | |
993 | 5.85k | while (*current) { |
994 | 4.20k | const std::size_t length = next - current; |
995 | | |
996 | 4.20k | if (!tok || length != tok->mStr.length() || std::strncmp(current, tok->mStr.c_str(), length) != 0) |
997 | 2.56k | return false; |
998 | | |
999 | 1.64k | current = next; |
1000 | 1.64k | if (*next) { |
1001 | 0 | next = std::strchr(++current, ' '); |
1002 | 0 | if (!next) |
1003 | 0 | next = end; |
1004 | 0 | } |
1005 | 1.64k | tok = tok->next(); |
1006 | 1.64k | } |
1007 | | |
1008 | 1.64k | return true; |
1009 | 4.20k | } |
1010 | | |
1011 | | bool Token::firstWordEquals(const char *str, const char *word) |
1012 | 0 | { |
1013 | 0 | for (;;) { |
1014 | 0 | if (*str != *word) |
1015 | 0 | return (*str == ' ' && *word == 0); |
1016 | 0 | if (*str == 0) |
1017 | 0 | break; |
1018 | | |
1019 | 0 | ++str; |
1020 | 0 | ++word; |
1021 | 0 | } |
1022 | | |
1023 | 0 | return true; |
1024 | 0 | } |
1025 | | |
1026 | | const char *Token::chrInFirstWord(const char *str, char c) |
1027 | 0 | { |
1028 | 0 | for (;;) { |
1029 | 0 | if (*str == ' ' || *str == 0) |
1030 | 0 | return nullptr; |
1031 | | |
1032 | 0 | if (*str == c) |
1033 | 0 | return str; |
1034 | | |
1035 | 0 | ++str; |
1036 | 0 | } |
1037 | 0 | } |
1038 | | |
1039 | | bool Token::Match(const Token *tok, const char pattern[], nonneg int varid) |
1040 | 0 | { |
1041 | 0 | if (!(*pattern)) |
1042 | 0 | return true; |
1043 | | |
1044 | 0 | const char *p = pattern; |
1045 | 0 | while (true) { |
1046 | | // Skip spaces in pattern.. |
1047 | 0 | while (*p == ' ') |
1048 | 0 | ++p; |
1049 | | |
1050 | | // No token => Success! |
1051 | 0 | if (*p == '\0') |
1052 | 0 | break; |
1053 | | |
1054 | 0 | if (!tok) { |
1055 | | // If we have no tokens, pattern "!!else" should return true |
1056 | 0 | if (p[0] == '!' && p[1] == '!' && p[2] != '\0') { |
1057 | 0 | while (*p && *p != ' ') |
1058 | 0 | ++p; |
1059 | 0 | continue; |
1060 | 0 | } |
1061 | | |
1062 | 0 | return false; |
1063 | 0 | } |
1064 | | |
1065 | | // [.. => search for a one-character token.. |
1066 | 0 | if (p[0] == '[' && chrInFirstWord(p, ']')) { |
1067 | 0 | if (tok->str().length() != 1) |
1068 | 0 | return false; |
1069 | | |
1070 | 0 | const char *temp = p+1; |
1071 | 0 | bool chrFound = false; |
1072 | 0 | int count = 0; |
1073 | 0 | while (*temp && *temp != ' ') { |
1074 | 0 | if (*temp == ']') { |
1075 | 0 | ++count; |
1076 | 0 | } |
1077 | | |
1078 | 0 | else if (*temp == tok->str()[0]) { |
1079 | 0 | chrFound = true; |
1080 | 0 | break; |
1081 | 0 | } |
1082 | | |
1083 | 0 | ++temp; |
1084 | 0 | } |
1085 | |
|
1086 | 0 | if (count > 1 && tok->str()[0] == ']') |
1087 | 0 | chrFound = true; |
1088 | |
|
1089 | 0 | if (!chrFound) |
1090 | 0 | return false; |
1091 | | |
1092 | 0 | p = temp; |
1093 | 0 | } |
1094 | | |
1095 | | // Parse "not" options. Token can be anything except the given one |
1096 | 0 | else if (p[0] == '!' && p[1] == '!' && p[2] != '\0') { |
1097 | 0 | p += 2; |
1098 | 0 | if (firstWordEquals(p, tok->str().c_str())) |
1099 | 0 | return false; |
1100 | 0 | } |
1101 | | |
1102 | | // Parse multi options, such as void|int|char (accept token which is one of these 3) |
1103 | 0 | else { |
1104 | 0 | const int res = multiCompareImpl(tok, p, varid); |
1105 | 0 | if (res == 0) { |
1106 | | // Empty alternative matches, use the same token on next round |
1107 | 0 | while (*p && *p != ' ') |
1108 | 0 | ++p; |
1109 | 0 | continue; |
1110 | 0 | } |
1111 | 0 | if (res == -1) { |
1112 | | // No match |
1113 | 0 | return false; |
1114 | 0 | } |
1115 | 0 | } |
1116 | | |
1117 | | // using strchr() for the other instances leads to a performance decrease |
1118 | 0 | if (!(p = strchr(p, ' '))) |
1119 | 0 | break; |
1120 | | |
1121 | 0 | tok = tok->next(); |
1122 | 0 | } |
1123 | | |
1124 | | // The end of the pattern has been reached and nothing wrong has been found |
1125 | 0 | return true; |
1126 | 0 | } |
1127 | | |
1128 | | nonneg int Token::getStrLength(const Token *tok) |
1129 | 0 | { |
1130 | 0 | assert(tok != nullptr); |
1131 | 0 | assert(tok->mTokType == eString); |
1132 | | |
1133 | 0 | const std::string s(replaceEscapeSequences(getStringLiteral(tok->str()))); |
1134 | |
|
1135 | 0 | const auto pos = s.find('\0'); |
1136 | 0 | return pos < s.size() ? pos : s.size(); |
1137 | 0 | } |
1138 | | |
1139 | | nonneg int Token::getStrArraySize(const Token *tok) |
1140 | 0 | { |
1141 | 0 | assert(tok != nullptr); |
1142 | 0 | assert(tok->tokType() == eString); |
1143 | | // cppcheck-suppress shadowFunction - TODO: fix this |
1144 | 0 | const std::string str(getStringLiteral(tok->str())); |
1145 | 0 | int sizeofstring = 1; |
1146 | 0 | for (int i = 0; i < (int)str.size(); i++) { |
1147 | 0 | if (str[i] == '\\') |
1148 | 0 | ++i; |
1149 | 0 | ++sizeofstring; |
1150 | 0 | } |
1151 | 0 | return sizeofstring; |
1152 | 0 | } |
1153 | | |
1154 | | nonneg int Token::getStrSize(const Token *tok, const Settings &settings) |
1155 | 0 | { |
1156 | 0 | assert(tok != nullptr && tok->tokType() == eString); |
1157 | 0 | nonneg int sizeofType = 1; |
1158 | 0 | if (tok->valueType()) { |
1159 | 0 | ValueType vt(*tok->valueType()); |
1160 | 0 | vt.pointer = 0; |
1161 | 0 | sizeofType = ValueFlow::getSizeOf(vt, settings); |
1162 | 0 | } |
1163 | 0 | return getStrArraySize(tok) * sizeofType; |
1164 | 0 | } |
1165 | | |
1166 | | void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation) |
1167 | 0 | { |
1168 | | /**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */ |
1169 | | |
1170 | | // Fix the gap, which tokens to be moved will leave |
1171 | 0 | srcStart->previous()->next(srcEnd->next()); |
1172 | 0 | srcEnd->next()->previous(srcStart->previous()); |
1173 | | |
1174 | | // Fix the tokens to be moved |
1175 | 0 | srcEnd->next(newLocation->next()); |
1176 | 0 | srcStart->previous(newLocation); |
1177 | | |
1178 | | // Fix the tokens at newLocation |
1179 | 0 | newLocation->next()->previous(srcEnd); |
1180 | 0 | newLocation->next(srcStart); |
1181 | | |
1182 | | // Update _progressValue |
1183 | 0 | for (Token *tok = srcStart; tok != srcEnd->next(); tok = tok->next()) |
1184 | 0 | tok->mImpl->mProgressValue = newLocation->mImpl->mProgressValue; |
1185 | 0 | } |
1186 | | |
1187 | | template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )> |
1188 | | static T* nextArgumentImpl(T *thisTok) |
1189 | 721 | { |
1190 | 4.07k | for (T* tok = thisTok; tok; tok = tok->next()) { |
1191 | 4.07k | if (tok->str() == MatchCompiler::makeConstString(",")) |
1192 | 0 | return tok->next(); |
1193 | 4.07k | if (tok->link() && match1(tok)) |
1194 | 166 | tok = tok->link(); |
1195 | 3.91k | else if (match2(tok)) |
1196 | 721 | return nullptr; |
1197 | 4.07k | } |
1198 | 0 | return nullptr; |
1199 | 721 | } token.cpp:Token const* nextArgumentImpl<Token const, void>(Token const*) Line | Count | Source | 1189 | 721 | { | 1190 | 4.07k | for (T* tok = thisTok; tok; tok = tok->next()) { | 1191 | 4.07k | if (tok->str() == MatchCompiler::makeConstString(",")) | 1192 | 0 | return tok->next(); | 1193 | 4.07k | if (tok->link() && match1(tok)) | 1194 | 166 | tok = tok->link(); | 1195 | 3.91k | else if (match2(tok)) | 1196 | 721 | return nullptr; | 1197 | 4.07k | } | 1198 | 0 | return nullptr; | 1199 | 721 | } |
Unexecuted instantiation: token.cpp:Token* nextArgumentImpl<Token, void>(Token*) |
1200 | | |
1201 | | const Token* Token::nextArgument() const |
1202 | 721 | { |
1203 | 721 | return nextArgumentImpl(this); |
1204 | 721 | } |
1205 | | |
1206 | | Token *Token::nextArgument() |
1207 | 0 | { |
1208 | 0 | return nextArgumentImpl(this); |
1209 | 0 | } |
1210 | | |
1211 | | const Token* Token::nextArgumentBeforeCreateLinks2() const |
1212 | 0 | { |
1213 | 0 | for (const Token* tok = this; tok; tok = tok->next()) { |
1214 | 0 | if (tok->str() == MatchCompiler::makeConstString(",")) |
1215 | 0 | return tok->next(); |
1216 | 0 | if (tok->link() && match3(tok)) |
1217 | 0 | tok = tok->link(); |
1218 | 0 | else if (tok->str() == MatchCompiler::makeConstString("<")) { |
1219 | 0 | const Token* temp = tok->findClosingBracket(); |
1220 | 0 | if (temp) |
1221 | 0 | tok = temp; |
1222 | 0 | } else if (match2(tok)) |
1223 | 0 | return nullptr; |
1224 | 0 | } |
1225 | 0 | return nullptr; |
1226 | 0 | } |
1227 | | |
1228 | | const Token* Token::nextTemplateArgument() const |
1229 | 0 | { |
1230 | 0 | for (const Token* tok = this; tok; tok = tok->next()) { |
1231 | 0 | if (tok->str() == MatchCompiler::makeConstString(",")) |
1232 | 0 | return tok->next(); |
1233 | 0 | if (tok->link() && match1(tok)) |
1234 | 0 | tok = tok->link(); |
1235 | 0 | else if (match4(tok)) |
1236 | 0 | return nullptr; |
1237 | 0 | } |
1238 | 0 | return nullptr; |
1239 | 0 | } |
1240 | | |
1241 | | static bool isOperator(const Token *tok) |
1242 | 0 | { |
1243 | 0 | if (tok->link()) |
1244 | 0 | tok = tok->link(); |
1245 | | // TODO handle multi token operators |
1246 | 0 | return tok->strAt(-1) == MatchCompiler::makeConstString("operator"); |
1247 | 0 | } |
1248 | | |
1249 | | const Token * Token::findClosingBracket() const |
1250 | 572 | { |
1251 | 572 | if (mStr != MatchCompiler::makeConstString("<")) |
1252 | 0 | return nullptr; |
1253 | | |
1254 | 572 | if (!mPrevious) |
1255 | 0 | return nullptr; |
1256 | | |
1257 | 572 | if (!(mPrevious->isName() || match5(mPrevious) || |
1258 | 572 | match6(mPrevious->previous()) || |
1259 | 572 | match7(mPrevious->tokAt(-2)))) |
1260 | 64 | return nullptr; |
1261 | | |
1262 | 508 | const Token *closing = nullptr; |
1263 | 508 | const bool templateParameter(strAt(-1) == MatchCompiler::makeConstString("template")); |
1264 | 508 | std::set<std::string> templateParameters; |
1265 | | |
1266 | 508 | bool isDecl = true; |
1267 | 2.94k | for (const Token *prev = previous(); prev; prev = prev->previous()) { |
1268 | 2.94k | if (prev->str() == MatchCompiler::makeConstString("=")) |
1269 | 152 | isDecl = false; |
1270 | 2.94k | if (match8(prev)) |
1271 | 0 | isDecl = true; |
1272 | 2.94k | if (match9(prev)) |
1273 | 508 | break; |
1274 | 2.94k | } |
1275 | | |
1276 | 508 | unsigned int depth = 0; |
1277 | 2.05k | for (closing = this; closing != nullptr; closing = closing->next()) { |
1278 | 2.05k | if (match10(closing)) { |
1279 | 59 | closing = closing->link(); |
1280 | 59 | if (!closing) |
1281 | 0 | return nullptr; // #6803 |
1282 | 1.99k | } else if (match11(closing)) |
1283 | 475 | return nullptr; |
1284 | | // we can make some guesses for template parameters |
1285 | 1.52k | else if (closing->str() == MatchCompiler::makeConstString("<") && closing->previous() && |
1286 | 1.52k | (closing->previous()->isName() || match5(closing->previous()) || isOperator(closing->previous())) && |
1287 | 1.52k | (templateParameter ? templateParameters.find(closing->strAt(-1)) == templateParameters.end() : true)) |
1288 | 543 | ++depth; |
1289 | 977 | else if (closing->str() == MatchCompiler::makeConstString(">")) { |
1290 | 35 | if (--depth == 0) |
1291 | 33 | return closing; |
1292 | 942 | } else if (closing->str() == MatchCompiler::makeConstString(">>") || closing->str() == MatchCompiler::makeConstString(">>=")) { |
1293 | 0 | if (!isDecl && depth == 1) |
1294 | 0 | continue; |
1295 | 0 | if (depth <= 2) |
1296 | 0 | return closing; |
1297 | 0 | depth -= 2; |
1298 | 0 | } |
1299 | | // save named template parameter |
1300 | 942 | else if (templateParameter && depth == 1 && match12(closing) && |
1301 | 942 | closing->previous()->isName() && !match13(closing->previous()) && !match14(closing->tokAt(-2))) |
1302 | 0 | templateParameters.insert(closing->strAt(-1)); |
1303 | 2.05k | } |
1304 | | |
1305 | 0 | return closing; |
1306 | 508 | } |
1307 | | |
1308 | | Token * Token::findClosingBracket() |
1309 | 268 | { |
1310 | | // return value of const function |
1311 | 268 | return const_cast<Token*>(static_cast<const Token*>(this)->findClosingBracket()); |
1312 | 268 | } |
1313 | | |
1314 | | const Token * Token::findOpeningBracket() const |
1315 | 0 | { |
1316 | 0 | if (mStr != MatchCompiler::makeConstString(">")) |
1317 | 0 | return nullptr; |
1318 | | |
1319 | 0 | const Token *opening = nullptr; |
1320 | |
|
1321 | 0 | unsigned int depth = 0; |
1322 | 0 | for (opening = this; opening != nullptr; opening = opening->previous()) { |
1323 | 0 | if (match15(opening)) { |
1324 | 0 | opening = opening->link(); |
1325 | 0 | if (!opening) |
1326 | 0 | return nullptr; |
1327 | 0 | } else if (match16(opening)) |
1328 | 0 | return nullptr; |
1329 | 0 | else if (opening->str() == MatchCompiler::makeConstString(">")) |
1330 | 0 | ++depth; |
1331 | 0 | else if (opening->str() == MatchCompiler::makeConstString("<")) { |
1332 | 0 | if (--depth == 0) |
1333 | 0 | return opening; |
1334 | 0 | } |
1335 | 0 | } |
1336 | | |
1337 | 0 | return opening; |
1338 | 0 | } |
1339 | | |
1340 | | Token * Token::findOpeningBracket() |
1341 | 0 | { |
1342 | | // return value of const function |
1343 | 0 | return const_cast<Token*>(static_cast<const Token*>(this)->findOpeningBracket()); |
1344 | 0 | } |
1345 | | |
1346 | | //--------------------------------------------------------------------------- |
1347 | | |
1348 | | template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )> |
1349 | | static T *findsimplematchImpl(T * const startTok, const char pattern[], size_t pattern_len) |
1350 | 0 | { |
1351 | 0 | for (T* tok = startTok; tok; tok = tok->next()) { |
1352 | 0 | if (Token::simpleMatch(tok, pattern, pattern_len)) |
1353 | 0 | return tok; |
1354 | 0 | } |
1355 | 0 | return nullptr; |
1356 | 0 | } Unexecuted instantiation: token.cpp:Token const* findsimplematchImpl<Token const, void>(Token const*, char const*, unsigned long) Unexecuted instantiation: token.cpp:Token* findsimplematchImpl<Token, void>(Token*, char const*, unsigned long) |
1357 | | |
1358 | | const Token *Token::findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len) |
1359 | 0 | { |
1360 | 0 | return findsimplematchImpl(startTok, pattern, pattern_len); |
1361 | 0 | } |
1362 | | |
1363 | | Token *Token::findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len) |
1364 | 0 | { |
1365 | 0 | return findsimplematchImpl(startTok, pattern, pattern_len); |
1366 | 0 | } |
1367 | | |
1368 | | template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )> |
1369 | | static T *findsimplematchImpl(T * const startTok, const char pattern[], size_t pattern_len, const Token * const end) |
1370 | 0 | { |
1371 | 0 | for (T* tok = startTok; tok && tok != end; tok = tok->next()) { |
1372 | 0 | if (Token::simpleMatch(tok, pattern, pattern_len)) |
1373 | 0 | return tok; |
1374 | 0 | } |
1375 | 0 | return nullptr; |
1376 | 0 | } Unexecuted instantiation: token.cpp:Token const* findsimplematchImpl<Token const, void>(Token const*, char const*, unsigned long, Token const*) Unexecuted instantiation: token.cpp:Token* findsimplematchImpl<Token, void>(Token*, char const*, unsigned long, Token const*) |
1377 | | |
1378 | | const Token *Token::findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end) |
1379 | 0 | { |
1380 | 0 | return findsimplematchImpl(startTok, pattern, pattern_len, end); |
1381 | 0 | } |
1382 | | |
1383 | 0 | Token *Token::findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end) { |
1384 | 0 | return findsimplematchImpl(startTok, pattern, pattern_len, end); |
1385 | 0 | } |
1386 | | |
1387 | | template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )> |
1388 | | static T *findmatchImpl(T * const startTok, const char pattern[], const nonneg int varId) |
1389 | 0 | { |
1390 | 0 | for (T* tok = startTok; tok; tok = tok->next()) { |
1391 | 0 | if (Token::Match(tok, pattern, varId)) |
1392 | 0 | return tok; |
1393 | 0 | } |
1394 | 0 | return nullptr; |
1395 | 0 | } Unexecuted instantiation: token.cpp:Token const* findmatchImpl<Token const, void>(Token const*, char const*, int) Unexecuted instantiation: token.cpp:Token* findmatchImpl<Token, void>(Token*, char const*, int) |
1396 | | |
1397 | | const Token *Token::findmatch(const Token * const startTok, const char pattern[], const nonneg int varId) |
1398 | 0 | { |
1399 | 0 | return findmatchImpl(startTok, pattern, varId); |
1400 | 0 | } |
1401 | | |
1402 | 0 | Token *Token::findmatch(Token * const startTok, const char pattern[], const nonneg int varId) { |
1403 | 0 | return findmatchImpl(startTok, pattern, varId); |
1404 | 0 | } |
1405 | | |
1406 | | template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )> |
1407 | | static T *findmatchImpl(T * const startTok, const char pattern[], const Token * const end, const nonneg int varId) |
1408 | 0 | { |
1409 | 0 | for (T* tok = startTok; tok && tok != end; tok = tok->next()) { |
1410 | 0 | if (Token::Match(tok, pattern, varId)) |
1411 | 0 | return tok; |
1412 | 0 | } |
1413 | 0 | return nullptr; |
1414 | 0 | } Unexecuted instantiation: token.cpp:Token const* findmatchImpl<Token const, void>(Token const*, char const*, Token const*, int) Unexecuted instantiation: token.cpp:Token* findmatchImpl<Token, void>(Token*, char const*, Token const*, int) |
1415 | | |
1416 | | const Token *Token::findmatch(const Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId) |
1417 | 0 | { |
1418 | 0 | return findmatchImpl(startTok, pattern, end, varId); |
1419 | 0 | } |
1420 | | |
1421 | 0 | Token *Token::findmatch(Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId) { |
1422 | 0 | return findmatchImpl(startTok, pattern, end, varId); |
1423 | 0 | } |
1424 | | |
1425 | | void Token::function(const Function *f) |
1426 | 58.2k | { |
1427 | 58.2k | mImpl->mFunction = f; |
1428 | 58.2k | if (f) { |
1429 | 3.30k | if (f->isLambda()) |
1430 | 0 | tokType(eLambda); |
1431 | 3.30k | else |
1432 | 3.30k | tokType(eFunction); |
1433 | 54.9k | } else if (mTokType == eFunction) |
1434 | 1.10k | tokType(eName); |
1435 | 58.2k | } |
1436 | | |
1437 | | Token* Token::insertToken(const std::string& tokenStr, const std::string& originalNameStr, const std::string& macroNameStr, bool prepend) |
1438 | 63.3k | { |
1439 | 63.3k | Token *newToken; |
1440 | 63.3k | if (mStr.empty()) |
1441 | 0 | newToken = this; |
1442 | 63.3k | else |
1443 | 63.3k | newToken = new Token(mTokensFrontBack); |
1444 | 63.3k | newToken->str(tokenStr); |
1445 | 63.3k | newToken->originalName(originalNameStr); |
1446 | 63.3k | newToken->setMacroName(macroNameStr); |
1447 | | |
1448 | 63.3k | if (newToken != this) { |
1449 | 63.3k | newToken->mImpl->mLineNumber = mImpl->mLineNumber; |
1450 | 63.3k | newToken->mImpl->mFileIndex = mImpl->mFileIndex; |
1451 | 63.3k | newToken->mImpl->mProgressValue = mImpl->mProgressValue; |
1452 | | |
1453 | 63.3k | if (prepend) { |
1454 | 0 | if (this->previous()) { |
1455 | 0 | newToken->previous(this->previous()); |
1456 | 0 | newToken->previous()->next(newToken); |
1457 | 0 | } else { |
1458 | 0 | mTokensFrontBack.front = newToken; |
1459 | 0 | } |
1460 | 0 | this->previous(newToken); |
1461 | 0 | newToken->next(this); |
1462 | 63.3k | } else { |
1463 | 63.3k | if (this->next()) { |
1464 | 7.92k | newToken->next(this->next()); |
1465 | 7.92k | newToken->next()->previous(newToken); |
1466 | 55.3k | } else { |
1467 | 55.3k | mTokensFrontBack.back = newToken; |
1468 | 55.3k | } |
1469 | 63.3k | this->next(newToken); |
1470 | 63.3k | newToken->previous(this); |
1471 | 63.3k | } |
1472 | | |
1473 | 63.3k | if (mImpl->mScopeInfo) { |
1474 | | // If the brace is immediately closed there is no point opening a new scope for it |
1475 | 0 | if (newToken->str() == MatchCompiler::makeConstString("{")) { |
1476 | 0 | std::string nextScopeNameAddition; |
1477 | | // This might be the opening of a member function |
1478 | 0 | Token *tok1 = newToken; |
1479 | 0 | while (match17(tok1->previous())) |
1480 | 0 | tok1 = tok1->previous(); |
1481 | 0 | if (tok1->previous() && tok1->strAt(-1) == MatchCompiler::makeConstString(")")) { |
1482 | 0 | tok1 = tok1->linkAt(-1); |
1483 | 0 | if (match18(tok1->previous())) { |
1484 | 0 | tok1 = tok1->previous(); |
1485 | 0 | while (match17(tok1->previous())) |
1486 | 0 | tok1 = tok1->previous(); |
1487 | 0 | if (tok1->strAt(-1) != MatchCompiler::makeConstString(")")) |
1488 | 0 | return newToken; |
1489 | 0 | } else if (match19(newToken->tokAt(-2))) { |
1490 | 0 | tok1 = tok1->tokAt(-2); |
1491 | 0 | if (tok1->strAt(-1) != MatchCompiler::makeConstString(")")) |
1492 | 0 | return newToken; |
1493 | 0 | } |
1494 | 0 | if (tok1->strAt(-1) == MatchCompiler::makeConstString(">")) |
1495 | 0 | tok1 = tok1->previous()->findOpeningBracket(); |
1496 | 0 | if (tok1 && match20(tok1->tokAt(-3))) { |
1497 | 0 | tok1 = tok1->tokAt(-2); |
1498 | | // cppcheck-suppress shadowFunction - TODO: fix this |
1499 | 0 | std::string scope = tok1->strAt(-1); |
1500 | 0 | while (match21(tok1->tokAt(-2))) { |
1501 | 0 | scope = tok1->strAt(-3) + " :: " + scope; |
1502 | 0 | tok1 = tok1->tokAt(-2); |
1503 | 0 | } |
1504 | 0 | nextScopeNameAddition += scope; |
1505 | 0 | } |
1506 | 0 | } |
1507 | | |
1508 | | // Or it might be a namespace/class/struct |
1509 | 0 | if (match22(newToken->previous())) { |
1510 | 0 | Token* nameTok = newToken->previous(); |
1511 | 0 | while (nameTok && !match23(nameTok)) { |
1512 | 0 | nameTok = nameTok->previous(); |
1513 | 0 | } |
1514 | 0 | if (nameTok) { |
1515 | 0 | for (nameTok = nameTok->next(); nameTok && !match24(nameTok); nameTok = nameTok->next()) { |
1516 | 0 | nextScopeNameAddition.append(nameTok->str()); |
1517 | 0 | nextScopeNameAddition.append(" "); |
1518 | 0 | } |
1519 | 0 | if (!nextScopeNameAddition.empty()) |
1520 | 0 | nextScopeNameAddition.pop_back(); |
1521 | 0 | } |
1522 | 0 | } |
1523 | | |
1524 | | // New scope is opening, record it here |
1525 | 0 | std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(mImpl->mScopeInfo->name, nullptr, mImpl->mScopeInfo->usingNamespaces); |
1526 | |
|
1527 | 0 | if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty()) newScopeInfo->name.append(" :: "); |
1528 | 0 | newScopeInfo->name.append(nextScopeNameAddition); |
1529 | 0 | nextScopeNameAddition = ""; |
1530 | |
|
1531 | 0 | newToken->scopeInfo(std::move(newScopeInfo)); |
1532 | 0 | } else if (newToken->str() == MatchCompiler::makeConstString("}")) { |
1533 | 0 | Token* matchingTok = newToken->previous(); |
1534 | 0 | int depth = 0; |
1535 | 0 | while (matchingTok && (depth != 0 || !match25(matchingTok))) { |
1536 | 0 | if (match26(matchingTok)) depth++; |
1537 | 0 | if (match25(matchingTok)) depth--; |
1538 | 0 | matchingTok = matchingTok->previous(); |
1539 | 0 | } |
1540 | 0 | if (matchingTok && matchingTok->previous()) { |
1541 | 0 | newToken->mImpl->mScopeInfo = matchingTok->previous()->scopeInfo(); |
1542 | 0 | } |
1543 | 0 | } else { |
1544 | 0 | if (prepend && newToken->previous()) { |
1545 | 0 | newToken->mImpl->mScopeInfo = newToken->previous()->scopeInfo(); |
1546 | 0 | } else { |
1547 | 0 | newToken->mImpl->mScopeInfo = mImpl->mScopeInfo; |
1548 | 0 | } |
1549 | 0 | if (newToken->str() == MatchCompiler::makeConstString(";")) { |
1550 | 0 | const Token* statementStart = newToken; |
1551 | 0 | while (statementStart->previous() && !match27(statementStart->previous())) { |
1552 | 0 | statementStart = statementStart->previous(); |
1553 | 0 | } |
1554 | 0 | if (match28(statementStart)) { |
1555 | 0 | const Token * tok1 = statementStart->tokAt(2); |
1556 | 0 | std::string nameSpace; |
1557 | 0 | while (tok1 && tok1->str() != MatchCompiler::makeConstString(";")) { |
1558 | 0 | if (!nameSpace.empty()) |
1559 | 0 | nameSpace += " "; |
1560 | 0 | nameSpace += tok1->str(); |
1561 | 0 | tok1 = tok1->next(); |
1562 | 0 | } |
1563 | 0 | mImpl->mScopeInfo->usingNamespaces.insert(nameSpace); |
1564 | 0 | } |
1565 | 0 | } |
1566 | 0 | } |
1567 | 0 | } |
1568 | 63.3k | } |
1569 | 63.3k | return newToken; |
1570 | 63.3k | } |
1571 | | |
1572 | | void Token::eraseTokens(Token *begin, const Token *end) |
1573 | 0 | { |
1574 | 0 | if (!begin || begin == end) |
1575 | 0 | return; |
1576 | | |
1577 | 0 | while (begin->next() && begin->next() != end) { |
1578 | 0 | begin->deleteNext(); |
1579 | 0 | } |
1580 | 0 | } |
1581 | | |
1582 | | void Token::createMutualLinks(Token *begin, Token *end) |
1583 | 5.04k | { |
1584 | 5.04k | assert(begin != nullptr); |
1585 | 5.04k | assert(end != nullptr); |
1586 | 5.04k | assert(begin != end); |
1587 | 5.04k | begin->link(end); |
1588 | 5.04k | end->link(begin); |
1589 | 5.04k | } |
1590 | | |
1591 | | void Token::printOut() const |
1592 | 0 | { |
1593 | 0 | printOut(std::cout, ""); |
1594 | 0 | } |
1595 | | |
1596 | | void Token::printOut(std::ostream& out, const char *title) const |
1597 | 0 | { |
1598 | 0 | if (title && title[0]) |
1599 | 0 | out << "\n### " << title << " ###\n"; |
1600 | 0 | out << stringifyList(stringifyOptions::forPrintOut(), nullptr, nullptr) << std::endl; |
1601 | 0 | } |
1602 | | |
1603 | | void Token::printOut(std::ostream& out, const char *title, const std::vector<std::string> &fileNames) const |
1604 | 0 | { |
1605 | 0 | if (title && title[0]) |
1606 | 0 | out << "\n### " << title << " ###\n"; |
1607 | 0 | out << stringifyList(stringifyOptions::forPrintOut(), &fileNames, nullptr) << std::endl; |
1608 | 0 | } |
1609 | | |
1610 | | // cppcheck-suppress unusedFunction - used for debugging |
1611 | | void Token::printLines(std::ostream& out, int lines) const |
1612 | 0 | { |
1613 | 0 | const Token *end = this; |
1614 | 0 | while (end && end->linenr() < lines + linenr()) |
1615 | 0 | end = end->next(); |
1616 | 0 | out << stringifyList(stringifyOptions::forDebugExprId(), nullptr, end) << std::endl; |
1617 | 0 | } |
1618 | | |
1619 | | std::string Token::stringify(const stringifyOptions& options) const |
1620 | 1.10k | { |
1621 | 1.10k | std::string ret; |
1622 | 1.10k | if (options.attributes) { |
1623 | 1.10k | if (isUnsigned()) |
1624 | 0 | ret += "unsigned "; |
1625 | 1.10k | else if (isSigned()) |
1626 | 0 | ret += "signed "; |
1627 | 1.10k | if (isComplex()) |
1628 | 0 | ret += "_Complex "; |
1629 | 1.10k | if (isLong()) { |
1630 | 0 | if (!(mTokType == eString || mTokType == eChar)) |
1631 | 0 | ret += "long "; |
1632 | 0 | } |
1633 | 1.10k | } |
1634 | 1.10k | if (options.macro && isExpandedMacro()) |
1635 | 0 | ret += '$'; |
1636 | 1.10k | if (isName() && mStr.find(' ') != std::string::npos) { |
1637 | 0 | for (const char i : mStr) { |
1638 | 0 | if (i != ' ') |
1639 | 0 | ret += i; |
1640 | 0 | } |
1641 | 1.10k | } else if (mStr[0] != '\"' || mStr.find('\0') == std::string::npos) |
1642 | 1.10k | ret += mStr; |
1643 | 0 | else { |
1644 | 0 | for (const char i : mStr) { |
1645 | 0 | if (i == '\0') |
1646 | 0 | ret += "\\0"; |
1647 | 0 | else |
1648 | 0 | ret += i; |
1649 | 0 | } |
1650 | 0 | } |
1651 | 1.10k | if (options.varid && mImpl->mVarId != 0) { |
1652 | 0 | ret += '@'; |
1653 | 0 | ret += (options.idtype ? "var" : ""); |
1654 | 0 | ret += std::to_string(mImpl->mVarId); |
1655 | 1.10k | } else if (options.exprid && mImpl->mExprId != 0) { |
1656 | 0 | ret += '@'; |
1657 | 0 | ret += (options.idtype ? "expr" : ""); |
1658 | 0 | if ((mImpl->mExprId & (1U << efIsUnique)) != 0) |
1659 | 0 | ret += "UNIQUE"; |
1660 | 0 | else |
1661 | 0 | ret += std::to_string(mImpl->mExprId); |
1662 | 0 | } |
1663 | | |
1664 | 1.10k | return ret; |
1665 | 1.10k | } |
1666 | | |
1667 | | std::string Token::stringify(bool varid, bool attributes, bool macro) const |
1668 | 558 | { |
1669 | 558 | stringifyOptions options; |
1670 | 558 | options.varid = varid; |
1671 | 558 | options.attributes = attributes; |
1672 | 558 | options.macro = macro; |
1673 | 558 | return stringify(options); |
1674 | 558 | } |
1675 | | |
1676 | | std::string Token::stringifyList(const stringifyOptions& options, const std::vector<std::string>* fileNames, const Token* end) const |
1677 | 149 | { |
1678 | 149 | if (this == end) |
1679 | 119 | return ""; |
1680 | | |
1681 | 30 | std::string ret; |
1682 | | |
1683 | 30 | unsigned int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1U : 0U); |
1684 | | // cppcheck-suppress shadowFunction - TODO: fix this |
1685 | 30 | unsigned int fileIndex = options.files ? ~0U : mImpl->mFileIndex; |
1686 | 30 | std::map<int, unsigned int> lineNumbers; |
1687 | 574 | for (const Token *tok = this; tok != end; tok = tok->next()) { |
1688 | 544 | assert(tok && "end precedes token"); |
1689 | 544 | if (!tok) |
1690 | 0 | return ret; |
1691 | 544 | bool fileChange = false; |
1692 | 544 | if (tok->mImpl->mFileIndex != fileIndex) { |
1693 | 0 | if (fileIndex != ~0U) { |
1694 | 0 | lineNumbers[fileIndex] = tok->mImpl->mFileIndex; |
1695 | 0 | } |
1696 | |
|
1697 | 0 | fileIndex = tok->mImpl->mFileIndex; |
1698 | 0 | if (options.files) { |
1699 | 0 | ret += "\n\n##file "; |
1700 | 0 | if (fileNames && fileNames->size() > tok->mImpl->mFileIndex) |
1701 | 0 | ret += fileNames->at(tok->mImpl->mFileIndex); |
1702 | 0 | else |
1703 | 0 | ret += std::to_string(fileIndex); |
1704 | 0 | ret += '\n'; |
1705 | 0 | } |
1706 | |
|
1707 | 0 | lineNumber = lineNumbers[fileIndex]; |
1708 | 0 | fileChange = true; |
1709 | 0 | } |
1710 | | |
1711 | 544 | if (options.linebreaks && (lineNumber != tok->linenr() || fileChange)) { |
1712 | 0 | if (lineNumber+4 < tok->linenr() && fileIndex == tok->mImpl->mFileIndex) { |
1713 | 0 | ret += '\n'; |
1714 | 0 | ret += std::to_string(lineNumber+1); |
1715 | 0 | ret += ":\n|\n"; |
1716 | 0 | ret += std::to_string(tok->linenr()-1); |
1717 | 0 | ret += ":\n"; |
1718 | 0 | ret += std::to_string(tok->linenr()); |
1719 | 0 | ret += ": "; |
1720 | 0 | } else if (this == tok && options.linenumbers) { |
1721 | 0 | ret += std::to_string(tok->linenr()); |
1722 | 0 | ret += ": "; |
1723 | 0 | } else if (lineNumber > tok->linenr()) { |
1724 | 0 | lineNumber = tok->linenr(); |
1725 | 0 | ret += '\n'; |
1726 | 0 | if (options.linenumbers) { |
1727 | 0 | ret += std::to_string(lineNumber); |
1728 | 0 | ret += ':'; |
1729 | 0 | ret += ' '; |
1730 | 0 | } |
1731 | 0 | } else { |
1732 | 0 | while (lineNumber < tok->linenr()) { |
1733 | 0 | ++lineNumber; |
1734 | 0 | ret += '\n'; |
1735 | 0 | if (options.linenumbers) { |
1736 | 0 | ret += std::to_string(lineNumber); |
1737 | 0 | ret += ':'; |
1738 | 0 | if (lineNumber == tok->linenr()) |
1739 | 0 | ret += ' '; |
1740 | 0 | } |
1741 | 0 | } |
1742 | 0 | } |
1743 | 0 | lineNumber = tok->linenr(); |
1744 | 0 | } |
1745 | | |
1746 | 544 | ret += tok->stringify(options); // print token |
1747 | 544 | if (tok->next() != end && (!options.linebreaks || (tok->next()->linenr() == tok->linenr() && tok->next()->fileIndex() == tok->fileIndex()))) |
1748 | 514 | ret += ' '; |
1749 | 544 | } |
1750 | 30 | if (options.linebreaks && (options.files || options.linenumbers)) |
1751 | 0 | ret += '\n'; |
1752 | 30 | return ret; |
1753 | 30 | } |
1754 | | std::string Token::stringifyList(bool varid, bool attributes, bool linenumbers, bool linebreaks, bool files, const std::vector<std::string>* fileNames, const Token* end) const |
1755 | 149 | { |
1756 | 149 | stringifyOptions options; |
1757 | 149 | options.varid = varid; |
1758 | 149 | options.attributes = attributes; |
1759 | 149 | options.macro = attributes; |
1760 | 149 | options.linenumbers = linenumbers; |
1761 | 149 | options.linebreaks = linebreaks; |
1762 | 149 | options.files = files; |
1763 | 149 | return stringifyList(options, fileNames, end); |
1764 | 149 | } |
1765 | | |
1766 | | std::string Token::stringifyList(const Token* end, bool attributes) const |
1767 | 149 | { |
1768 | 149 | return stringifyList(false, attributes, false, false, false, nullptr, end); |
1769 | 149 | } |
1770 | | |
1771 | | std::string Token::stringifyList(bool varid) const |
1772 | 0 | { |
1773 | 0 | return stringifyList(varid, false, true, true, true, nullptr, nullptr); |
1774 | 0 | } |
1775 | | |
1776 | | void Token::astParent(Token* tok) |
1777 | 19.3k | { |
1778 | 19.3k | const Token* tok2 = tok; |
1779 | 38.6k | while (tok2) { |
1780 | 19.3k | if (this == tok2) |
1781 | 0 | throw InternalError(this, "Internal error. AST cyclic dependency."); |
1782 | 19.3k | tok2 = tok2->astParent(); |
1783 | 19.3k | } |
1784 | | // Clear children to avoid nodes referenced twice |
1785 | 19.3k | if (this->astParent()) { |
1786 | 0 | Token* parent = this->astParent(); |
1787 | 0 | if (parent->astOperand1() == this) |
1788 | 0 | parent->mImpl->mAstOperand1 = nullptr; |
1789 | 0 | if (parent->astOperand2() == this) |
1790 | 0 | parent->mImpl->mAstOperand2 = nullptr; |
1791 | 0 | } |
1792 | 19.3k | mImpl->mAstParent = tok; |
1793 | 19.3k | } |
1794 | | |
1795 | | void Token::astOperand1(Token *tok) |
1796 | 10.7k | { |
1797 | 10.7k | if (mImpl->mAstOperand1) |
1798 | 0 | mImpl->mAstOperand1->astParent(nullptr); |
1799 | | // goto parent operator |
1800 | 10.7k | if (tok) { |
1801 | 10.7k | tok = tok->astTop(); |
1802 | 10.7k | tok->astParent(this); |
1803 | 10.7k | } |
1804 | 10.7k | mImpl->mAstOperand1 = tok; |
1805 | 10.7k | } |
1806 | | |
1807 | | void Token::astOperand2(Token *tok) |
1808 | 8.63k | { |
1809 | 8.63k | if (mImpl->mAstOperand2) |
1810 | 0 | mImpl->mAstOperand2->astParent(nullptr); |
1811 | | // goto parent operator |
1812 | 8.63k | if (tok) { |
1813 | 8.63k | tok = tok->astTop(); |
1814 | 8.63k | tok->astParent(this); |
1815 | 8.63k | } |
1816 | 8.63k | mImpl->mAstOperand2 = tok; |
1817 | 8.63k | } |
1818 | | |
1819 | | static const Token* goToLeftParenthesis(const Token* start, const Token* end) |
1820 | 15.7k | { |
1821 | | // move start to lpar in such expression: '(*it).x' |
1822 | 15.7k | int par = 0; |
1823 | 52.0k | for (const Token *tok = start; tok && tok != end; tok = tok->next()) { |
1824 | 36.2k | if (tok->str() == MatchCompiler::makeConstString("(")) |
1825 | 913 | ++par; |
1826 | 35.3k | else if (tok->str() == MatchCompiler::makeConstString(")")) { |
1827 | 1.28k | if (par == 0) |
1828 | 852 | start = tok->link(); |
1829 | 428 | else |
1830 | 428 | --par; |
1831 | 1.28k | } |
1832 | 36.2k | } |
1833 | 15.7k | return start; |
1834 | 15.7k | } |
1835 | | |
1836 | | static const Token* goToRightParenthesis(const Token* start, const Token* end) |
1837 | 15.7k | { |
1838 | | // move end to rpar in such expression: '2>(x+1)' |
1839 | 15.7k | int par = 0; |
1840 | 52.8k | for (const Token *tok = end; tok && tok != start; tok = tok->previous()) { |
1841 | 37.1k | if (tok->str() == MatchCompiler::makeConstString(")")) |
1842 | 1.28k | ++par; |
1843 | 35.8k | else if (tok->str() == MatchCompiler::makeConstString("(")) { |
1844 | 945 | if (par == 0) |
1845 | 485 | end = tok->link(); |
1846 | 460 | else |
1847 | 460 | --par; |
1848 | 945 | } |
1849 | 37.1k | } |
1850 | 15.7k | return end; |
1851 | 15.7k | } |
1852 | | |
1853 | | std::pair<const Token *, const Token *> Token::findExpressionStartEndTokens() const |
1854 | 15.7k | { |
1855 | 15.7k | const Token * const top = this; |
1856 | | |
1857 | | // find start node in AST tree |
1858 | 15.7k | const Token *start = top; |
1859 | 28.0k | while (start->astOperand1() && precedes(start->astOperand1(), start)) |
1860 | 12.2k | start = start->astOperand1(); |
1861 | | |
1862 | | // find end node in AST tree |
1863 | 15.7k | const Token *end = top; |
1864 | 28.6k | while (end->astOperand1() && (end->astOperand2() || end->isUnaryPreOp())) { |
1865 | | // lambda.. |
1866 | 12.8k | if (end->str() == MatchCompiler::makeConstString("[")) { |
1867 | 0 | const Token *lambdaEnd = findLambdaEndToken(end); |
1868 | 0 | if (lambdaEnd) { |
1869 | 0 | end = lambdaEnd; |
1870 | 0 | break; |
1871 | 0 | } |
1872 | 0 | } |
1873 | 12.8k | if (match29(end) && |
1874 | 12.8k | !(match30(end) && !end->astOperand2())) { |
1875 | 0 | end = end->link(); |
1876 | 0 | break; |
1877 | 0 | } |
1878 | 12.8k | end = end->astOperand2() ? end->astOperand2() : end->astOperand1(); |
1879 | 12.8k | } |
1880 | | |
1881 | | // skip parentheses |
1882 | 15.7k | start = goToLeftParenthesis(start, end); |
1883 | 15.7k | end = goToRightParenthesis(start, end); |
1884 | 15.7k | if (match25(end)) |
1885 | 0 | end = end->link(); |
1886 | | |
1887 | 15.7k | if (precedes(top, start)) |
1888 | 0 | throw InternalError(start, "Cannot find start of expression"); |
1889 | 15.7k | if (succeeds(top, end)) |
1890 | 1 | throw InternalError(end, "Cannot find end of expression"); |
1891 | | |
1892 | 15.7k | return std::pair<const Token *, const Token *>(start,end); |
1893 | 15.7k | } |
1894 | | |
1895 | | bool Token::isCalculation() const |
1896 | 0 | { |
1897 | 0 | if (!match31(this)) |
1898 | 0 | return false; |
1899 | | |
1900 | 0 | if (match32(this)) { |
1901 | | // dereference or address-of? |
1902 | 0 | if (!this->astOperand2()) |
1903 | 0 | return false; |
1904 | | |
1905 | 0 | if (this->astOperand2()->str() == MatchCompiler::makeConstString("[")) |
1906 | 0 | return false; |
1907 | | |
1908 | | // type specification? |
1909 | 0 | std::stack<const Token *> operands; |
1910 | 0 | operands.push(this); |
1911 | 0 | while (!operands.empty()) { |
1912 | 0 | const Token *op = operands.top(); |
1913 | 0 | operands.pop(); |
1914 | 0 | if (op->isNumber() || op->varId() > 0) |
1915 | 0 | return true; |
1916 | 0 | if (op->astOperand1()) |
1917 | 0 | operands.push(op->astOperand1()); |
1918 | 0 | if (op->astOperand2()) |
1919 | 0 | operands.push(op->astOperand2()); |
1920 | 0 | else if (match32(op)) |
1921 | 0 | return false; |
1922 | 0 | } |
1923 | | |
1924 | | // type specification => return false |
1925 | 0 | return false; |
1926 | 0 | } |
1927 | | |
1928 | 0 | return true; |
1929 | 0 | } |
1930 | | |
1931 | | bool Token::isUnaryPreOp() const |
1932 | 773 | { |
1933 | 773 | if (!astOperand1() || astOperand2()) |
1934 | 0 | return false; |
1935 | 773 | if (this->tokType() != Token::eIncDecOp) |
1936 | 270 | return true; |
1937 | 503 | const Token *tokbefore = mPrevious; |
1938 | 503 | const Token *tokafter = mNext; |
1939 | 527 | for (int distance = 1; distance < 10 && tokbefore; distance++) { |
1940 | 527 | if (tokbefore == mImpl->mAstOperand1) |
1941 | 4 | return false; |
1942 | 523 | if (tokafter == mImpl->mAstOperand1) |
1943 | 499 | return true; |
1944 | 24 | tokbefore = tokbefore->mPrevious; |
1945 | 24 | tokafter = tokafter->mPrevious; |
1946 | 24 | } |
1947 | 0 | return false; // <- guess |
1948 | 503 | } |
1949 | | |
1950 | | static std::string stringFromTokenRange(const Token* start, const Token* end) |
1951 | 10.9k | { |
1952 | 10.9k | std::string ret; |
1953 | 10.9k | if (end) |
1954 | 10.9k | end = end->next(); |
1955 | 53.2k | for (const Token *tok = start; tok && tok != end; tok = tok->next()) { |
1956 | 42.3k | if (tok->isUnsigned()) |
1957 | 0 | ret += "unsigned "; |
1958 | 42.3k | if (tok->isLong() && !tok->isLiteral()) |
1959 | 0 | ret += "long "; |
1960 | 42.3k | if (tok->tokType() == Token::eString) { |
1961 | 0 | for (const unsigned char c: tok->str()) { |
1962 | 0 | if (c == '\n') |
1963 | 0 | ret += "\\n"; |
1964 | 0 | else if (c == '\r') |
1965 | 0 | ret += "\\r"; |
1966 | 0 | else if (c == '\t') |
1967 | 0 | ret += "\\t"; |
1968 | 0 | else if (c >= ' ' && c <= 126) |
1969 | 0 | ret += c; |
1970 | 0 | else { |
1971 | 0 | char str[10]; |
1972 | 0 | sprintf(str, "\\x%02x", c); |
1973 | 0 | ret += str; |
1974 | 0 | } |
1975 | 0 | } |
1976 | 42.3k | } else if (tok->originalName().empty() || tok->isUnsigned() || tok->isLong()) { |
1977 | 42.3k | ret += tok->str(); |
1978 | 42.3k | } else |
1979 | 0 | ret += tok->originalName(); |
1980 | 42.3k | if (match33(tok)) |
1981 | 0 | ret += ' '; |
1982 | 42.3k | } |
1983 | 10.9k | return ret; |
1984 | 10.9k | } |
1985 | | |
1986 | | std::string Token::expressionString() const |
1987 | 10.9k | { |
1988 | 10.9k | const auto tokens = findExpressionStartEndTokens(); |
1989 | 10.9k | return stringFromTokenRange(tokens.first, tokens.second); |
1990 | 10.9k | } |
1991 | | |
1992 | | static void astStringXml(const Token *tok, nonneg int indent, std::ostream &out) |
1993 | 0 | { |
1994 | 0 | const std::string strindent(indent, ' '); |
1995 | |
|
1996 | 0 | out << strindent << "<token str=\"" << tok->str() << '\"'; |
1997 | 0 | if (tok->varId()) |
1998 | 0 | out << " varId=\"" << tok->varId() << '\"'; |
1999 | 0 | if (tok->variable()) |
2000 | 0 | out << " variable=\"" << tok->variable() << '\"'; |
2001 | 0 | if (tok->function()) |
2002 | 0 | out << " function=\"" << tok->function() << '\"'; |
2003 | 0 | if (!tok->values().empty()) |
2004 | 0 | out << " values=\"" << &tok->values() << '\"'; |
2005 | |
|
2006 | 0 | if (!tok->astOperand1() && !tok->astOperand2()) { |
2007 | 0 | out << "/>" << std::endl; |
2008 | 0 | } |
2009 | | |
2010 | 0 | else { |
2011 | 0 | out << '>' << std::endl; |
2012 | 0 | if (tok->astOperand1()) |
2013 | 0 | astStringXml(tok->astOperand1(), indent+2U, out); |
2014 | 0 | if (tok->astOperand2()) |
2015 | 0 | astStringXml(tok->astOperand2(), indent+2U, out); |
2016 | 0 | out << strindent << "</token>" << std::endl; |
2017 | 0 | } |
2018 | 0 | } |
2019 | | |
2020 | | void Token::printAst(bool verbose, bool xml, const std::vector<std::string> &fileNames, std::ostream &out) const |
2021 | 0 | { |
2022 | 0 | if (!xml) |
2023 | 0 | out << "\n\n##AST" << std::endl; |
2024 | |
|
2025 | 0 | std::set<const Token *> printed; |
2026 | 0 | for (const Token *tok = this; tok; tok = tok->next()) { |
2027 | 0 | if (!tok->mImpl->mAstParent && tok->mImpl->mAstOperand1) { |
2028 | 0 | if (printed.find(tok) != printed.end()) |
2029 | 0 | continue; |
2030 | 0 | printed.insert(tok); |
2031 | |
|
2032 | 0 | if (xml) { |
2033 | 0 | out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr() |
2034 | 0 | << "\" column=\"" << tok->column() << "\">" << std::endl; |
2035 | 0 | astStringXml(tok, 2U, out); |
2036 | 0 | out << "</ast>" << std::endl; |
2037 | 0 | } else if (verbose) |
2038 | 0 | out << "[" << fileNames[tok->fileIndex()] << ":" << tok->linenr() << "]" << std::endl << tok->astStringVerbose() << std::endl; |
2039 | 0 | else |
2040 | 0 | out << tok->astString(" ") << std::endl; |
2041 | 0 | if (tok->str() == MatchCompiler::makeConstString("(")) |
2042 | 0 | tok = tok->link(); |
2043 | 0 | } |
2044 | 0 | } |
2045 | 0 | } |
2046 | | |
2047 | | static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2) |
2048 | 0 | { |
2049 | 0 | for (int i = 0; i < indent1; ++i) |
2050 | 0 | str += ' '; |
2051 | 0 | for (int i = indent1; i < indent2; i += 2) |
2052 | 0 | str += "| "; |
2053 | 0 | } |
2054 | | |
2055 | | void Token::astStringVerboseRecursive(std::string& ret, const nonneg int indent1, const nonneg int indent2) const |
2056 | 0 | { |
2057 | 0 | if (isExpandedMacro()) |
2058 | 0 | ret += '$'; |
2059 | 0 | ret += mStr; |
2060 | 0 | if (mImpl->mValueType) |
2061 | 0 | ret += " \'" + mImpl->mValueType->str() + '\''; |
2062 | 0 | if (function()) { |
2063 | 0 | std::ostringstream ostr; |
2064 | 0 | ostr << std::hex << function(); |
2065 | 0 | ret += " f:" + ostr.str(); |
2066 | 0 | } |
2067 | 0 | ret += '\n'; |
2068 | |
|
2069 | 0 | if (mImpl->mAstOperand1) { |
2070 | 0 | int i1 = indent1, i2 = indent2 + 2; |
2071 | 0 | if (indent1 == indent2 && !mImpl->mAstOperand2) |
2072 | 0 | i1 += 2; |
2073 | 0 | indent(ret, indent1, indent2); |
2074 | 0 | ret += mImpl->mAstOperand2 ? "|-" : "`-"; |
2075 | 0 | mImpl->mAstOperand1->astStringVerboseRecursive(ret, i1, i2); |
2076 | 0 | } |
2077 | 0 | if (mImpl->mAstOperand2) { |
2078 | 0 | int i1 = indent1, i2 = indent2 + 2; |
2079 | 0 | if (indent1 == indent2) |
2080 | 0 | i1 += 2; |
2081 | 0 | indent(ret, indent1, indent2); |
2082 | 0 | ret += "`-"; |
2083 | 0 | mImpl->mAstOperand2->astStringVerboseRecursive(ret, i1, i2); |
2084 | 0 | } |
2085 | 0 | } |
2086 | | |
2087 | | std::string Token::astStringVerbose() const |
2088 | 0 | { |
2089 | 0 | std::string ret; |
2090 | 0 | astStringVerboseRecursive(ret); |
2091 | 0 | return ret; |
2092 | 0 | } |
2093 | | |
2094 | | // cppcheck-suppress unusedFunction // used in test |
2095 | | std::string Token::astStringZ3() const |
2096 | 0 | { |
2097 | 0 | if (!astOperand1()) |
2098 | 0 | return str(); |
2099 | 0 | if (!astOperand2()) |
2100 | 0 | return "(" + str() + " " + astOperand1()->astStringZ3() + ")"; |
2101 | 0 | return "(" + str() + " " + astOperand1()->astStringZ3() + " " + astOperand2()->astStringZ3() + ")"; |
2102 | 0 | } |
2103 | | |
2104 | | void Token::printValueFlow(bool xml, std::ostream &out) const |
2105 | 0 | { |
2106 | 0 | std::string outs; |
2107 | | |
2108 | | // cppcheck-suppress shadowFunction |
2109 | 0 | int fileIndex = -1; |
2110 | 0 | int line = 0; |
2111 | 0 | if (xml) |
2112 | 0 | outs += " <valueflow>\n"; |
2113 | 0 | else |
2114 | 0 | outs += "\n\n##Value flow\n"; |
2115 | 0 | for (const Token *tok = this; tok; tok = tok->next()) { |
2116 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2117 | 0 | const auto* const values = tok->mImpl->mValues; |
2118 | 0 | if (!values) |
2119 | 0 | continue; |
2120 | 0 | if (values->empty()) // Values might be removed by removeContradictions |
2121 | 0 | continue; |
2122 | 0 | if (xml) { |
2123 | 0 | outs += " <values id=\""; |
2124 | 0 | outs += id_string(values); |
2125 | 0 | outs += "\">"; |
2126 | 0 | outs += '\n'; |
2127 | 0 | } |
2128 | 0 | else { |
2129 | 0 | if (fileIndex != tok->fileIndex()) { |
2130 | 0 | outs += "File "; |
2131 | 0 | outs += tok->mTokensFrontBack.list.getFiles()[tok->fileIndex()]; |
2132 | 0 | outs += '\n'; |
2133 | 0 | line = 0; |
2134 | 0 | } |
2135 | 0 | if (line != tok->linenr()) { |
2136 | 0 | outs += "Line "; |
2137 | 0 | outs += std::to_string(tok->linenr()); |
2138 | 0 | outs += '\n'; |
2139 | 0 | } |
2140 | 0 | } |
2141 | 0 | fileIndex = tok->fileIndex(); |
2142 | 0 | line = tok->linenr(); |
2143 | 0 | if (!xml) { |
2144 | 0 | ValueFlow::Value::ValueKind valueKind = values->front().valueKind; |
2145 | 0 | const bool same = std::all_of(values->begin(), values->end(), [&](const ValueFlow::Value& value) { |
2146 | 0 | return value.valueKind == valueKind; |
2147 | 0 | }); |
2148 | 0 | outs += " "; |
2149 | 0 | outs += tok->str(); |
2150 | 0 | outs += " "; |
2151 | 0 | if (same) { |
2152 | 0 | switch (valueKind) { |
2153 | 0 | case ValueFlow::Value::ValueKind::Impossible: |
2154 | 0 | case ValueFlow::Value::ValueKind::Known: |
2155 | 0 | outs += "always "; |
2156 | 0 | break; |
2157 | 0 | case ValueFlow::Value::ValueKind::Inconclusive: |
2158 | 0 | outs += "inconclusive "; |
2159 | 0 | break; |
2160 | 0 | case ValueFlow::Value::ValueKind::Possible: |
2161 | 0 | outs += "possible "; |
2162 | 0 | break; |
2163 | 0 | } |
2164 | 0 | } |
2165 | 0 | if (values->size() > 1U) |
2166 | 0 | outs += '{'; |
2167 | 0 | } |
2168 | 0 | for (const ValueFlow::Value& value : *values) { |
2169 | 0 | if (xml) { |
2170 | 0 | outs += " <value "; |
2171 | 0 | switch (value.valueType) { |
2172 | 0 | case ValueFlow::Value::ValueType::INT: |
2173 | 0 | if (tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED) { |
2174 | 0 | outs += "intvalue=\""; |
2175 | 0 | outs += MathLib::toString(static_cast<MathLib::biguint>(value.intvalue)); |
2176 | 0 | outs += '\"'; |
2177 | 0 | } |
2178 | 0 | else { |
2179 | 0 | outs += "intvalue=\""; |
2180 | 0 | outs += MathLib::toString(value.intvalue); |
2181 | 0 | outs += '\"'; |
2182 | 0 | } |
2183 | 0 | break; |
2184 | 0 | case ValueFlow::Value::ValueType::TOK: |
2185 | 0 | outs += "tokvalue=\""; |
2186 | 0 | outs += id_string(value.tokvalue); |
2187 | 0 | outs += '\"'; |
2188 | 0 | break; |
2189 | 0 | case ValueFlow::Value::ValueType::FLOAT: |
2190 | 0 | outs += "floatvalue=\""; |
2191 | 0 | outs += std::to_string(value.floatValue); // TODO: should this be MathLib::toString()? |
2192 | 0 | outs += '\"'; |
2193 | 0 | break; |
2194 | 0 | case ValueFlow::Value::ValueType::MOVED: |
2195 | 0 | outs += "movedvalue=\""; |
2196 | 0 | outs += ValueFlow::Value::toString(value.moveKind); |
2197 | 0 | outs += '\"'; |
2198 | 0 | break; |
2199 | 0 | case ValueFlow::Value::ValueType::UNINIT: |
2200 | 0 | outs += "uninit=\"1\""; |
2201 | 0 | break; |
2202 | 0 | case ValueFlow::Value::ValueType::BUFFER_SIZE: |
2203 | 0 | outs += "buffer-size=\""; |
2204 | 0 | outs += MathLib::toString(value.intvalue); |
2205 | 0 | outs += "\""; |
2206 | 0 | break; |
2207 | 0 | case ValueFlow::Value::ValueType::CONTAINER_SIZE: |
2208 | 0 | outs += "container-size=\""; |
2209 | 0 | outs += MathLib::toString(value.intvalue); |
2210 | 0 | outs += '\"'; |
2211 | 0 | break; |
2212 | 0 | case ValueFlow::Value::ValueType::ITERATOR_START: |
2213 | 0 | outs += "iterator-start=\""; |
2214 | 0 | outs += MathLib::toString(value.intvalue); |
2215 | 0 | outs += '\"'; |
2216 | 0 | break; |
2217 | 0 | case ValueFlow::Value::ValueType::ITERATOR_END: |
2218 | 0 | outs += "iterator-end=\""; |
2219 | 0 | outs += MathLib::toString(value.intvalue); |
2220 | 0 | outs += '\"'; |
2221 | 0 | break; |
2222 | 0 | case ValueFlow::Value::ValueType::LIFETIME: |
2223 | 0 | outs += "lifetime=\""; |
2224 | 0 | outs += id_string(value.tokvalue); |
2225 | 0 | outs += '\"'; |
2226 | 0 | outs += " lifetime-scope=\""; |
2227 | 0 | outs += ValueFlow::Value::toString(value.lifetimeScope); |
2228 | 0 | outs += "\""; |
2229 | 0 | outs += " lifetime-kind=\""; |
2230 | 0 | outs += ValueFlow::Value::toString(value.lifetimeKind); |
2231 | 0 | outs += "\""; |
2232 | 0 | break; |
2233 | 0 | case ValueFlow::Value::ValueType::SYMBOLIC: |
2234 | 0 | outs += "symbolic=\""; |
2235 | 0 | outs += id_string(value.tokvalue); |
2236 | 0 | outs += '\"'; |
2237 | 0 | outs += " symbolic-delta=\""; |
2238 | 0 | outs += MathLib::toString(value.intvalue); |
2239 | 0 | outs += '\"'; |
2240 | 0 | break; |
2241 | 0 | } |
2242 | 0 | outs += " bound=\""; |
2243 | 0 | outs += ValueFlow::Value::toString(value.bound); |
2244 | 0 | outs += "\""; |
2245 | 0 | if (value.condition) { |
2246 | 0 | outs += " condition-line=\""; |
2247 | 0 | outs += std::to_string(value.condition->linenr()); |
2248 | 0 | outs += '\"'; |
2249 | 0 | } |
2250 | 0 | if (value.isKnown()) |
2251 | 0 | outs += " known=\"true\""; |
2252 | 0 | else if (value.isPossible()) |
2253 | 0 | outs += " possible=\"true\""; |
2254 | 0 | else if (value.isImpossible()) |
2255 | 0 | outs += " impossible=\"true\""; |
2256 | 0 | else if (value.isInconclusive()) |
2257 | 0 | outs += " inconclusive=\"true\""; |
2258 | |
|
2259 | 0 | outs += " path=\""; |
2260 | 0 | outs += MathLib::toString(value.path); |
2261 | 0 | outs += "\""; |
2262 | |
|
2263 | 0 | outs += "/>\n"; |
2264 | 0 | } |
2265 | | |
2266 | 0 | else { |
2267 | 0 | if (&value != &values->front()) |
2268 | 0 | outs += ","; |
2269 | 0 | outs += value.toString(); |
2270 | 0 | } |
2271 | 0 | } |
2272 | 0 | if (xml) |
2273 | 0 | outs += " </values>\n"; |
2274 | 0 | else if (values->size() > 1U) |
2275 | 0 | outs += "}\n"; |
2276 | 0 | else |
2277 | 0 | outs += '\n'; |
2278 | 0 | } |
2279 | 0 | if (xml) |
2280 | 0 | outs += " </valueflow>\n"; |
2281 | |
|
2282 | 0 | out << outs; |
2283 | 0 | } |
2284 | | |
2285 | | const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings &settings) const |
2286 | 353 | { |
2287 | 353 | if (!mImpl->mValues) |
2288 | 292 | return nullptr; |
2289 | 63 | return ValueFlow::findValue(*mImpl->mValues, settings, [&](const ValueFlow::Value& v) { |
2290 | 63 | return !v.isImpossible() && v.isIntValue() && v.intvalue <= val; |
2291 | 63 | }); |
2292 | 353 | } |
2293 | | |
2294 | | const ValueFlow::Value * Token::getValueGE(const MathLib::bigint val, const Settings &settings) const |
2295 | 353 | { |
2296 | 353 | if (!mImpl->mValues) |
2297 | 292 | return nullptr; |
2298 | 63 | return ValueFlow::findValue(*mImpl->mValues, settings, [&](const ValueFlow::Value& v) { |
2299 | 63 | return !v.isImpossible() && v.isIntValue() && v.intvalue >= val; |
2300 | 63 | }); |
2301 | 353 | } |
2302 | | |
2303 | | const ValueFlow::Value * Token::getValueNE(MathLib::bigint val) const |
2304 | 0 | { |
2305 | 0 | if (!mImpl->mValues) |
2306 | 0 | return nullptr; |
2307 | 0 | const auto it = std::find_if(mImpl->mValues->cbegin(), mImpl->mValues->cend(), [=](const ValueFlow::Value& value) { |
2308 | 0 | return value.isIntValue() && !value.isImpossible() && value.intvalue != val; |
2309 | 0 | }); |
2310 | 0 | return it == mImpl->mValues->end() ? nullptr : &*it; |
2311 | 0 | } |
2312 | | |
2313 | | const ValueFlow::Value * Token::getInvalidValue(const Token *ftok, nonneg int argnr, const Settings &settings) const |
2314 | 647 | { |
2315 | 647 | if (!mImpl->mValues) |
2316 | 62 | return nullptr; |
2317 | 585 | const ValueFlow::Value *ret = nullptr; |
2318 | 1.61k | for (auto it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) { |
2319 | 1.03k | if (it->isImpossible()) |
2320 | 885 | continue; |
2321 | 146 | if ((it->isIntValue() && !settings.library.isIntArgValid(ftok, argnr, it->intvalue)) || |
2322 | 146 | (it->isFloatValue() && !settings.library.isFloatArgValid(ftok, argnr, it->floatValue))) { |
2323 | 0 | if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive())) |
2324 | 0 | ret = &(*it); |
2325 | 0 | if (!ret->isInconclusive() && !ret->condition) |
2326 | 0 | break; |
2327 | 0 | } |
2328 | 146 | } |
2329 | 585 | if (ret) { |
2330 | 0 | if (ret->isInconclusive() && !settings.certainty.isEnabled(Certainty::inconclusive)) |
2331 | 0 | return nullptr; |
2332 | 0 | if (ret->condition && !settings.severity.isEnabled(Severity::warning)) |
2333 | 0 | return nullptr; |
2334 | 0 | } |
2335 | 585 | return ret; |
2336 | 585 | } |
2337 | | |
2338 | | const Token *Token::getValueTokenMinStrSize(const Settings &settings, MathLib::bigint* path) const |
2339 | 0 | { |
2340 | 0 | if (!mImpl->mValues) |
2341 | 0 | return nullptr; |
2342 | 0 | const Token *ret = nullptr; |
2343 | 0 | int minsize = INT_MAX; |
2344 | 0 | for (auto it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) { |
2345 | 0 | if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) { |
2346 | 0 | const int size = getStrSize(it->tokvalue, settings); |
2347 | 0 | if (!ret || size < minsize) { |
2348 | 0 | minsize = size; |
2349 | 0 | ret = it->tokvalue; |
2350 | 0 | if (path) |
2351 | 0 | *path = it->path; |
2352 | 0 | } |
2353 | 0 | } |
2354 | 0 | } |
2355 | 0 | return ret; |
2356 | 0 | } |
2357 | | |
2358 | | const Token *Token::getValueTokenMaxStrLength() const |
2359 | 0 | { |
2360 | 0 | if (!mImpl->mValues) |
2361 | 0 | return nullptr; |
2362 | 0 | const Token *ret = nullptr; |
2363 | 0 | int maxlength = 0; |
2364 | 0 | for (auto it = mImpl->mValues->cbegin(); it != mImpl->mValues->end(); ++it) { |
2365 | 0 | if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) { |
2366 | 0 | const int length = getStrLength(it->tokvalue); |
2367 | 0 | if (!ret || length > maxlength) { |
2368 | 0 | maxlength = length; |
2369 | 0 | ret = it->tokvalue; |
2370 | 0 | } |
2371 | 0 | } |
2372 | 0 | } |
2373 | 0 | return ret; |
2374 | 0 | } |
2375 | | |
2376 | | static bool isAdjacent(const ValueFlow::Value& x, const ValueFlow::Value& y) |
2377 | 1.62k | { |
2378 | 1.62k | if (x.bound != ValueFlow::Value::Bound::Point && x.bound == y.bound) |
2379 | 0 | return true; |
2380 | 1.62k | if (x.valueType == ValueFlow::Value::ValueType::FLOAT) |
2381 | 0 | return false; |
2382 | 1.62k | return std::abs(x.intvalue - y.intvalue) == 1; |
2383 | 1.62k | } |
2384 | | |
2385 | | static bool removePointValue(std::list<ValueFlow::Value>& values, std::list<ValueFlow::Value>::iterator& x) |
2386 | 0 | { |
2387 | 0 | const bool isPoint = x->bound == ValueFlow::Value::Bound::Point; |
2388 | 0 | if (!isPoint) |
2389 | 0 | x->decreaseRange(); |
2390 | 0 | else |
2391 | 0 | x = values.erase(x); |
2392 | 0 | return isPoint; |
2393 | 0 | } |
2394 | | |
2395 | | static bool removeContradiction(std::list<ValueFlow::Value>& values) |
2396 | 11.1k | { |
2397 | 11.1k | bool result = false; |
2398 | 23.2k | for (auto itx = values.begin(); itx != values.end(); ++itx) { |
2399 | 12.0k | if (itx->isNonValue()) |
2400 | 10 | continue; |
2401 | | |
2402 | 12.0k | auto ity = itx; |
2403 | 12.0k | ++ity; |
2404 | 12.9k | for (; ity != values.end(); ++ity) { |
2405 | 918 | if (ity->isNonValue()) |
2406 | 0 | continue; |
2407 | 918 | if (*itx == *ity) |
2408 | 0 | continue; |
2409 | 918 | if (itx->valueType != ity->valueType) |
2410 | 10 | continue; |
2411 | 908 | if (itx->isImpossible() == ity->isImpossible()) |
2412 | 845 | continue; |
2413 | 63 | if (itx->isSymbolicValue() && !ValueFlow::Value::sameToken(itx->tokvalue, ity->tokvalue)) |
2414 | 0 | continue; |
2415 | 63 | if (!itx->equalValue(*ity)) { |
2416 | 126 | auto compare = [](const std::list<ValueFlow::Value>::const_iterator& x, const std::list<ValueFlow::Value>::const_iterator& y) { |
2417 | 126 | return x->compareValue(*y, less{}); |
2418 | 126 | }; |
2419 | 63 | auto itMax = std::max(itx, ity, compare); |
2420 | 63 | auto itMin = std::min(itx, ity, compare); |
2421 | | // TODO: Adjust non-points instead of removing them |
2422 | 63 | if (itMax->isImpossible() && itMax->bound == ValueFlow::Value::Bound::Upper) { |
2423 | 0 | values.erase(itMin); |
2424 | 0 | return true; |
2425 | 0 | } |
2426 | 63 | if (itMin->isImpossible() && itMin->bound == ValueFlow::Value::Bound::Lower) { |
2427 | 0 | values.erase(itMax); |
2428 | 0 | return true; |
2429 | 0 | } |
2430 | 63 | continue; |
2431 | 63 | } |
2432 | 0 | const bool removex = !itx->isImpossible() || ity->isKnown(); |
2433 | 0 | const bool removey = !ity->isImpossible() || itx->isKnown(); |
2434 | 0 | if (itx->bound == ity->bound) { |
2435 | 0 | if (removex) |
2436 | 0 | values.erase(itx); |
2437 | 0 | if (removey) |
2438 | 0 | values.erase(ity); |
2439 | | // itx and ity are invalidated |
2440 | 0 | return true; |
2441 | 0 | } |
2442 | 0 | result = removex || removey; |
2443 | 0 | bool bail = false; |
2444 | 0 | if (removex && removePointValue(values, itx)) |
2445 | 0 | bail = true; |
2446 | 0 | if (removey && removePointValue(values, ity)) |
2447 | 0 | bail = true; |
2448 | 0 | if (bail) |
2449 | 0 | return true; |
2450 | 0 | } |
2451 | 12.0k | } |
2452 | 11.1k | return result; |
2453 | 11.1k | } |
2454 | | |
2455 | | using ValueIterator = std::list<ValueFlow::Value>::iterator; |
2456 | | |
2457 | | template<class Iterator> |
2458 | | // NOLINTNEXTLINE(performance-unnecessary-value-param) - false positive |
2459 | | static ValueIterator removeAdjacentValues(std::list<ValueFlow::Value>& values, ValueIterator x, Iterator start, Iterator last) |
2460 | 0 | { |
2461 | 0 | if (!isAdjacent(*x, **start)) |
2462 | 0 | return std::next(x); |
2463 | 0 | auto it = std::adjacent_find(start, last, [](ValueIterator x, ValueIterator y) { |
2464 | 0 | return !isAdjacent(*x, *y); |
2465 | 0 | }); Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> > >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>) const Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>) const |
2466 | 0 | if (it == last) |
2467 | 0 | it--; |
2468 | 0 | (*it)->bound = x->bound; |
2469 | 0 | std::for_each(std::move(start), std::move(it), [&](ValueIterator y) { |
2470 | 0 | values.erase(y); |
2471 | 0 | }); Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> > >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>) const Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>) const |
2472 | 0 | return values.erase(x); |
2473 | 0 | } Unexecuted instantiation: token.cpp:std::__1::__list_iterator<ValueFlow::Value, void*> removeAdjacentValues<std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> > >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >) Unexecuted instantiation: token.cpp:std::__1::__list_iterator<ValueFlow::Value, void*> removeAdjacentValues<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>) |
2474 | | |
2475 | | static void mergeAdjacent(std::list<ValueFlow::Value>& values) |
2476 | 11.1k | { |
2477 | 23.2k | for (auto x = values.begin(); x != values.end();) { |
2478 | 12.0k | if (x->isNonValue()) { |
2479 | 10 | x++; |
2480 | 10 | continue; |
2481 | 10 | } |
2482 | 12.0k | if (x->bound == ValueFlow::Value::Bound::Point) { |
2483 | 9.44k | x++; |
2484 | 9.44k | continue; |
2485 | 9.44k | } |
2486 | 2.60k | std::vector<ValueIterator> adjValues; |
2487 | 6.96k | for (auto y = values.begin(); y != values.end(); y++) { |
2488 | 4.35k | if (x == y) |
2489 | 2.60k | continue; |
2490 | 1.75k | if (y->isNonValue()) |
2491 | 0 | continue; |
2492 | 1.75k | if (x->valueType != y->valueType) |
2493 | 16 | continue; |
2494 | 1.73k | if (x->valueKind != y->valueKind) |
2495 | 115 | continue; |
2496 | 1.62k | if (x->isSymbolicValue() && !ValueFlow::Value::sameToken(x->tokvalue, y->tokvalue)) |
2497 | 0 | continue; |
2498 | 1.62k | if (x->bound != y->bound) { |
2499 | 1.62k | if (y->bound != ValueFlow::Value::Bound::Point && isAdjacent(*x, *y)) { |
2500 | 0 | adjValues.clear(); |
2501 | 0 | break; |
2502 | 0 | } |
2503 | | // No adjacent points for floating points |
2504 | 1.62k | if (x->valueType == ValueFlow::Value::ValueType::FLOAT) |
2505 | 0 | continue; |
2506 | 1.62k | if (y->bound != ValueFlow::Value::Bound::Point) |
2507 | 1.62k | continue; |
2508 | 1.62k | } |
2509 | 0 | if (x->bound == ValueFlow::Value::Bound::Lower && !y->compareValue(*x, less{})) |
2510 | 0 | continue; |
2511 | 0 | if (x->bound == ValueFlow::Value::Bound::Upper && !x->compareValue(*y, less{})) |
2512 | 0 | continue; |
2513 | 0 | adjValues.push_back(y); |
2514 | 0 | } |
2515 | 2.60k | if (adjValues.empty()) { |
2516 | 2.60k | x++; |
2517 | 2.60k | continue; |
2518 | 2.60k | } |
2519 | 0 | std::sort(adjValues.begin(), adjValues.end(), [&values](ValueIterator xx, ValueIterator yy) { |
2520 | 0 | (void)values; |
2521 | 0 | assert(xx != values.end() && yy != values.end()); |
2522 | 0 | return xx->compareValue(*yy, less{}); |
2523 | 0 | }); |
2524 | 0 | if (x->bound == ValueFlow::Value::Bound::Lower) |
2525 | 0 | x = removeAdjacentValues(values, x, adjValues.rbegin(), adjValues.rend()); |
2526 | 0 | else if (x->bound == ValueFlow::Value::Bound::Upper) |
2527 | 0 | x = removeAdjacentValues(values, x, adjValues.begin(), adjValues.end()); |
2528 | 0 | } |
2529 | 11.1k | } |
2530 | | |
2531 | | static void removeOverlaps(std::list<ValueFlow::Value>& values) |
2532 | 11.1k | { |
2533 | 12.0k | for (const ValueFlow::Value& x : values) { |
2534 | 12.0k | if (x.isNonValue()) |
2535 | 10 | continue; |
2536 | 13.8k | values.remove_if([&](const ValueFlow::Value& y) { |
2537 | 13.8k | if (y.isNonValue()) |
2538 | 4 | return false; |
2539 | 13.8k | if (&x == &y) |
2540 | 12.0k | return false; |
2541 | 1.83k | if (x.valueType != y.valueType) |
2542 | 20 | return false; |
2543 | 1.81k | if (x.valueKind != y.valueKind) |
2544 | 126 | return false; |
2545 | | // TODO: Remove points covered in a lower or upper bound |
2546 | | // TODO: Remove lower or upper bound already covered by a lower and upper bound |
2547 | 1.69k | if (!x.equalValue(y)) |
2548 | 1.69k | return false; |
2549 | 0 | if (x.bound != y.bound) |
2550 | 0 | return false; |
2551 | 0 | return true; |
2552 | 0 | }); |
2553 | 12.0k | } |
2554 | 11.1k | mergeAdjacent(values); |
2555 | 11.1k | } |
2556 | | |
2557 | | // Removing contradictions is an NP-hard problem. Instead we run multiple |
2558 | | // passes to try to catch most contradictions |
2559 | | static void removeContradictions(std::list<ValueFlow::Value>& values) |
2560 | 11.1k | { |
2561 | 11.1k | removeOverlaps(values); |
2562 | 11.1k | for (int i = 0; i < 4; i++) { |
2563 | 11.1k | if (!removeContradiction(values)) |
2564 | 11.1k | return; |
2565 | 0 | removeOverlaps(values); |
2566 | 0 | } |
2567 | 11.1k | } |
2568 | | |
2569 | | static bool sameValueType(const ValueFlow::Value& x, const ValueFlow::Value& y) |
2570 | 164 | { |
2571 | 164 | if (x.valueType != y.valueType) |
2572 | 0 | return false; |
2573 | | // Symbolic are the same type if they share the same tokvalue |
2574 | 164 | if (x.isSymbolicValue()) |
2575 | 106 | return x.tokvalue->exprId() == 0 || x.tokvalue->exprId() == y.tokvalue->exprId(); |
2576 | 58 | return true; |
2577 | 164 | } |
2578 | | |
2579 | | bool Token::addValue(const ValueFlow::Value &value) |
2580 | 12.9k | { |
2581 | 12.9k | if (value.isKnown() && mImpl->mValues) { |
2582 | | // Clear all other values of the same type since value is known |
2583 | 156 | mImpl->mValues->remove_if([&](const ValueFlow::Value& x) { |
2584 | 156 | return sameValueType(x, value); |
2585 | 156 | }); |
2586 | 136 | } |
2587 | | |
2588 | | // Don't add a value if its already known |
2589 | 12.9k | if (!value.isKnown() && mImpl->mValues && |
2590 | 12.9k | std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& x) { |
2591 | 4.25k | return x.isKnown() && sameValueType(x, value) && !x.equalValue(value); |
2592 | 4.25k | })) |
2593 | 0 | return false; |
2594 | | |
2595 | | // assert(value.isKnown() || !mImpl->mValues || std::none_of(mImpl->mValues->begin(), mImpl->mValues->end(), |
2596 | | // [&](const ValueFlow::Value& x) { |
2597 | | // return x.isKnown() && sameValueType(x, value); |
2598 | | // })); |
2599 | | |
2600 | 12.9k | if (mImpl->mValues) { |
2601 | | // Don't handle more than 10 values for performance reasons |
2602 | | // TODO: add setting? |
2603 | 2.81k | if (mImpl->mValues->size() >= 10U) |
2604 | 0 | return false; |
2605 | | |
2606 | | // if value already exists, don't add it again |
2607 | 2.81k | auto it = mImpl->mValues->begin(); |
2608 | 4.50k | for (; it != mImpl->mValues->end(); ++it) { |
2609 | | // different types => continue |
2610 | 3.49k | if (it->valueType != value.valueType) |
2611 | 18 | continue; |
2612 | | |
2613 | 3.47k | if (it->isImpossible() != value.isImpossible()) |
2614 | 108 | continue; |
2615 | | |
2616 | | // different value => continue |
2617 | 3.36k | if (!it->equalValue(value)) |
2618 | 1.57k | continue; |
2619 | | |
2620 | 1.79k | if ((value.isTokValue() || value.isLifetimeValue()) && (it->tokvalue != value.tokvalue) && (it->tokvalue->str() != value.tokvalue->str())) |
2621 | 0 | continue; |
2622 | | |
2623 | | // same value, but old value is inconclusive so replace it |
2624 | 1.79k | if (it->isInconclusive() && !value.isInconclusive() && !value.isImpossible()) { |
2625 | 0 | *it = value; |
2626 | 0 | if (it->varId == 0) |
2627 | 0 | it->varId = mImpl->mVarId; |
2628 | 0 | break; |
2629 | 0 | } |
2630 | | |
2631 | | // Same value already exists, don't add new value |
2632 | 1.79k | return false; |
2633 | 1.79k | } |
2634 | | |
2635 | | // Add value |
2636 | 1.01k | if (it == mImpl->mValues->end()) { |
2637 | 1.01k | ValueFlow::Value v(value); |
2638 | 1.01k | if (v.varId == 0) |
2639 | 1.00k | v.varId = mImpl->mVarId; |
2640 | 1.01k | if (v.isKnown() && v.isIntValue()) |
2641 | 48 | mImpl->mValues->push_front(std::move(v)); |
2642 | 968 | else |
2643 | 968 | mImpl->mValues->push_back(std::move(v)); |
2644 | 1.01k | } |
2645 | 10.1k | } else { |
2646 | 10.1k | ValueFlow::Value v(value); |
2647 | 10.1k | if (v.varId == 0) |
2648 | 10.1k | v.varId = mImpl->mVarId; |
2649 | 10.1k | mImpl->mValues = new std::list<ValueFlow::Value>; |
2650 | 10.1k | mImpl->mValues->push_back(std::move(v)); |
2651 | 10.1k | } |
2652 | | |
2653 | 11.1k | removeContradictions(*mImpl->mValues); |
2654 | | |
2655 | 11.1k | return true; |
2656 | 12.9k | } |
2657 | | |
2658 | | void Token::assignProgressValues(Token *tok) |
2659 | 1.65k | { |
2660 | 1.65k | int total_count = 0; |
2661 | 114k | for (Token *tok2 = tok; tok2; tok2 = tok2->next()) |
2662 | 113k | ++total_count; |
2663 | 1.65k | int count = 0; |
2664 | 114k | for (Token *tok2 = tok; tok2; tok2 = tok2->next()) |
2665 | 113k | tok2->mImpl->mProgressValue = count++ *100 / total_count; |
2666 | 1.65k | } |
2667 | | |
2668 | | void Token::assignIndexes() |
2669 | 790 | { |
2670 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2671 | 790 | int index = (mPrevious ? mPrevious->mImpl->mIndex : 0) + 1; |
2672 | 57.6k | for (Token *tok = this; tok; tok = tok->next()) |
2673 | 56.8k | tok->mImpl->mIndex = index++; |
2674 | 790 | } |
2675 | | |
2676 | | void Token::setValueType(ValueType *vt) |
2677 | 372k | { |
2678 | 372k | if (vt != mImpl->mValueType) { |
2679 | 196k | delete mImpl->mValueType; |
2680 | 196k | mImpl->mValueType = vt; |
2681 | 196k | } |
2682 | 372k | } |
2683 | | |
2684 | 0 | const ValueType *Token::argumentType() const { |
2685 | 0 | const Token *top = this; |
2686 | 0 | while (top && !match34(top->astParent())) |
2687 | 0 | top = top->astParent(); |
2688 | 0 | return top ? top->mImpl->mValueType : nullptr; |
2689 | 0 | } |
2690 | | |
2691 | | void Token::type(const ::Type *t) |
2692 | 58.7k | { |
2693 | 58.7k | mImpl->mType = t; |
2694 | 58.7k | if (t) { |
2695 | 0 | tokType(eType); |
2696 | 0 | isEnumType(mImpl->mType->isEnumType()); |
2697 | 58.7k | } else if (mTokType == eType) |
2698 | 4.92k | tokType(eName); |
2699 | 58.7k | } |
2700 | | |
2701 | | const ::Type* Token::typeOf(const Token* tok, const Token** typeTok) |
2702 | 5.45k | { |
2703 | 5.45k | if (!tok) |
2704 | 0 | return nullptr; |
2705 | 5.45k | if (typeTok != nullptr) |
2706 | 2 | *typeTok = tok; |
2707 | 5.45k | const Token* lhsVarTok{}; |
2708 | 5.45k | if (tok->type()) |
2709 | 0 | return tok->type(); |
2710 | 5.45k | if (tok->variable()) |
2711 | 1.47k | return tok->variable()->type(); |
2712 | 3.98k | if (tok->function()) |
2713 | 0 | return tok->function()->retType; |
2714 | 3.98k | if (match35(tok)) { |
2715 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2716 | 1 | const Scope *scope = tok->scope(); |
2717 | 1 | if (!scope) |
2718 | 0 | return nullptr; |
2719 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2720 | 1 | const Function *function = scope->function; |
2721 | 1 | if (!function) |
2722 | 0 | return nullptr; |
2723 | 1 | return function->retType; |
2724 | 1 | } |
2725 | 3.98k | if (match36(tok->previous())) |
2726 | 0 | return typeOf(tok->previous(), typeTok); |
2727 | 3.98k | if (match37(tok) && (lhsVarTok = getLHSVariableToken(tok)) != tok->next()) |
2728 | 0 | return Token::typeOf(lhsVarTok, typeTok); |
2729 | 3.98k | if (match38(tok)) |
2730 | 0 | return Token::typeOf(tok->astOperand2(), typeTok); |
2731 | 3.98k | if (match39(tok)) |
2732 | 0 | return Token::typeOf(tok->astOperand1(), typeTok); |
2733 | 3.98k | if (match25(tok)) { |
2734 | 0 | int argnr; |
2735 | 0 | const Token* ftok = getTokenArgumentFunction(tok, argnr); |
2736 | 0 | if (argnr < 0) |
2737 | 0 | return nullptr; |
2738 | 0 | if (!ftok) |
2739 | 0 | return nullptr; |
2740 | 0 | if (ftok == tok) |
2741 | 0 | return nullptr; |
2742 | 0 | std::vector<const Variable*> vars = getArgumentVars(ftok, argnr); |
2743 | 0 | if (vars.empty()) |
2744 | 0 | return nullptr; |
2745 | 0 | if (std::all_of( |
2746 | 0 | vars.cbegin(), vars.cend(), [&](const Variable* var) { |
2747 | 0 | return var->type() == vars.front()->type(); |
2748 | 0 | })) |
2749 | 0 | return vars.front()->type(); |
2750 | 0 | } |
2751 | | |
2752 | 3.98k | return nullptr; |
2753 | 3.98k | } |
2754 | | |
2755 | | std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool pointedToType) |
2756 | 3.46k | { |
2757 | 3.46k | if (!tok) |
2758 | 0 | return {}; |
2759 | 3.46k | if (tok->type()) |
2760 | 0 | return {tok, tok->next()}; |
2761 | 3.46k | if (tok->variable()) { |
2762 | 1.47k | const Variable *var = tok->variable(); |
2763 | 1.47k | if (!var->typeStartToken() || !var->typeEndToken()) |
2764 | 0 | return {}; |
2765 | 1.47k | if (pointedToType && astIsSmartPointer(var->nameToken())) { |
2766 | 0 | const ValueType* vt = var->valueType(); |
2767 | 0 | if (vt && vt->smartPointerTypeToken) |
2768 | 0 | return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) }; |
2769 | 0 | } |
2770 | 1.47k | if (pointedToType && astIsIterator(var->nameToken())) { |
2771 | 0 | const ValueType* vt = var->valueType(); |
2772 | 0 | if (vt && vt->containerTypeToken) |
2773 | 0 | return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) }; |
2774 | 0 | } |
2775 | 1.47k | std::pair<const Token*, const Token*> result; |
2776 | 1.47k | if (match40(var->typeStartToken())) { |
2777 | 0 | const Token * tok2 = var->declEndToken(); |
2778 | 0 | if (match41(tok2, var->declarationId())) |
2779 | 0 | tok2 = tok2->tokAt(2); |
2780 | 0 | if (match37(tok2) && match42(tok2->astOperand2()) && tok != tok2->astOperand2()) { |
2781 | 0 | tok2 = tok2->astOperand2(); |
2782 | |
|
2783 | 0 | if (match39(tok2) && tok2->astOperand1()) { |
2784 | 0 | const ValueType* vt = tok2->astOperand1()->valueType(); |
2785 | 0 | if (vt && vt->containerTypeToken) |
2786 | 0 | return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) }; |
2787 | 0 | } |
2788 | | |
2789 | 0 | const Token* varTok = tok2; // try to find a variable |
2790 | 0 | if (match21(varTok)) |
2791 | 0 | varTok = varTok->next(); |
2792 | 0 | while (match43(varTok)) |
2793 | 0 | varTok = varTok->tokAt(2); |
2794 | 0 | std::pair<const Token*, const Token*> r = typeDecl(varTok); |
2795 | 0 | if (r.first) |
2796 | 0 | return r; |
2797 | | |
2798 | 0 | if (pointedToType && tok2->astOperand1() && match44(tok2)) { |
2799 | 0 | if (match45(tok2->astOperand1())) |
2800 | 0 | return { tok2->next(), tok2->astOperand1() }; |
2801 | 0 | const Token* declEnd = nextAfterAstRightmostLeaf(tok2->astOperand1()); |
2802 | 0 | if (match46(declEnd) && declEnd->link()) |
2803 | 0 | declEnd = declEnd->link()->next(); |
2804 | 0 | return { tok2->next(), declEnd }; |
2805 | 0 | } |
2806 | 0 | const Token *typeBeg{}, *typeEnd{}; |
2807 | 0 | if (tok2->str() == MatchCompiler::makeConstString("::") && match25(tok2->astOperand2())) { // empty initlist |
2808 | 0 | typeBeg = previousBeforeAstLeftmostLeaf(tok2); |
2809 | 0 | typeEnd = tok2->astOperand2(); |
2810 | 0 | } |
2811 | 0 | else if (tok2->str() == MatchCompiler::makeConstString("{")) { |
2812 | 0 | typeBeg = previousBeforeAstLeftmostLeaf(tok2); |
2813 | 0 | typeEnd = tok2; |
2814 | 0 | } |
2815 | 0 | if (typeBeg) |
2816 | 0 | result = { typeBeg->next(), typeEnd }; // handle smart pointers/iterators first |
2817 | 0 | } |
2818 | 0 | if (astIsRangeBasedForDecl(var->nameToken()) && astIsContainer(var->nameToken()->astParent()->astOperand2())) { // range-based for |
2819 | 0 | const ValueType* vt = var->nameToken()->astParent()->astOperand2()->valueType(); |
2820 | 0 | if (vt && vt->containerTypeToken) |
2821 | 0 | return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) }; |
2822 | 0 | } |
2823 | 0 | } |
2824 | 1.47k | if (result.first) |
2825 | 0 | return result; |
2826 | 1.47k | return {var->typeStartToken(), var->typeEndToken()->next()}; |
2827 | 1.47k | } |
2828 | 1.99k | if (match35(tok)) { |
2829 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2830 | 1 | const Scope* scope = tok->scope(); |
2831 | 1 | if (!scope) |
2832 | 0 | return {}; |
2833 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2834 | 1 | const Function* function = scope->function; |
2835 | 1 | if (!function) |
2836 | 0 | return {}; |
2837 | 1 | return { function->retDef, function->returnDefEnd() }; |
2838 | 1 | } |
2839 | 1.99k | if (tok->previous() && tok->previous()->function()) { |
2840 | | // cppcheck-suppress shadowFunction - TODO: fix this |
2841 | 0 | const Function *function = tok->previous()->function(); |
2842 | 0 | return {function->retDef, function->returnDefEnd()}; |
2843 | 0 | } |
2844 | 1.99k | if (match37(tok)) |
2845 | 0 | return Token::typeDecl(tok->astOperand1()); |
2846 | 1.99k | if (match38(tok)) |
2847 | 0 | return Token::typeDecl(tok->astOperand2()); |
2848 | | |
2849 | 1.99k | const ::Type * t = typeOf(tok); |
2850 | 1.99k | if (!t || !t->classDef) |
2851 | 1.99k | return {}; |
2852 | 0 | return {t->classDef->next(), t->classDef->tokAt(2)}; |
2853 | 1.99k | } |
2854 | | std::string Token::typeStr(const Token* tok) |
2855 | 0 | { |
2856 | 0 | if (tok->valueType()) { |
2857 | 0 | const ValueType * vt = tok->valueType(); |
2858 | 0 | std::string ret = vt->str(); |
2859 | 0 | if (!ret.empty()) |
2860 | 0 | return ret; |
2861 | 0 | } |
2862 | 0 | std::pair<const Token*, const Token*> r = Token::typeDecl(tok); |
2863 | 0 | if (!r.first || !r.second) |
2864 | 0 | return ""; |
2865 | 0 | return r.first->stringifyList(r.second, false); |
2866 | 0 | } |
2867 | | |
2868 | | void Token::scopeInfo(std::shared_ptr<ScopeInfo2> newScopeInfo) |
2869 | 115k | { |
2870 | 115k | mImpl->mScopeInfo = std::move(newScopeInfo); |
2871 | 115k | } |
2872 | | std::shared_ptr<ScopeInfo2> Token::scopeInfo() const |
2873 | 116k | { |
2874 | 116k | return mImpl->mScopeInfo; |
2875 | 116k | } |
2876 | | |
2877 | | bool Token::hasKnownIntValue() const |
2878 | 533k | { |
2879 | 533k | if (!mImpl->mValues) |
2880 | 432k | return false; |
2881 | 129k | return std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) { |
2882 | 129k | return value.isKnown() && value.isIntValue(); |
2883 | 129k | }); |
2884 | 533k | } |
2885 | | |
2886 | | bool Token::hasKnownValue() const |
2887 | 564 | { |
2888 | 564 | return mImpl->mValues && std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown)); |
2889 | 564 | } |
2890 | | |
2891 | | bool Token::hasKnownValue(ValueFlow::Value::ValueType t) const |
2892 | 0 | { |
2893 | 0 | return mImpl->mValues && |
2894 | 0 | std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) { |
2895 | 0 | return value.isKnown() && value.valueType == t; |
2896 | 0 | }); |
2897 | 0 | } |
2898 | | |
2899 | | bool Token::hasKnownSymbolicValue(const Token* tok) const |
2900 | 5.87k | { |
2901 | 5.87k | if (tok->exprId() == 0) |
2902 | 0 | return false; |
2903 | 5.87k | return mImpl->mValues && |
2904 | 5.87k | std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) { |
2905 | 935 | return value.isKnown() && value.isSymbolicValue() && value.tokvalue && |
2906 | 935 | value.tokvalue->exprId() == tok->exprId(); |
2907 | 935 | }); |
2908 | 5.87k | } |
2909 | | |
2910 | | const ValueFlow::Value* Token::getKnownValue(ValueFlow::Value::ValueType t) const |
2911 | 109k | { |
2912 | 109k | if (!mImpl->mValues) |
2913 | 69.6k | return nullptr; |
2914 | 72.1k | auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) { |
2915 | 72.1k | return value.isKnown() && value.valueType == t; |
2916 | 72.1k | }); |
2917 | 40.3k | return it == mImpl->mValues->end() ? nullptr : &*it; |
2918 | 109k | } |
2919 | | |
2920 | | const ValueFlow::Value* Token::getValue(const MathLib::bigint val) const |
2921 | 3.87k | { |
2922 | 3.87k | if (!mImpl->mValues) |
2923 | 3.35k | return nullptr; |
2924 | 770 | const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [=](const ValueFlow::Value& value) { |
2925 | 770 | return value.isIntValue() && !value.isImpossible() && value.intvalue == val; |
2926 | 770 | }); |
2927 | 526 | return it == mImpl->mValues->end() ? nullptr : &*it; |
2928 | 3.87k | } |
2929 | | |
2930 | | template<class Compare> |
2931 | | static const ValueFlow::Value* getCompareValue(const std::list<ValueFlow::Value>& values, |
2932 | | bool condition, |
2933 | | MathLib::bigint path, |
2934 | | Compare compare) |
2935 | 0 | { |
2936 | 0 | const ValueFlow::Value* ret = nullptr; |
2937 | 0 | for (const ValueFlow::Value& value : values) { |
2938 | 0 | if (!value.isIntValue()) |
2939 | 0 | continue; |
2940 | 0 | if (value.isImpossible()) |
2941 | 0 | continue; |
2942 | 0 | if (path > -0 && value.path != 0 && value.path != path) |
2943 | 0 | continue; |
2944 | 0 | if ((!ret || compare(value.intvalue, ret->intvalue)) && ((value.condition != nullptr) == condition)) |
2945 | 0 | ret = &value; |
2946 | 0 | } |
2947 | 0 | return ret; |
2948 | 0 | } Unexecuted instantiation: token.cpp:ValueFlow::Value const* getCompareValue<std::__1::greater<long long> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> > const&, bool, long long, std::__1::greater<long long>) Unexecuted instantiation: token.cpp:ValueFlow::Value const* getCompareValue<std::__1::less<long long> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> > const&, bool, long long, std::__1::less<long long>) |
2949 | | |
2950 | | const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const |
2951 | 0 | { |
2952 | 0 | if (!mImpl->mValues) |
2953 | 0 | return nullptr; |
2954 | 0 | return getCompareValue(*mImpl->mValues, condition, path, std::greater<MathLib::bigint>{}); |
2955 | 0 | } |
2956 | | |
2957 | | const ValueFlow::Value* Token::getMinValue(bool condition, MathLib::bigint path) const |
2958 | 0 | { |
2959 | 0 | if (!mImpl->mValues) |
2960 | 0 | return nullptr; |
2961 | 0 | return getCompareValue(*mImpl->mValues, condition, path, std::less<MathLib::bigint>{}); |
2962 | 0 | } |
2963 | | |
2964 | | const ValueFlow::Value* Token::getMovedValue() const |
2965 | 11.0k | { |
2966 | 11.0k | if (!mImpl->mValues) |
2967 | 8.82k | return nullptr; |
2968 | 3.05k | const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) { |
2969 | 3.05k | return value.isMovedValue() && !value.isImpossible() && |
2970 | 3.05k | value.moveKind != ValueFlow::Value::MoveKind::NonMovedVariable; |
2971 | 3.05k | }); |
2972 | 2.23k | return it == mImpl->mValues->end() ? nullptr : &*it; |
2973 | 11.0k | } |
2974 | | |
2975 | | // cppcheck-suppress unusedFunction |
2976 | | const ValueFlow::Value* Token::getContainerSizeValue(const MathLib::bigint val) const |
2977 | 0 | { |
2978 | 0 | if (!mImpl->mValues) |
2979 | 0 | return nullptr; |
2980 | 0 | const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [=](const ValueFlow::Value& value) { |
2981 | 0 | return value.isContainerSizeValue() && !value.isImpossible() && value.intvalue == val; |
2982 | 0 | }); |
2983 | 0 | return it == mImpl->mValues->end() ? nullptr : &*it; |
2984 | 0 | } |
2985 | | |
2986 | | TokenImpl::~TokenImpl() |
2987 | 64.1k | { |
2988 | 64.1k | delete mOriginalName; |
2989 | 64.1k | delete mValueType; |
2990 | 64.1k | delete mValues; |
2991 | | |
2992 | 64.1k | if (mTemplateSimplifierPointers) { |
2993 | 0 | for (auto *templateSimplifierPointer : *mTemplateSimplifierPointers) { |
2994 | 0 | templateSimplifierPointer->token(nullptr); |
2995 | 0 | } |
2996 | 0 | } |
2997 | 64.1k | delete mTemplateSimplifierPointers; |
2998 | | |
2999 | 64.1k | while (mCppcheckAttributes) { |
3000 | 0 | CppcheckAttributes *c = mCppcheckAttributes; |
3001 | 0 | mCppcheckAttributes = mCppcheckAttributes->next; |
3002 | 0 | delete c; |
3003 | 0 | } |
3004 | 64.1k | } |
3005 | | |
3006 | | void TokenImpl::setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value) |
3007 | 0 | { |
3008 | 0 | CppcheckAttributes *attr = mCppcheckAttributes; |
3009 | 0 | while (attr && attr->type != type) |
3010 | 0 | attr = attr->next; |
3011 | 0 | if (attr) |
3012 | 0 | attr->value = value; |
3013 | 0 | else { |
3014 | 0 | attr = new CppcheckAttributes; |
3015 | 0 | attr->type = type; |
3016 | 0 | attr->value = value; |
3017 | 0 | attr->next = mCppcheckAttributes; |
3018 | 0 | mCppcheckAttributes = attr; |
3019 | 0 | } |
3020 | 0 | } |
3021 | | |
3022 | | bool TokenImpl::getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint &value) const |
3023 | 0 | { |
3024 | 0 | CppcheckAttributes *attr = mCppcheckAttributes; |
3025 | 0 | while (attr && attr->type != type) |
3026 | 0 | attr = attr->next; |
3027 | 0 | if (attr) |
3028 | 0 | value = attr->value; |
3029 | 0 | return attr != nullptr; |
3030 | 0 | } |
3031 | | |
3032 | | Token* findTypeEnd(Token* tok) |
3033 | 0 | { |
3034 | 0 | while (match47(tok)) { |
3035 | 0 | if (match48(tok)) |
3036 | 0 | tok = tok->link(); |
3037 | 0 | if (!tok) |
3038 | 0 | return nullptr; |
3039 | 0 | tok = tok->next(); |
3040 | 0 | } |
3041 | 0 | return tok; |
3042 | 0 | } |
3043 | | |
3044 | | Token* findLambdaEndScope(Token* tok) |
3045 | 0 | { |
3046 | 0 | if (!match39(tok)) |
3047 | 0 | return nullptr; |
3048 | 0 | tok = tok->link(); |
3049 | 0 | if (!match49(tok)) |
3050 | 0 | return nullptr; |
3051 | 0 | tok = tok->linkAt(1); |
3052 | 0 | if (match26(tok)) |
3053 | 0 | return tok; |
3054 | 0 | if (match50(tok)) |
3055 | 0 | return tok->linkAt(1); |
3056 | 0 | if (!match51(tok)) |
3057 | 0 | return nullptr; |
3058 | 0 | tok = tok->next(); |
3059 | 0 | while (match52(tok)) { |
3060 | 0 | if (match53(tok)) |
3061 | 0 | tok = tok->linkAt(1); |
3062 | 0 | if (match38(tok)) { |
3063 | 0 | tok = findTypeEnd(tok); |
3064 | 0 | break; |
3065 | 0 | } |
3066 | 0 | tok = tok->next(); |
3067 | 0 | } |
3068 | 0 | if (match25(tok)) |
3069 | 0 | return tok->link(); |
3070 | 0 | return nullptr; |
3071 | 0 | } |
3072 | 0 | const Token* findLambdaEndScope(const Token* tok) { |
3073 | 0 | return findLambdaEndScope(const_cast<Token*>(tok)); |
3074 | 0 | } |
3075 | | |
3076 | 1.10k | const std::string& Token::fileName() const { |
3077 | 1.10k | return mTokensFrontBack.list.getFiles()[mImpl->mFileIndex]; |
3078 | 1.10k | } |