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