cppcheck-py 2.9__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. cppcheck/__init__.py +55 -0
  2. cppcheck/cppcheck-2.9.tar.gz +0 -0
  3. cppcheck/data/addons/__init__.py +0 -0
  4. cppcheck/data/addons/cppcheck.py +39 -0
  5. cppcheck/data/addons/cppcheckdata.py +1529 -0
  6. cppcheck/data/addons/findcasts.py +33 -0
  7. cppcheck/data/addons/misc.py +163 -0
  8. cppcheck/data/addons/misra.py +4728 -0
  9. cppcheck/data/addons/misra_9.py +513 -0
  10. cppcheck/data/addons/naming.py +91 -0
  11. cppcheck/data/addons/namingng.py +253 -0
  12. cppcheck/data/addons/runaddon.py +12 -0
  13. cppcheck/data/addons/threadsafety.py +39 -0
  14. cppcheck/data/addons/y2038.py +252 -0
  15. cppcheck/data/cfg/avr.cfg +431 -0
  16. cppcheck/data/cfg/bento4.cfg +142 -0
  17. cppcheck/data/cfg/boost.cfg +1268 -0
  18. cppcheck/data/cfg/bsd.cfg +546 -0
  19. cppcheck/data/cfg/cairo.cfg +88 -0
  20. cppcheck/data/cfg/cppcheck-lib.cfg +72 -0
  21. cppcheck/data/cfg/cppunit.cfg +48 -0
  22. cppcheck/data/cfg/daca.cfg +31 -0
  23. cppcheck/data/cfg/dpdk.cfg +11 -0
  24. cppcheck/data/cfg/embedded_sql.cfg +4 -0
  25. cppcheck/data/cfg/emscripten.cfg +7 -0
  26. cppcheck/data/cfg/ginac.cfg +12848 -0
  27. cppcheck/data/cfg/gnu.cfg +1626 -0
  28. cppcheck/data/cfg/googletest.cfg +60 -0
  29. cppcheck/data/cfg/gtk.cfg +20584 -0
  30. cppcheck/data/cfg/icu.cfg +6 -0
  31. cppcheck/data/cfg/kde.cfg +51 -0
  32. cppcheck/data/cfg/libcerror.cfg +128 -0
  33. cppcheck/data/cfg/libcurl.cfg +487 -0
  34. cppcheck/data/cfg/libsigc++.cfg +36 -0
  35. cppcheck/data/cfg/lua.cfg +316 -0
  36. cppcheck/data/cfg/mfc.cfg +256 -0
  37. cppcheck/data/cfg/microsoft_atl.cfg +40 -0
  38. cppcheck/data/cfg/microsoft_sal.cfg +491 -0
  39. cppcheck/data/cfg/microsoft_unittest.cfg +20 -0
  40. cppcheck/data/cfg/motif.cfg +318 -0
  41. cppcheck/data/cfg/nspr.cfg +38 -0
  42. cppcheck/data/cfg/ntl.cfg +6907 -0
  43. cppcheck/data/cfg/opencv2.cfg +132 -0
  44. cppcheck/data/cfg/opengl.cfg +580 -0
  45. cppcheck/data/cfg/openmp.cfg +157 -0
  46. cppcheck/data/cfg/openssl.cfg +174 -0
  47. cppcheck/data/cfg/pcre.cfg +165 -0
  48. cppcheck/data/cfg/posix.cfg +6252 -0
  49. cppcheck/data/cfg/python.cfg +674 -0
  50. cppcheck/data/cfg/qt.cfg +5255 -0
  51. cppcheck/data/cfg/ruby.cfg +142 -0
  52. cppcheck/data/cfg/sdl.cfg +354 -0
  53. cppcheck/data/cfg/sfml.cfg +301 -0
  54. cppcheck/data/cfg/sqlite3.cfg +1527 -0
  55. cppcheck/data/cfg/std.cfg +8716 -0
  56. cppcheck/data/cfg/tinyxml2.cfg +56 -0
  57. cppcheck/data/cfg/vcl.cfg +4 -0
  58. cppcheck/data/cfg/windows.cfg +17941 -0
  59. cppcheck/data/cfg/wxsqlite3.cfg +1955 -0
  60. cppcheck/data/cfg/wxsvg.cfg +16905 -0
  61. cppcheck/data/cfg/wxwidgets.cfg +16464 -0
  62. cppcheck/data/cfg/zlib.cfg +1450 -0
  63. cppcheck/data/cppcheck-htmlreport +986 -0
  64. cppcheck/data/cppcheck.exe +0 -0
  65. cppcheck/data/platforms/aix_ppc64.xml +17 -0
  66. cppcheck/data/platforms/arm32-wchar_t2.xml +17 -0
  67. cppcheck/data/platforms/arm32-wchar_t4.xml +17 -0
  68. cppcheck/data/platforms/arm64-wchar_t2.xml +17 -0
  69. cppcheck/data/platforms/arm64-wchar_t4.xml +17 -0
  70. cppcheck/data/platforms/avr8.xml +18 -0
  71. cppcheck/data/platforms/cray_sv1.xml +17 -0
  72. cppcheck/data/platforms/elbrus-e1cp.xml +18 -0
  73. cppcheck/data/platforms/mips32.xml +18 -0
  74. cppcheck/data/platforms/msp430_eabi_large_datamodel.xml +17 -0
  75. cppcheck/data/platforms/pic16.xml +18 -0
  76. cppcheck/data/platforms/pic8-enhanced.xml +18 -0
  77. cppcheck/data/platforms/pic8.xml +18 -0
  78. cppcheck/data/platforms/unix32-unsigned.xml +17 -0
  79. cppcheck/data/platforms/unix64-unsigned.xml +17 -0
  80. cppcheck_py-2.9.dist-info/METADATA +76 -0
  81. cppcheck_py-2.9.dist-info/RECORD +84 -0
  82. cppcheck_py-2.9.dist-info/WHEEL +5 -0
  83. cppcheck_py-2.9.dist-info/entry_points.txt +4 -0
  84. cppcheck_py-2.9.dist-info/licenses/LICENSE.md +191 -0
@@ -0,0 +1,1529 @@
1
+ """
2
+ cppcheckdata
3
+
4
+ This is a Python module that helps you access Cppcheck dump data.
5
+
6
+ License: No restrictions, use this as you need.
7
+ """
8
+
9
+ import argparse
10
+ import json
11
+ import os
12
+ import sys
13
+ import subprocess
14
+
15
+ try:
16
+ import pathlib
17
+ except ImportError:
18
+ message = "Failed to load pathlib. Upgrade python to 3.x or install pathlib with 'pip install pathlib'."
19
+ error_id = 'pythonError'
20
+ if '--cli' in sys.argv:
21
+ msg = { 'file': '',
22
+ 'linenr': 0,
23
+ 'column': 0,
24
+ 'severity': 'error',
25
+ 'message': message,
26
+ 'addon': 'cppcheckdata',
27
+ 'errorId': error_id,
28
+ 'extra': ''}
29
+ sys.stdout.write(json.dumps(msg) + '\n')
30
+ else:
31
+ sys.stderr.write('%s [%s]\n' % (message, error_id))
32
+ sys.exit(1)
33
+
34
+ from xml.etree import ElementTree
35
+ from fnmatch import fnmatch
36
+
37
+ EXIT_CODE = 0
38
+
39
+ current_dumpfile_suppressions = []
40
+
41
+ def _load_location(location, element):
42
+ """Load location from element/dict"""
43
+ location.file = element.get('file')
44
+ line = element.get('line')
45
+ if line is None:
46
+ line = element.get('linenr')
47
+ if line is None:
48
+ line = '0'
49
+ location.linenr = int(line)
50
+ location.column = int(element.get('column', '0'))
51
+
52
+
53
+ class Location:
54
+ """Utility location class"""
55
+ file = None
56
+ linenr = None
57
+ column = None
58
+ def __init__(self, element):
59
+ _load_location(self, element)
60
+
61
+
62
+ class Directive:
63
+ """
64
+ Directive class. Contains information about each preprocessor directive in the source code.
65
+
66
+ Attributes:
67
+ str The directive line, with all C or C++ comments removed
68
+ file Name of (possibly included) file where directive is defined
69
+ linenr Line number in (possibly included) file where directive is defined
70
+
71
+ To iterate through all directives use such code:
72
+ @code
73
+ data = cppcheckdata.parsedump(...)
74
+ for cfg in data.configurations:
75
+ for directive in cfg.directives:
76
+ print(directive.str)
77
+ @endcode
78
+ """
79
+
80
+ str = None
81
+ file = None
82
+ linenr = None
83
+ column = None
84
+
85
+ def __init__(self, element):
86
+ self.str = element.get('str')
87
+ _load_location(self, element)
88
+
89
+ def __repr__(self):
90
+ attrs = ["str", "file", "linenr"]
91
+ return "{}({})".format(
92
+ "Directive",
93
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
94
+ )
95
+
96
+ class MacroUsage:
97
+ """
98
+ Tracks preprocessor macro usage
99
+ """
100
+
101
+ name = None # Macro name
102
+ file = None
103
+ linenr = None
104
+ column = None
105
+ usefile = None
106
+ uselinenr = None
107
+ usecolumn = None
108
+
109
+ def __init__(self, element):
110
+ self.name = element.get('name')
111
+ _load_location(self, element)
112
+ self.usefile = element.get('usefile')
113
+ self.useline = element.get('useline')
114
+ self.usecolumn = element.get('usecolumn')
115
+
116
+ def __repr__(self):
117
+ attrs = ["name", "file", "linenr", "column", "usefile", "useline", "usecolumn"]
118
+ return "{}({})".format(
119
+ "MacroUsage",
120
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
121
+ )
122
+
123
+
124
+ class PreprocessorIfCondition:
125
+ """
126
+ Information about #if/#elif conditions
127
+ """
128
+
129
+ file = None
130
+ linenr = None
131
+ column = None
132
+ E = None
133
+ result = None
134
+
135
+ def __init__(self, element):
136
+ _load_location(self, element)
137
+ self.E = element.get('E')
138
+ self.result = int(element.get('result'))
139
+
140
+ def __repr__(self):
141
+ attrs = ["file", "linenr", "column", "E", "result"]
142
+ return "{}({})".format(
143
+ "PreprocessorIfCondition",
144
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
145
+ )
146
+
147
+
148
+ class ValueType:
149
+ """
150
+ ValueType class. Contains (promoted) type information for each node in the AST.
151
+ """
152
+
153
+ type = None
154
+ sign = None
155
+ bits = 0
156
+ constness = 0
157
+ pointer = 0
158
+ typeScopeId = None
159
+ typeScope = None
160
+ originalTypeName = None
161
+
162
+ def __init__(self, element):
163
+ self.type = element.get('valueType-type')
164
+ self.sign = element.get('valueType-sign')
165
+ self.bits = int(element.get('valueType-bits', 0))
166
+ self.typeScopeId = element.get('valueType-typeScope')
167
+ self.originalTypeName = element.get('valueType-originalTypeName')
168
+ self.constness = int(element.get('valueType-constness', 0))
169
+ self.pointer = int(element.get('valueType-pointer', 0))
170
+
171
+ def __repr__(self):
172
+ attrs = ["type", "sign", "bits", "typeScopeId", "originalTypeName",
173
+ "constness", "pointer"]
174
+ return "{}({})".format(
175
+ "ValueType",
176
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
177
+ )
178
+
179
+
180
+ def setId(self, IdMap):
181
+ self.typeScope = IdMap[self.typeScopeId]
182
+
183
+ def isIntegral(self):
184
+ return self.type in {'bool', 'char', 'short', 'int', 'long', 'long long'}
185
+
186
+ def isFloat(self):
187
+ return self.type in {'float', 'double', 'long double'}
188
+
189
+ def isEnum(self):
190
+ return self.typeScope and self.typeScope.type == "Enum"
191
+
192
+
193
+ class Token:
194
+ """
195
+ Token class. Contains information about each token in the source code.
196
+
197
+ The CppcheckData.tokenlist is a list of Token items
198
+
199
+ C++ class: https://cppcheck.sourceforge.io/devinfo/doxyoutput/classToken.html
200
+
201
+ Attributes:
202
+ str Token string
203
+ next Next token in tokenlist. For last token, next is None.
204
+ previous Previous token in tokenlist. For first token, previous is None.
205
+ link Linked token in tokenlist. Each '(', '[' and '{' are linked to the
206
+ corresponding '}', ']' and ')'. For templates, the '<' is linked to
207
+ the corresponding '>'.
208
+ scope Scope information for this token. See the Scope class.
209
+ isName Is this token a symbol name
210
+ isNumber Is this token a number, for example 123, 12.34
211
+ isInt Is this token a int value such as 1234
212
+ isFloat Is this token a float value such as 12.34
213
+ isString Is this token a string literal such as "hello"
214
+ strlen string length for string literal
215
+ isChar Is this token a char literal such as 'x'
216
+ isOp Is this token a operator
217
+ isArithmeticalOp Is this token a arithmetic operator
218
+ isAssignmentOp Is this token a assignment operator
219
+ isComparisonOp Is this token a comparison operator
220
+ isLogicalOp Is this token a logical operator: && ||
221
+ isUnsigned Is this token a unsigned type
222
+ isSigned Is this token a signed type
223
+ isExpandedMacro Is this token a expanded macro token
224
+ isRemovedVoidParameter Has void parameter been removed?
225
+ isSplittedVarDeclComma Is this a comma changed to semicolon in a splitted variable declaration ('int a,b;' => 'int a; int b;')
226
+ isSplittedVarDeclEq Is this a '=' changed to semicolon in a splitted variable declaration ('int a=5;' => 'int a; a=5;')
227
+ isImplicitInt Is this token an implicit "int"?
228
+ varId varId for token, each variable has a unique non-zero id
229
+ variable Variable information for this token. See the Variable class.
230
+ function If this token points at a function call, this attribute has the Function
231
+ information. See the Function class.
232
+ values Possible/Known values of token
233
+ impossible_values Impossible values of token
234
+ valueType type information
235
+ typeScope type scope (token->type()->classScope)
236
+ astParent ast parent
237
+ astOperand1 ast operand1
238
+ astOperand2 ast operand2
239
+ file file name
240
+ linenr line number
241
+ column column
242
+
243
+ To iterate through all tokens use such code:
244
+ @code
245
+ data = cppcheckdata.parsedump(...)
246
+ for cfg in data.configurations:
247
+ code = ''
248
+ for token in cfg.tokenlist:
249
+ code = code + token.str + ' '
250
+ print(code)
251
+ @endcode
252
+ """
253
+
254
+ Id = None
255
+ str = None
256
+ next = None
257
+ previous = None
258
+ linkId = None
259
+ link = None
260
+ scopeId = None
261
+ scope = None
262
+ isName = False
263
+ isNumber = False
264
+ isInt = False
265
+ isFloat = False
266
+ isString = False
267
+ strlen = None
268
+ isChar = False
269
+ isOp = False
270
+ isArithmeticalOp = False
271
+ isAssignmentOp = False
272
+ isComparisonOp = False
273
+ isLogicalOp = False
274
+ isUnsigned = False
275
+ isSigned = False
276
+ isExpandedMacro = False
277
+ isRemovedVoidParameter = False
278
+ isSplittedVarDeclComma = False
279
+ isSplittedVarDeclEq = False
280
+ isImplicitInt = False
281
+ exprId = None
282
+ varId = None
283
+ variableId = None
284
+ variable = None
285
+ functionId = None
286
+ function = None
287
+ valuesId = None
288
+ values = None
289
+ impossible_values = None
290
+ valueType = None
291
+
292
+ typeScopeId = None
293
+ typeScope = None
294
+
295
+ astParentId = None
296
+ astParent = None
297
+ astOperand1Id = None
298
+ astOperand1 = None
299
+ astOperand2Id = None
300
+ astOperand2 = None
301
+
302
+ file = None
303
+ linenr = None
304
+ column = None
305
+
306
+ def __init__(self, element):
307
+ self.Id = element.get('id')
308
+ self.str = element.get('str')
309
+ self.next = None
310
+ self.previous = None
311
+ self.scopeId = element.get('scope')
312
+ self.scope = None
313
+ type = element.get('type')
314
+ if type == 'name':
315
+ self.isName = True
316
+ if element.get('isUnsigned'):
317
+ self.isUnsigned = True
318
+ if element.get('isSigned'):
319
+ self.isSigned = True
320
+ elif type == 'number':
321
+ self.isNumber = True
322
+ if element.get('isInt'):
323
+ self.isInt = True
324
+ elif element.get('isFloat'):
325
+ self.isFloat = True
326
+ elif type == 'string':
327
+ self.isString = True
328
+ self.strlen = int(element.get('strlen'))
329
+ elif type == 'char':
330
+ self.isChar = True
331
+ elif type == 'op':
332
+ self.isOp = True
333
+ if element.get('isArithmeticalOp'):
334
+ self.isArithmeticalOp = True
335
+ elif element.get('isAssignmentOp'):
336
+ self.isAssignmentOp = True
337
+ elif element.get('isComparisonOp'):
338
+ self.isComparisonOp = True
339
+ elif element.get('isLogicalOp'):
340
+ self.isLogicalOp = True
341
+ if element.get('isExpandedMacro'):
342
+ self.isExpandedMacro = True
343
+ if element.get('isRemovedVoidParameter'):
344
+ self.isRemovedVoidParameter = True
345
+ if element.get('isSplittedVarDeclComma'):
346
+ self.isSplittedVarDeclComma = True
347
+ if element.get('isSplittedVarDeclEq'):
348
+ self.isSplittedVarDeclEq = True
349
+ if element.get('isImplicitInt'):
350
+ self.isImplicitInt = True
351
+ self.linkId = element.get('link')
352
+ self.link = None
353
+ if element.get('varId'):
354
+ self.varId = int(element.get('varId'))
355
+ if element.get('exprId'):
356
+ self.exprId = int(element.get('exprId'))
357
+ self.variableId = element.get('variable')
358
+ self.variable = None
359
+ self.functionId = element.get('function')
360
+ self.function = None
361
+ self.valuesId = element.get('values')
362
+ self.values = None
363
+ if element.get('valueType-type'):
364
+ self.valueType = ValueType(element)
365
+ else:
366
+ self.valueType = None
367
+ self.typeScopeId = element.get('type-scope')
368
+ self.typeScope = None
369
+ self.astParentId = element.get('astParent')
370
+ self.astParent = None
371
+ self.astOperand1Id = element.get('astOperand1')
372
+ self.astOperand1 = None
373
+ self.astOperand2Id = element.get('astOperand2')
374
+ self.astOperand2 = None
375
+ _load_location(self, element)
376
+
377
+ def __repr__(self):
378
+ attrs = ["Id", "str", "scopeId", "isName", "isUnsigned", "isSigned",
379
+ "isNumber", "isInt", "isFloat", "isString", "strlen",
380
+ "isChar", "isOp", "isArithmeticalOp", "isComparisonOp",
381
+ "isLogicalOp", "isExpandedMacro", "isSplittedVarDeclComma",
382
+ "isSplittedVarDeclEq", "isImplicitInt", "linkId", "varId",
383
+ "variableId", "functionId", "valuesId", "valueType",
384
+ "typeScopeId", "astParentId", "astOperand1Id", "file",
385
+ "linenr", "column"]
386
+ return "{}({})".format(
387
+ "Token",
388
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
389
+ )
390
+
391
+ def setId(self, IdMap):
392
+ self.scope = IdMap[self.scopeId]
393
+ self.link = IdMap[self.linkId]
394
+ self.variable = IdMap[self.variableId]
395
+ self.function = IdMap[self.functionId]
396
+ self.values = []
397
+ self.impossible_values = []
398
+ if IdMap[self.valuesId]:
399
+ for v in IdMap[self.valuesId]:
400
+ if v.isImpossible():
401
+ self.impossible_values.append(v)
402
+ else:
403
+ self.values.append(v)
404
+ v.setId(IdMap)
405
+ self.typeScope = IdMap[self.typeScopeId]
406
+ self.astParent = IdMap[self.astParentId]
407
+ self.astOperand1 = IdMap[self.astOperand1Id]
408
+ self.astOperand2 = IdMap[self.astOperand2Id]
409
+ if self.valueType:
410
+ self.valueType.setId(IdMap)
411
+
412
+ def getValue(self, v):
413
+ """
414
+ Get value if it exists
415
+ Returns None if it doesn't exist
416
+ """
417
+
418
+ if not self.values:
419
+ return None
420
+ for value in self.values:
421
+ if value.intvalue == v:
422
+ return value
423
+ return None
424
+
425
+ def getKnownIntValue(self):
426
+ """
427
+ If token has a known int value then return that.
428
+ Otherwise returns None
429
+ """
430
+ if not self.values:
431
+ return None
432
+ for value in self.values:
433
+ if value.valueKind == 'known':
434
+ return value.intvalue
435
+ return None
436
+
437
+ def isUnaryOp(self, op):
438
+ return self.astOperand1 and (self.astOperand2 is None) and self.str == op
439
+
440
+ def isBinaryOp(self):
441
+ return self.astOperand1 and self.astOperand2
442
+
443
+ def forward(self, end=None):
444
+ token = self
445
+ while token and token != end:
446
+ yield token
447
+ token = token.next
448
+
449
+ def backward(self, start=None):
450
+ token = self
451
+ while token and token != start:
452
+ yield token
453
+ token = token.previous
454
+
455
+ def astParents(self):
456
+ token = self
457
+ while token and token.astParent:
458
+ token = token.astParent
459
+ yield token
460
+
461
+ def astTop(self):
462
+ top = None
463
+ for parent in self.astParents():
464
+ top = parent
465
+ return top
466
+
467
+ def tokAt(self, n):
468
+ tl = self.forward()
469
+ if n < 0:
470
+ tl = self.backward()
471
+ n = -n
472
+ for i, t in enumerate(tl):
473
+ if i == n:
474
+ return t
475
+
476
+ def linkAt(self, n):
477
+ token = self.tokAt(n)
478
+ if token:
479
+ return token.link
480
+ return None
481
+
482
+ class Scope:
483
+ """
484
+ Scope. Information about global scope, function scopes, class scopes, inner scopes, etc.
485
+ C++ class: https://cppcheck.sourceforge.io/devinfo/doxyoutput/classScope.html
486
+
487
+ Attributes
488
+ bodyStart The { Token for this scope
489
+ bodyEnd The } Token for this scope
490
+ className Name of this scope.
491
+ For a function scope, this is the function name;
492
+ For a class scope, this is the class name.
493
+ function If this scope belongs at a function call, this attribute
494
+ has the Function information. See the Function class.
495
+ type Type of scope: Global, Function, Class, If, While
496
+ """
497
+
498
+ Id = None
499
+ bodyStartId = None
500
+ bodyStart = None
501
+ bodyEndId = None
502
+ bodyEnd = None
503
+ className = None
504
+ functionId = None
505
+ function = None
506
+ nestedInId = None
507
+ nestedIn = None
508
+ type = None
509
+ isExecutable = None
510
+ varlistId = None
511
+ varlist = None
512
+
513
+ def __init__(self, element):
514
+ self.Id = element.get('id')
515
+ self.className = element.get('className')
516
+ self.functionId = element.get('function')
517
+ self.function = None
518
+ self.bodyStartId = element.get('bodyStart')
519
+ self.bodyStart = None
520
+ self.bodyEndId = element.get('bodyEnd')
521
+ self.bodyEnd = None
522
+ self.nestedInId = element.get('nestedIn')
523
+ self.nestedIn = None
524
+ self.type = element.get('type')
525
+ self.isExecutable = (self.type in ('Function', 'If', 'Else', 'For', 'While', 'Do',
526
+ 'Switch', 'Try', 'Catch', 'Unconditional', 'Lambda'))
527
+ self.varlistId = list()
528
+ self.varlist = list()
529
+
530
+ def __repr__(self):
531
+ attrs = ["Id", "className", "functionId", "bodyStartId", "bodyEndId",
532
+ "nestedInId", "nestedIn", "type", "isExecutable"]
533
+ return "{}({})".format(
534
+ "Scope",
535
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
536
+ )
537
+
538
+ def setId(self, IdMap):
539
+ self.bodyStart = IdMap[self.bodyStartId]
540
+ self.bodyEnd = IdMap[self.bodyEndId]
541
+ self.nestedIn = IdMap[self.nestedInId]
542
+ self.function = IdMap[self.functionId]
543
+ for v in self.varlistId:
544
+ value = IdMap.get(v)
545
+ if value:
546
+ self.varlist.append(value)
547
+
548
+
549
+ class Function:
550
+ """
551
+ Information about a function
552
+ C++ class:
553
+ https://cppcheck.sourceforge.io/devinfo/doxyoutput/classFunction.html
554
+
555
+ Attributes
556
+ argument Argument list
557
+ token Token in function implementation
558
+ tokenDef Token in function definition
559
+ isVirtual Is this function is virtual
560
+ isImplicitlyVirtual Is this function is virtual this in the base classes
561
+ isInlineKeyword Is inline keyword used
562
+ isStatic Is this function static?
563
+ """
564
+
565
+ Id = None
566
+ argument = None
567
+ argumentId = None
568
+ token = None
569
+ tokenId = None
570
+ tokenDef = None
571
+ tokenDefId = None
572
+ name = None
573
+ type = None
574
+ isVirtual = None
575
+ isImplicitlyVirtual = None
576
+ isInlineKeyword = None
577
+ isStatic = None
578
+ nestedIn = None
579
+
580
+ def __init__(self, element, nestedIn):
581
+ self.Id = element.get('id')
582
+ self.tokenId = element.get('token')
583
+ self.tokenDefId = element.get('tokenDef')
584
+ self.name = element.get('name')
585
+ self.type = element.get('type')
586
+ self.isImplicitlyVirtual = element.get('isImplicitlyVirtual', 'false') == 'true'
587
+ self.isVirtual = element.get('isVirtual', 'false') == 'true'
588
+ self.isInlineKeyword = element.get('isInlineKeyword', 'false') == 'true'
589
+ self.isStatic = element.get('isStatic', 'false') == 'true'
590
+ self.nestedIn = nestedIn
591
+
592
+ self.argument = {}
593
+ self.argumentId = {}
594
+
595
+ def __repr__(self):
596
+ attrs = ["Id", "tokenId", "tokenDefId", "name", "type", "isVirtual",
597
+ "isImplicitlyVirtual", "isInlineKeyword", "isStatic", "argumentId"]
598
+ return "{}({})".format(
599
+ "Function",
600
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
601
+ )
602
+
603
+ def setId(self, IdMap):
604
+ for argnr, argid in self.argumentId.items():
605
+ self.argument[argnr] = IdMap[argid]
606
+ self.token = IdMap.get(self.tokenId, None)
607
+ self.tokenDef = IdMap[self.tokenDefId]
608
+
609
+
610
+ class Variable:
611
+ """
612
+ Information about a variable
613
+ C++ class:
614
+ https://cppcheck.sourceforge.io/devinfo/doxyoutput/classVariable.html
615
+
616
+ Attributes:
617
+ nameToken Name token in variable declaration
618
+ typeStartToken Start token of variable declaration
619
+ typeEndToken End token of variable declaration
620
+ access Global/Local/Namespace/Public/Protected/Public/Throw/Argument
621
+ scope Variable scope
622
+ isArgument Is this variable a function argument?
623
+ isArray Is this variable an array?
624
+ isClass Is this variable a class or struct?
625
+ isConst Is this variable a const variable?
626
+ isGlobal Is this variable a global variable?
627
+ isExtern Is this variable an extern variable?
628
+ isLocal Is this variable a local variable?
629
+ isPointer Is this variable a pointer
630
+ isReference Is this variable a reference
631
+ isStatic Is this variable static?
632
+ constness Variable constness (same encoding as ValueType::constness)
633
+ """
634
+
635
+ Id = None
636
+ nameTokenId = None
637
+ nameToken = None
638
+ typeStartTokenId = None
639
+ typeStartToken = None
640
+ typeEndTokenId = None
641
+ typeEndToken = None
642
+ access = None
643
+ scopeId = None
644
+ scope = None
645
+ isArgument = False
646
+ isArray = False
647
+ isClass = False
648
+ isConst = False
649
+ isExtern = False
650
+ isGlobal = False
651
+ isLocal = False
652
+ isPointer = False
653
+ isReference = False
654
+ isStatic = False
655
+ constness = 0
656
+
657
+ def __init__(self, element):
658
+ self.Id = element.get('id')
659
+ self.nameTokenId = element.get('nameToken')
660
+ self.nameToken = None
661
+ self.typeStartTokenId = element.get('typeStartToken')
662
+ self.typeStartToken = None
663
+ self.typeEndTokenId = element.get('typeEndToken')
664
+ self.typeEndToken = None
665
+ self.access = element.get('access')
666
+ self.scopeId = element.get('scope')
667
+ self.scope = None
668
+ self.isArgument = (self.access and self.access == 'Argument')
669
+ self.isArray = element.get('isArray') == 'true'
670
+ self.isClass = element.get('isClass') == 'true'
671
+ self.isConst = element.get('isConst') == 'true'
672
+ self.isGlobal = (self.access and self.access == 'Global')
673
+ self.isExtern = element.get('isExtern') == 'true'
674
+ self.isLocal = (self.access and self.access == 'Local')
675
+ self.isPointer = element.get('isPointer') == 'true'
676
+ self.isReference = element.get('isReference') == 'true'
677
+ self.isStatic = element.get('isStatic') == 'true'
678
+ self.constness = int(element.get('constness',0))
679
+
680
+ def __repr__(self):
681
+ attrs = ["Id", "nameTokenId", "typeStartTokenId", "typeEndTokenId",
682
+ "access", "scopeId", "isArgument", "isArray", "isClass",
683
+ "isConst", "isGlobal", "isExtern", "isLocal", "isPointer",
684
+ "isReference", "isStatic", "constness", ]
685
+ return "{}({})".format(
686
+ "Variable",
687
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
688
+ )
689
+
690
+ def setId(self, IdMap):
691
+ self.nameToken = IdMap[self.nameTokenId]
692
+ self.typeStartToken = IdMap[self.typeStartTokenId]
693
+ self.typeEndToken = IdMap[self.typeEndTokenId]
694
+ self.scope = IdMap[self.scopeId]
695
+
696
+
697
+ class TypedefInfo:
698
+ """
699
+ TypedefInfo class -- information about typedefs
700
+ """
701
+ name = None
702
+ used = None
703
+ file = None
704
+ linenr = None
705
+ column = None
706
+
707
+ def __init__(self, element):
708
+ self.name = element.get('name')
709
+ _load_location(self, element)
710
+ self.used = (element.get('used') == '1')
711
+
712
+ class Value:
713
+ """
714
+ Value class
715
+
716
+ Attributes:
717
+ intvalue integer value
718
+ tokvalue token value
719
+ floatvalue float value
720
+ containerSize container size
721
+ condition condition where this Value comes from
722
+ valueKind 'known' or 'possible'
723
+ inconclusive Is value inconclusive?
724
+ """
725
+
726
+ intvalue = None
727
+ tokvalue = None
728
+ floatvalue = None
729
+ containerSize = None
730
+ condition = None
731
+ valueKind = None
732
+ inconclusive = False
733
+
734
+ def isKnown(self):
735
+ return self.valueKind and self.valueKind == 'known'
736
+
737
+ def isPossible(self):
738
+ return self.valueKind and self.valueKind == 'possible'
739
+
740
+ def isImpossible(self):
741
+ return self.valueKind and self.valueKind == 'impossible'
742
+
743
+ def __init__(self, element):
744
+ self.intvalue = element.get('intvalue')
745
+ if self.intvalue:
746
+ self.intvalue = int(self.intvalue)
747
+ self._tokvalueId = element.get('tokvalue')
748
+ self.floatvalue = element.get('floatvalue')
749
+ self.containerSize = element.get('container-size')
750
+ self.iteratorStart = element.get('iterator-start')
751
+ self.iteratorEnd = element.get('iterator-end')
752
+ self._lifetimeId = element.get('lifetime')
753
+ self.lifetimeScope = element.get('lifetime-scope')
754
+ self.lifetimeKind = element.get('lifetime-kind')
755
+ self._symbolicId = element.get('symbolic')
756
+ self.symbolicDelta = element.get('symbolic-delta')
757
+ self.condition = element.get('condition-line')
758
+ self.bound = element.get('bound')
759
+ self.path = element.get('path')
760
+ if self.condition:
761
+ self.condition = int(self.condition)
762
+ if element.get('known'):
763
+ self.valueKind = 'known'
764
+ elif element.get('possible'):
765
+ self.valueKind = 'possible'
766
+ elif element.get('impossible'):
767
+ self.valueKind = 'impossible'
768
+ if element.get('inconclusive'):
769
+ self.inconclusive = True
770
+
771
+ def setId(self, IdMap):
772
+ self.tokvalue = IdMap.get(self._tokvalueId)
773
+ self.lifetime = IdMap.get(self._lifetimeId)
774
+ self.symbolic = IdMap.get(self._symbolicId)
775
+
776
+ def __repr__(self):
777
+ attrs = ["intvalue", "tokvalue", "floatvalue", "containerSize",
778
+ "condition", "valueKind", "inconclusive"]
779
+ return "{}({})".format(
780
+ "Value",
781
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
782
+ )
783
+
784
+
785
+ class ValueFlow:
786
+ """
787
+ ValueFlow::Value class
788
+ Each possible value has a ValueFlow::Value item.
789
+ Each ValueFlow::Value either has a intvalue or tokvalue
790
+ C++ class:
791
+ https://cppcheck.sourceforge.io/devinfo/doxyoutput/classValueFlow_1_1Value.html
792
+
793
+ Attributes:
794
+ values Possible values
795
+ """
796
+
797
+ Id = None
798
+ values = None
799
+
800
+ def __init__(self, element):
801
+ self.Id = element.get('id')
802
+ self.values = []
803
+
804
+ def __repr__(self):
805
+ attrs = ["Id", "values"]
806
+ return "{}({})".format(
807
+ "ValueFlow",
808
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
809
+ )
810
+
811
+
812
+ class Suppression:
813
+ """
814
+ Suppression class
815
+ This class contains a suppression entry to suppress a warning.
816
+
817
+ Attributes
818
+ errorId The id string of the error to suppress, can be a wildcard
819
+ fileName The name of the file to suppress warnings for, can include wildcards
820
+ lineNumber The number of the line to suppress warnings from, can be 0 to represent any line
821
+ symbolName The name of the symbol to match warnings for, can include wildcards
822
+ """
823
+
824
+ errorId = None
825
+ fileName = None
826
+ lineNumber = None
827
+ symbolName = None
828
+
829
+ def __init__(self, element):
830
+ self.errorId = element.get('errorId')
831
+ self.fileName = element.get('fileName')
832
+ self.lineNumber = element.get('lineNumber')
833
+ self.symbolName = element.get('symbolName')
834
+
835
+ def __repr__(self):
836
+ attrs = ['errorId' , "fileName", "lineNumber", "symbolName"]
837
+ return "{}({})".format(
838
+ "Suppression",
839
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
840
+ )
841
+
842
+ def isMatch(self, file, line, message, errorId):
843
+ if ((self.fileName is None or fnmatch(file, self.fileName))
844
+ and (self.lineNumber is None or int(line) == int(self.lineNumber))
845
+ and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*'))
846
+ and fnmatch(errorId, self.errorId)):
847
+ return True
848
+ return False
849
+
850
+
851
+ class Configuration:
852
+ """
853
+ Configuration class
854
+ This class contains the directives, tokens, scopes, functions,
855
+ variables, value flows, and suppressions for one configuration.
856
+
857
+ Attributes:
858
+ name Name of the configuration, "" for default
859
+ directives List of Directive items
860
+ macro_usage List of used macros
861
+ preprocessor_if_conditions List of preprocessor if conditions that was evaluated during preprocessing
862
+ tokenlist List of Token items
863
+ scopes List of Scope items
864
+ functions List of Function items
865
+ variables List of Variable items
866
+ valueflow List of ValueFlow values
867
+ standards List of Standards values
868
+ """
869
+
870
+ name = ''
871
+ directives = []
872
+ macro_usage = []
873
+ preprocessor_if_conditions = []
874
+ tokenlist = []
875
+ scopes = []
876
+ functions = []
877
+ variables = []
878
+ typedefInfo = []
879
+ valueflow = []
880
+ standards = None
881
+ clang_warnings = []
882
+
883
+ def __init__(self, name):
884
+ self.name = name
885
+ self.directives = []
886
+ self.macro_usage = []
887
+ self.preprocessor_if_conditions = []
888
+ self.tokenlist = []
889
+ self.scopes = []
890
+ self.functions = []
891
+ self.variables = []
892
+ self.typedefInfo = []
893
+ self.valueflow = []
894
+ self.standards = Standards()
895
+ self.clang_warnings = []
896
+
897
+ def set_tokens_links(self):
898
+ """Set next/previous links between tokens."""
899
+ prev = None
900
+ for token in self.tokenlist:
901
+ token.previous = prev
902
+ if prev:
903
+ prev.next = token
904
+ prev = token
905
+
906
+ def set_id_map(self, arguments):
907
+ IdMap = {None: None, '0': None, '00000000': None, '0000000000000000': None, '0x0': None}
908
+ for token in self.tokenlist:
909
+ IdMap[token.Id] = token
910
+ for scope in self.scopes:
911
+ IdMap[scope.Id] = scope
912
+ for function in self.functions:
913
+ IdMap[function.Id] = function
914
+ for variable in self.variables:
915
+ IdMap[variable.Id] = variable
916
+ for variable in arguments:
917
+ IdMap[variable.Id] = variable
918
+ for values in self.valueflow:
919
+ IdMap[values.Id] = values.values
920
+ for token in self.tokenlist:
921
+ token.setId(IdMap)
922
+ for scope in self.scopes:
923
+ scope.setId(IdMap)
924
+ for function in self.functions:
925
+ function.setId(IdMap)
926
+ for variable in self.variables:
927
+ variable.setId(IdMap)
928
+ for variable in arguments:
929
+ variable.setId(IdMap)
930
+
931
+ def setIdMap(self, functions_arguments):
932
+ """Set relationships between objects stored in this configuration.
933
+ :param functions_arguments: List of Variable objects which are function arguments
934
+ """
935
+ self.set_tokens_links()
936
+ self.set_id_map(functions_arguments)
937
+
938
+
939
+ class Platform:
940
+ """
941
+ Platform class
942
+ This class contains type sizes
943
+
944
+ Attributes:
945
+ name Name of the platform
946
+ char_bit CHAR_BIT value
947
+ short_bit SHORT_BIT value
948
+ int_bit INT_BIT value
949
+ long_bit LONG_BIT value
950
+ long_long_bit LONG_LONG_BIT value
951
+ pointer_bit POINTER_BIT value
952
+ """
953
+
954
+ name = ''
955
+ char_bit = 0
956
+ short_bit = 0
957
+ int_bit = 0
958
+ long_bit = 0
959
+ long_long_bit = 0
960
+ pointer_bit = 0
961
+
962
+ def __init__(self, platformnode):
963
+ self.name = platformnode.get('name')
964
+ self.char_bit = int(platformnode.get('char_bit'))
965
+ self.short_bit = int(platformnode.get('short_bit'))
966
+ self.int_bit = int(platformnode.get('int_bit'))
967
+ self.long_bit = int(platformnode.get('long_bit'))
968
+ self.long_long_bit = int(platformnode.get('long_long_bit'))
969
+ self.pointer_bit = int(platformnode.get('pointer_bit'))
970
+
971
+ def __repr__(self):
972
+ attrs = ["name", "char_bit", "short_bit", "int_bit",
973
+ "long_bit", "long_long_bit", "pointer_bit"]
974
+ return "{}({})".format(
975
+ "Platform",
976
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
977
+ )
978
+
979
+
980
+ class Standards:
981
+ """
982
+ Standards class
983
+ This class contains versions of standards that were used for the cppcheck
984
+
985
+ Attributes:
986
+ c C Standard used
987
+ cpp C++ Standard used
988
+ posix If Posix was used
989
+ """
990
+
991
+ c = ""
992
+ cpp = ""
993
+ posix = False
994
+
995
+ def set_c(self, node):
996
+ self.c = node.get("version")
997
+
998
+ def set_cpp(self, node):
999
+ self.cpp = node.get("version")
1000
+
1001
+ def set_posix(self, node):
1002
+ self.posix = node.get("posix") is not None
1003
+
1004
+ def __repr__(self):
1005
+ attrs = ["c", "cpp", "posix"]
1006
+ return "{}({})".format(
1007
+ "Standards",
1008
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
1009
+ )
1010
+
1011
+
1012
+ class CppcheckData:
1013
+ """
1014
+ Class that makes cppcheck dump data available
1015
+ Contains a list of Configuration instances
1016
+
1017
+ Attributes:
1018
+ filename Path to Cppcheck dump file
1019
+ rawTokens List of rawToken elements
1020
+ suppressions List of Suppressions
1021
+ files Source files for elements occurred in this configuration
1022
+
1023
+ To iterate through all configurations use such code:
1024
+ @code
1025
+ data = cppcheckdata.parsedump(...)
1026
+ for cfg in data.configurations:
1027
+ print('cfg: ' + cfg.name)
1028
+ @endcode
1029
+
1030
+ To iterate through all tokens in each configuration use such code:
1031
+ @code
1032
+ data = cppcheckdata.parsedump(...)
1033
+ for cfg in data.configurations:
1034
+ print('cfg: ' + cfg.name)
1035
+ code = ''
1036
+ for token in cfg.tokenlist:
1037
+ code = code + token.str + ' '
1038
+ print(' ' + code)
1039
+ @endcode
1040
+
1041
+ To iterate through all scopes (functions, types, etc) use such code:
1042
+ @code
1043
+ data = cppcheckdata.parsedump(...)
1044
+ for cfg in data.configurations:
1045
+ print('cfg: ' + cfg.name)
1046
+ for scope in cfg.scopes:
1047
+ print(' type:' + scope.type + ' name:' + scope.className)
1048
+ @endcode
1049
+ """
1050
+
1051
+ def __init__(self, filename):
1052
+ """
1053
+ :param filename: Path to Cppcheck dump file
1054
+ """
1055
+ self.filename = filename
1056
+ self.rawTokens = []
1057
+ self.platform = None
1058
+ self.suppressions = []
1059
+ self.files = []
1060
+
1061
+ platform_done = False
1062
+ rawtokens_done = False
1063
+ suppressions_done = False
1064
+
1065
+ # Parse general configuration options from <dumps> node
1066
+ # We intentionally don't clean node resources here because we
1067
+ # want to serialize in memory only small part of the XML tree.
1068
+ for event, node in ElementTree.iterparse(self.filename, events=('start', 'end')):
1069
+ if platform_done and rawtokens_done and suppressions_done:
1070
+ break
1071
+ if node.tag == 'platform' and event == 'start':
1072
+ self.platform = Platform(node)
1073
+ platform_done = True
1074
+ elif node.tag == 'rawtokens' and event == 'end':
1075
+ for rawtokens_node in node:
1076
+ if rawtokens_node.tag == 'file':
1077
+ self.files.append(rawtokens_node.get('name'))
1078
+ elif rawtokens_node.tag == 'tok':
1079
+ tok = Token(rawtokens_node)
1080
+ tok.file = self.files[int(rawtokens_node.get('fileIndex'))]
1081
+ self.rawTokens.append(tok)
1082
+ rawtokens_done = True
1083
+ elif node.tag == 'suppressions' and event == 'end':
1084
+ for suppressions_node in node:
1085
+ self.suppressions.append(Suppression(suppressions_node))
1086
+ suppressions_done = True
1087
+
1088
+ global current_dumpfile_suppressions
1089
+ current_dumpfile_suppressions = self.suppressions
1090
+
1091
+ # Set links between rawTokens.
1092
+ for i in range(len(self.rawTokens)-1):
1093
+ self.rawTokens[i+1].previous = self.rawTokens[i]
1094
+ self.rawTokens[i].next = self.rawTokens[i+1]
1095
+
1096
+ @property
1097
+ def configurations(self):
1098
+ """
1099
+ Return the list of all available Configuration objects.
1100
+ """
1101
+ return list(self.iterconfigurations())
1102
+
1103
+ def iterconfigurations(self):
1104
+ """
1105
+ Create and return iterator for the available Configuration objects.
1106
+ The iterator loops over all Configurations in the dump file tree, in document order.
1107
+ """
1108
+ cfg = None
1109
+ cfg_arguments = [] # function arguments for Configuration node initialization
1110
+ cfg_function = None
1111
+ cfg_valueflow = None
1112
+
1113
+ # Iterating <varlist> in a <scope>.
1114
+ iter_scope_varlist = False
1115
+
1116
+ # Iterating <typedef-info>
1117
+ iter_typedef_info = False
1118
+
1119
+ # Use iterable objects to traverse XML tree for dump files incrementally.
1120
+ # Iterative approach is required to avoid large memory consumption.
1121
+ # Calling .clear() is necessary to let the element be garbage collected.
1122
+ for event, node in ElementTree.iterparse(self.filename, events=('start', 'end')):
1123
+ # Serialize new configuration node
1124
+ if node.tag == 'dump':
1125
+ if event == 'start':
1126
+ cfg = Configuration(node.get('cfg'))
1127
+ continue
1128
+ elif event == 'end':
1129
+ cfg.setIdMap(cfg_arguments)
1130
+ yield cfg
1131
+ cfg = None
1132
+ cfg_arguments = []
1133
+
1134
+ elif node.tag == 'clang-warning' and event == 'start':
1135
+ cfg.clang_warnings.append({'file': node.get('file'),
1136
+ 'line': int(node.get('line')),
1137
+ 'column': int(node.get('column')),
1138
+ 'message': node.get('message')})
1139
+
1140
+ # Parse standards
1141
+ elif node.tag == "standards" and event == 'start':
1142
+ continue
1143
+ elif node.tag == 'c' and event == 'start':
1144
+ cfg.standards.set_c(node)
1145
+ elif node.tag == 'cpp' and event == 'start':
1146
+ cfg.standards.set_cpp(node)
1147
+ elif node.tag == 'posix' and event == 'start':
1148
+ cfg.standards.set_posix(node)
1149
+
1150
+ # Parse directives list
1151
+ elif node.tag == 'directive' and event == 'start':
1152
+ cfg.directives.append(Directive(node))
1153
+
1154
+ # Parse macro usage
1155
+ elif node.tag == 'macro' and event == 'start':
1156
+ cfg.macro_usage.append(MacroUsage(node))
1157
+
1158
+ # Preprocessor #if/#elif condition
1159
+ elif node.tag == "if-cond" and event == 'start':
1160
+ cfg.preprocessor_if_conditions.append(PreprocessorIfCondition(node))
1161
+
1162
+ # Parse tokens
1163
+ elif node.tag == 'tokenlist' and event == 'start':
1164
+ continue
1165
+ elif node.tag == 'token' and event == 'start':
1166
+ cfg.tokenlist.append(Token(node))
1167
+
1168
+ # Parse scopes
1169
+ elif node.tag == 'scopes' and event == 'start':
1170
+ continue
1171
+ elif node.tag == 'scope' and event == 'start':
1172
+ cfg.scopes.append(Scope(node))
1173
+ elif node.tag == 'varlist':
1174
+ if event == 'start':
1175
+ iter_scope_varlist = True
1176
+ elif event == 'end':
1177
+ iter_scope_varlist = False
1178
+
1179
+ # Parse functions
1180
+ elif node.tag == 'functionList' and event == 'start':
1181
+ continue
1182
+ elif node.tag == 'function':
1183
+ if event == 'start':
1184
+ cfg_function = Function(node, cfg.scopes[-1])
1185
+ continue
1186
+ elif event == 'end':
1187
+ cfg.functions.append(cfg_function)
1188
+ cfg_function = None
1189
+
1190
+ # Parse function arguments
1191
+ elif node.tag == 'arg' and event == 'start':
1192
+ arg_nr = int(node.get('nr'))
1193
+ arg_variable_id = node.get('variable')
1194
+ cfg_function.argumentId[arg_nr] = arg_variable_id
1195
+
1196
+ # Parse variables
1197
+ elif node.tag == 'var' and event == 'start':
1198
+ if iter_scope_varlist:
1199
+ cfg.scopes[-1].varlistId.append(node.get('id'))
1200
+ else:
1201
+ var = Variable(node)
1202
+ if var.nameTokenId:
1203
+ cfg.variables.append(var)
1204
+ else:
1205
+ cfg_arguments.append(var)
1206
+
1207
+ # Parse typedef info
1208
+ elif node.tag == 'typedef-info':
1209
+ iter_typedef_info = (event == 'start')
1210
+ elif iter_typedef_info and node.tag == 'info' and event == 'start':
1211
+ cfg.typedefInfo.append(TypedefInfo(node))
1212
+
1213
+ # Parse valueflows (list of values)
1214
+ elif node.tag == 'valueflow' and event == 'start':
1215
+ continue
1216
+ elif node.tag == 'values':
1217
+ if event == 'start':
1218
+ cfg_valueflow = ValueFlow(node)
1219
+ continue
1220
+ elif event == 'end':
1221
+ cfg.valueflow.append(cfg_valueflow)
1222
+ cfg_valueflow = None
1223
+
1224
+ # Parse values
1225
+ elif node.tag == 'value' and event == 'start':
1226
+ cfg_valueflow.values.append(Value(node))
1227
+
1228
+ # Remove links to the sibling nodes
1229
+ node.clear()
1230
+
1231
+ def __repr__(self):
1232
+ attrs = ["configurations", "platform"]
1233
+ return "{}({})".format(
1234
+ "CppcheckData",
1235
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
1236
+ )
1237
+
1238
+
1239
+ # Get function arguments
1240
+ def getArgumentsRecursive(tok, arguments):
1241
+ if tok is None:
1242
+ return
1243
+ if tok.str == ',':
1244
+ getArgumentsRecursive(tok.astOperand1, arguments)
1245
+ getArgumentsRecursive(tok.astOperand2, arguments)
1246
+ else:
1247
+ arguments.append(tok)
1248
+
1249
+
1250
+ def getArguments(ftok):
1251
+ if (not ftok.isName) or (ftok.next is None) or ftok.next.str != '(':
1252
+ return None
1253
+ args = []
1254
+ getArgumentsRecursive(ftok.next.astOperand2, args)
1255
+ return args
1256
+
1257
+
1258
+ def parsedump(filename):
1259
+ """
1260
+ parse a cppcheck dump file
1261
+ """
1262
+ return CppcheckData(filename)
1263
+
1264
+
1265
+ def astIsFloat(token):
1266
+ """
1267
+ Check if type of ast node is float/double
1268
+ """
1269
+
1270
+ if not token:
1271
+ return False
1272
+ if token.str == '.':
1273
+ return astIsFloat(token.astOperand2)
1274
+ if token.str in '+-*/%':
1275
+ return astIsFloat(token.astOperand1) or astIsFloat(token.astOperand2)
1276
+ if not token.variable:
1277
+ # float literal?
1278
+ if token.str[0].isdigit():
1279
+ for c in token.str:
1280
+ if c == 'f' or c == '.' or c == 'E':
1281
+ return True
1282
+ return False
1283
+ typeToken = token.variable.typeStartToken
1284
+ endToken = token.variable.typeEndToken
1285
+ while typeToken != endToken:
1286
+ if typeToken.str == 'float' or typeToken.str == 'double':
1287
+ return True
1288
+ typeToken = typeToken.next
1289
+ if typeToken.str == 'float' or typeToken.str == 'double':
1290
+ return True
1291
+ return False
1292
+
1293
+
1294
+ class CppCheckFormatter(argparse.HelpFormatter):
1295
+ """
1296
+ Properly formats multiline argument helps
1297
+ """
1298
+ def _split_lines(self, text, width):
1299
+ # this is the RawTextHelpFormatter._split_lines
1300
+ if text.startswith('R|'):
1301
+ return text[2:].splitlines()
1302
+ return argparse.HelpFormatter._split_lines(self, text, width)
1303
+
1304
+
1305
+ def ArgumentParser():
1306
+ """
1307
+ Returns an argparse argument parser with an already-added
1308
+ argument definition for -t/--template
1309
+ """
1310
+ parser = argparse.ArgumentParser(formatter_class=CppCheckFormatter)
1311
+ parser.add_argument('-t', '--template', metavar='<text>',
1312
+ default='{callstack}: ({severity}) {message}',
1313
+ help="R|Format the error messages. E.g.\n"
1314
+ "'{file}:{line},{severity},{id},{message}' or\n"
1315
+ "'{file}({line}):({severity}) {message}' or\n"
1316
+ "'{callstack} {message}'\n"
1317
+ "Pre-defined templates: gcc, vs, edit")
1318
+ parser.add_argument("dumpfile", nargs='*',
1319
+ help="Path of dump files from cppcheck.")
1320
+ parser.add_argument("--cli",
1321
+ help="Addon is executed from Cppcheck",
1322
+ action="store_true")
1323
+ parser.add_argument("--file-list", metavar='<text>',
1324
+ default=None,
1325
+ help="file list in a text file")
1326
+ parser.add_argument("-q", "--quiet",
1327
+ help='do not print "Checking ..." lines',
1328
+ action="store_true")
1329
+ return parser
1330
+
1331
+
1332
+ def get_files(args):
1333
+ """Return dump_files, ctu_info_files"""
1334
+ all_files = args.dumpfile
1335
+ if args.file_list:
1336
+ with open(args.file_list, 'rt') as f:
1337
+ for line in f.readlines():
1338
+ all_files.append(line.rstrip())
1339
+ dump_files = []
1340
+ ctu_info_files = []
1341
+ for f in all_files:
1342
+ if f.endswith('.ctu-info'):
1343
+ ctu_info_files.append(f)
1344
+ else:
1345
+ dump_files.append(f)
1346
+ return dump_files, ctu_info_files
1347
+
1348
+
1349
+ def simpleMatch(token, pattern):
1350
+ for p in pattern.split(' '):
1351
+ if not token or token.str != p:
1352
+ return False
1353
+ token = token.next
1354
+ return True
1355
+
1356
+ patterns = {
1357
+ '%any%': lambda tok: tok,
1358
+ '%assign%': lambda tok: tok if tok.isAssignmentOp else None,
1359
+ '%comp%': lambda tok: tok if tok.isComparisonOp else None,
1360
+ '%name%': lambda tok: tok if tok.isName else None,
1361
+ '%op%': lambda tok: tok if tok.isOp else None,
1362
+ '%or%': lambda tok: tok if tok.str == '|' else None,
1363
+ '%oror%': lambda tok: tok if tok.str == '||' else None,
1364
+ '%var%': lambda tok: tok if tok.variable else None,
1365
+ '(*)': lambda tok: tok.link if tok.str == '(' else None,
1366
+ '[*]': lambda tok: tok.link if tok.str == '[' else None,
1367
+ '{*}': lambda tok: tok.link if tok.str == '{' else None,
1368
+ '<*>': lambda tok: tok.link if tok.str == '<' and tok.link else None,
1369
+ }
1370
+
1371
+ def match_atom(token, p):
1372
+ if not token:
1373
+ return None
1374
+ if not p:
1375
+ return None
1376
+ if token.str == p:
1377
+ return token
1378
+ if p in ['!', '|', '||', '%', '!=', '*']:
1379
+ return None
1380
+ if p in patterns:
1381
+ return patterns[p](token)
1382
+ if '|' in p:
1383
+ for x in p.split('|'):
1384
+ t = match_atom(token, x)
1385
+ if t:
1386
+ return t
1387
+ elif p.startswith('!!'):
1388
+ t = match_atom(token, p[2:])
1389
+ if not t:
1390
+ return token
1391
+ elif p.startswith('**'):
1392
+ a = p[2:]
1393
+ t = token
1394
+ while t:
1395
+ if match_atom(t, a):
1396
+ return t
1397
+ if t.link and t.str in ['(', '[', '<', '{']:
1398
+ t = t.link
1399
+ t = t.next
1400
+ return None
1401
+
1402
+ class MatchResult:
1403
+ def __init__(self, matches, bindings=None, keys=None):
1404
+ self.__dict__.update(bindings or {})
1405
+ self._matches = matches
1406
+ self._keys = keys or []
1407
+
1408
+ def __bool__(self):
1409
+ return self._matches
1410
+
1411
+ def __nonzero__(self):
1412
+ return self._matches
1413
+
1414
+ def __getattr__(self, k):
1415
+ if k in self._keys:
1416
+ return None
1417
+ else:
1418
+ raise AttributeError
1419
+
1420
+ def bind_split(s):
1421
+ if '@' in s:
1422
+ p = s.partition('@')
1423
+ return (p[0], p[2])
1424
+ return (s, None)
1425
+
1426
+ def match(token, pattern):
1427
+ if not pattern:
1428
+ return MatchResult(False)
1429
+ end = None
1430
+ bindings = {}
1431
+ words = [bind_split(word) for word in pattern.split()]
1432
+ for p, b in words:
1433
+ t = match_atom(token, p)
1434
+ if b:
1435
+ bindings[b] = token
1436
+ if not t:
1437
+ return MatchResult(False, keys=[xx for pp, xx in words]+['end'])
1438
+ end = t
1439
+ token = t.next
1440
+ bindings['end'] = end
1441
+ return MatchResult(True, bindings=bindings)
1442
+
1443
+ def get_function_call_name_args(token):
1444
+ """Get function name and arguments for function call
1445
+ name, args = get_function_call_name_args(tok)
1446
+ """
1447
+ if token is None:
1448
+ return None, None
1449
+ if not token.isName or not token.scope.isExecutable:
1450
+ return None, None
1451
+ if not simpleMatch(token.next, '('):
1452
+ return None, None
1453
+ if token.function:
1454
+ nametok = token.function.token
1455
+ if nametok is None:
1456
+ nametok = token.function.tokenDef
1457
+ if token in (token.function.token, token.function.tokenDef):
1458
+ return None, None
1459
+ name = nametok.str
1460
+ while nametok.previous and nametok.previous.previous and nametok.previous.str == '::' and nametok.previous.previous.isName:
1461
+ name = nametok.previous.previous.str + '::' + name
1462
+ nametok = nametok.previous.previous
1463
+ scope = token.function.nestedIn
1464
+ while scope:
1465
+ if scope.className:
1466
+ name = scope.className + '::' + name
1467
+ scope = scope.nestedIn
1468
+ else:
1469
+ nametok = token
1470
+ name = nametok.str
1471
+ while nametok.previous and nametok.previous.previous and nametok.previous.str == '::' and nametok.previous.previous.isName:
1472
+ name = nametok.previous.previous.str + '::' + name
1473
+ nametok = nametok.previous.previous
1474
+ return name, getArguments(token)
1475
+
1476
+ def is_suppressed(location, message, errorId):
1477
+ for suppression in current_dumpfile_suppressions:
1478
+ if suppression.isMatch(location.file, location.linenr, message, errorId):
1479
+ return True
1480
+ return False
1481
+
1482
+ def reportError(location, severity, message, addon, errorId, extra=''):
1483
+ if '--cli' in sys.argv:
1484
+ msg = { 'file': location.file,
1485
+ 'linenr': location.linenr,
1486
+ 'column': location.column,
1487
+ 'severity': severity,
1488
+ 'message': message,
1489
+ 'addon': addon,
1490
+ 'errorId': errorId,
1491
+ 'extra': extra}
1492
+ sys.stdout.write(json.dumps(msg) + '\n')
1493
+ else:
1494
+ if is_suppressed(location, message, '%s-%s' % (addon, errorId)):
1495
+ return
1496
+ loc = '[%s:%i]' % (location.file, location.linenr)
1497
+ if len(extra) > 0:
1498
+ message += ' (' + extra + ')'
1499
+ sys.stderr.write('%s (%s) %s [%s-%s]\n' % (loc, severity, message, addon, errorId))
1500
+ global EXIT_CODE
1501
+ EXIT_CODE = 1
1502
+
1503
+ def reportSummary(dumpfile, summary_type, summary_data):
1504
+ # dumpfile ends with ".dump"
1505
+ ctu_info_file = dumpfile[:-4] + "ctu-info"
1506
+ with open(ctu_info_file, 'at') as f:
1507
+ msg = {'summary': summary_type, 'data': summary_data}
1508
+ f.write(json.dumps(msg) + '\n')
1509
+
1510
+
1511
+ def get_path_premium_addon():
1512
+ p = pathlib.Path(sys.argv[0]).parent.parent
1513
+
1514
+ for ext in ('.exe', ''):
1515
+ p1 = os.path.join(p, 'premiumaddon' + ext)
1516
+ p2 = os.path.join(p, 'cppcheck' + ext)
1517
+ if os.path.isfile(p1) and os.path.isfile(p2):
1518
+ return p1
1519
+ return None
1520
+
1521
+
1522
+ def cmd_output(cmd):
1523
+ with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
1524
+ comm = p.communicate()
1525
+ out = comm[0]
1526
+ if p.returncode == 1 and len(comm[1]) > 2:
1527
+ out = comm[1]
1528
+ return out.decode(encoding='utf-8', errors='ignore')
1529
+