cppcheck-py 2.15.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.15.0.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 +1715 -0
  6. cppcheck/data/addons/findcasts.py +32 -0
  7. cppcheck/data/addons/misc.py +163 -0
  8. cppcheck/data/addons/misra.py +4998 -0
  9. cppcheck/data/addons/misra_9.py +561 -0
  10. cppcheck/data/addons/naming.py +91 -0
  11. cppcheck/data/addons/namingng.py +420 -0
  12. cppcheck/data/addons/runaddon.py +12 -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 +1698 -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 +5457 -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 +1572 -0
  56. cppcheck/data/cfg/std.cfg +9139 -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 +992 -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.15.0.dist-info/METADATA +76 -0
  83. cppcheck_py-2.15.0.dist-info/RECORD +86 -0
  84. cppcheck_py-2.15.0.dist-info/WHEEL +5 -0
  85. cppcheck_py-2.15.0.dist-info/entry_points.txt +4 -0
  86. cppcheck_py-2.15.0.dist-info/licenses/LICENSE.md +191 -0
@@ -0,0 +1,1715 @@
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
+
536
+ def linkAt(self, n):
537
+ token = self.tokAt(n)
538
+ if token:
539
+ return token.link
540
+ return None
541
+
542
+ class Scope:
543
+ """
544
+ Scope. Information about global scope, function scopes, class scopes, inner scopes, etc.
545
+ C++ class: https://cppcheck.sourceforge.io/devinfo/doxyoutput/classScope.html
546
+
547
+ Attributes
548
+ bodyStart The { Token for this scope
549
+ bodyEnd The } Token for this scope
550
+ className Name of this scope.
551
+ For a function scope, this is the function name;
552
+ For a class scope, this is the class name.
553
+ function If this scope belongs at a function call, this attribute
554
+ has the Function information. See the Function class.
555
+ functions if this is a Class type, it may have functions defined
556
+ nestedIn
557
+ type Type of scope: Function, If/Else/For/While/Switch/Global/Enum/Struct/Namespace/Class/Constructor/Destructor
558
+ isExecutable True when the type is: Function/If/Else/For/While/Do/Switch/Try/Catch/Unconditional/Lambda
559
+ definedType
560
+ """
561
+ #symboldatabase.cpp/SymbolDatabase::printXml
562
+
563
+ Id = None
564
+ bodyStartId = None
565
+ bodyStart = None
566
+ bodyEndId = None
567
+ bodyEnd = None
568
+ className = None
569
+ functionId = None
570
+ function = None
571
+ nestedInId = None
572
+ nestedIn = None
573
+ nestedList = None
574
+ type = None
575
+ isExecutable = None
576
+ varlistId = None
577
+ varlist = None
578
+
579
+ def __init__(self, element):
580
+ self.Id = element.get('id')
581
+ self.className = element.get('className')
582
+ self.functionId = element.get('function')
583
+ self.function = None
584
+ self.functions = []
585
+ self.bodyStartId = element.get('bodyStart')
586
+ self.bodyStart = None
587
+ self.bodyEndId = element.get('bodyEnd')
588
+ self.bodyEnd = None
589
+ self.nestedInId = element.get('nestedIn')
590
+ self.nestedIn = None
591
+ self.nestedList = list()
592
+ self.type = element.get('type')
593
+ self.definedType = element.get('definedType')
594
+ self.isExecutable = (self.type in ('Function', 'If', 'Else', 'For', 'While', 'Do',
595
+ 'Switch', 'Try', 'Catch', 'Unconditional', 'Lambda'))
596
+
597
+ self.varlistId = list()
598
+ self.varlist = list()
599
+
600
+ def __repr__(self):
601
+ attrs = ["Id", "className", "functionId", "bodyStartId", "bodyEndId",
602
+ "nestedInId", "nestedIn", "type", "definedType", "isExecutable", "functions"]
603
+ return "{}({})".format(
604
+ "Scope",
605
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
606
+ )
607
+
608
+ def setId(self, IdMap):
609
+ self.bodyStart = IdMap[self.bodyStartId]
610
+ self.bodyEnd = IdMap[self.bodyEndId]
611
+ self.nestedIn = IdMap[self.nestedInId]
612
+ if self.nestedIn:
613
+ self.nestedIn.nestedList.append(self)
614
+ self.function = IdMap[self.functionId]
615
+ for v in self.varlistId:
616
+ value = IdMap.get(v)
617
+ if value:
618
+ self.varlist.append(value)
619
+
620
+
621
+ class Function:
622
+ """
623
+ Information about a function
624
+ C++ class:
625
+ https://cppcheck.sourceforge.io/devinfo/doxyoutput/classFunction.html
626
+
627
+ Attributes
628
+ argument Argument list (dict of argument number and variable)
629
+ token Token in function implementation
630
+ tokenDef Token in function definition
631
+ name
632
+ type Constructor/CopyConstructor/MoveConstructor/OperatorEqual/Destructor/Function/Lambda/Unknown
633
+ hasVirtualSpecifier Is this function is virtual
634
+ isImplicitlyVirtual Is this function is virtual this in the base classes
635
+ access Public/Protected/Private
636
+ isInlineKeyword Is inline keyword used
637
+ isStatic Is this function static
638
+ isAttributeNoreturn
639
+ overriddenFunction
640
+ """
641
+ #symboldatabase.cpp/SymbolDatabase::printXml
642
+
643
+ Id = None
644
+ argument = None
645
+ argumentId = None
646
+ token = None
647
+ tokenId = None
648
+ tokenDef = None
649
+ tokenDefId = None
650
+ name = None
651
+ type = None
652
+ access = None
653
+ isImplicitlyVirtual = None
654
+ hasVirtualSpecifier = None
655
+ isInlineKeyword = None
656
+ isStatic = None
657
+ isAttributeNoreturn = None
658
+ overriddenFunction = None
659
+ nestedIn = None
660
+
661
+ def __init__(self, element, nestedIn):
662
+ self.Id = element.get('id')
663
+ self.tokenId = element.get('token')
664
+ self.tokenDefId = element.get('tokenDef')
665
+ self.name = element.get('name')
666
+ self.type = element.get('type')
667
+ self.hasVirtualSpecifier = element.get('hasVirtualSpecifier', 'false') == 'true'
668
+ self.isImplicitlyVirtual = element.get('isImplicitlyVirtual', 'false') == 'true'
669
+ self.access = element.get('access')
670
+ self.isInlineKeyword = element.get('isInlineKeyword', 'false') == 'true'
671
+ self.isStatic = element.get('isStatic', 'false') == 'true'
672
+ self.isAttributeNoreturn = element.get('isAttributeNoreturn', 'false') == 'true'
673
+ self.overriddenFunction = element.get('overriddenFunction', 'false') == 'true'
674
+ self.nestedIn = nestedIn
675
+
676
+ self.argument = {}
677
+ self.argumentId = {}
678
+
679
+ def __repr__(self):
680
+ attrs = ["Id", "tokenId", "tokenDefId", "name", "type", "hasVirtualSpecifier",
681
+ "isImplicitlyVirtual", "access", "isInlineKeyword", "isStatic",
682
+ "isAttributeNoreturn", "overriddenFunction", "nestedIn", "argumentId"]
683
+ return "{}({})".format(
684
+ "Function",
685
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
686
+ )
687
+
688
+ def setId(self, IdMap):
689
+ for argnr, argid in self.argumentId.items():
690
+ self.argument[argnr] = IdMap[argid]
691
+ self.token = IdMap.get(self.tokenId, None)
692
+ self.tokenDef = IdMap[self.tokenDefId]
693
+
694
+
695
+ #todo add class Types:
696
+ #symboldatabase.cpp/SymbolDatabase::printXml
697
+
698
+
699
+ class Variable:
700
+ """
701
+ Information about a variable
702
+ C++ class:
703
+ https://cppcheck.sourceforge.io/devinfo/doxyoutput/classVariable.html
704
+
705
+ Attributes:
706
+ nameToken Name token in variable declaration
707
+ typeStartToken Start token of variable declaration
708
+ typeEndToken End token of variable declaration
709
+ access Global/Local/Namespace/Public/Protected/Public/Throw/Argument/Unknown
710
+ scope Variable scope
711
+ constness Variable constness (same encoding as ValueType::constness)
712
+ isArgument Is this variable a function argument?
713
+ isGlobal Is this variable a global variable?
714
+ isLocal Is this variable a local variable?
715
+ isArray Is this variable an array?
716
+ isClass Is this variable a class or struct?
717
+ isConst Is this variable a const variable?
718
+ isExtern Is this variable an extern variable?
719
+ isPointer Is this variable a pointer
720
+ isReference Is this variable a reference
721
+ isStatic Is this variable static?
722
+ isVolatile Is this variable volatile?
723
+ """
724
+ #symboldatabase.cpp/SymbolDatabase::printXml
725
+
726
+ Id = None
727
+ nameTokenId = None
728
+ nameToken = None
729
+ typeStartTokenId = None
730
+ typeStartToken = None
731
+ typeEndTokenId = None
732
+ typeEndToken = None
733
+ access = None
734
+ scopeId = None
735
+ scope = None
736
+ isArgument = False
737
+ isArray = False
738
+ isClass = False
739
+ isConst = False
740
+ isExtern = False
741
+ isGlobal = False
742
+ isLocal = False
743
+ isPointer = False
744
+ isReference = False
745
+ isStatic = False
746
+ isVolatile = False
747
+ constness = 0
748
+
749
+ def __init__(self, element):
750
+ self.Id = element.get('id')
751
+ self.nameTokenId = element.get('nameToken')
752
+ self.nameToken = None
753
+ self.typeStartTokenId = element.get('typeStartToken')
754
+ self.typeStartToken = None
755
+ self.typeEndTokenId = element.get('typeEndToken')
756
+ self.typeEndToken = None
757
+ self.access = element.get('access')
758
+ self.isArgument = (self.access and self.access == 'Argument')
759
+ self.isGlobal = (self.access and self.access == 'Global')
760
+ self.isLocal = (self.access and self.access == 'Local')
761
+ self.scopeId = element.get('scope')
762
+ self.scope = None
763
+ self.constness = int(element.get('constness',0))
764
+ self.isArray = element.get('isArray') == 'true'
765
+ self.isClass = element.get('isClass') == 'true'
766
+ self.isConst = element.get('isConst') == 'true'
767
+ self.isExtern = element.get('isExtern') == 'true'
768
+ self.isPointer = element.get('isPointer') == 'true'
769
+ self.isReference = element.get('isReference') == 'true'
770
+ self.isStatic = element.get('isStatic') == 'true'
771
+ self.isVolatile = element.get('isVolatile') == 'true'
772
+
773
+ def __repr__(self):
774
+ attrs = ["Id", "nameTokenId", "typeStartTokenId", "typeEndTokenId",
775
+ "access", "scopeId", "isArgument", "isArray", "isClass",
776
+ "isConst", "isGlobal", "isExtern", "isLocal", "isPointer",
777
+ "isReference", "isStatic", "isVolatile", "constness"]
778
+ return "{}({})".format(
779
+ "Variable",
780
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
781
+ )
782
+
783
+ def setId(self, IdMap):
784
+ self.nameToken = IdMap[self.nameTokenId]
785
+ self.typeStartToken = IdMap[self.typeStartTokenId]
786
+ self.typeEndToken = IdMap[self.typeEndTokenId]
787
+ self.scope = IdMap[self.scopeId]
788
+
789
+ class Container:
790
+ """
791
+ Container class -- information about containers
792
+
793
+ Attributes:
794
+ array-like-index-op true/false
795
+ stdStringLike true/false
796
+ """
797
+ #tokenizer.cpp/tokenizer::dump
798
+ Id = None
799
+
800
+ def __init__(self, element):
801
+ self.Id = element.get('id')
802
+ self.arrayLikeIndexOp = element.get('array-like-index-op') == 'true'
803
+ self.stdStringLike = element.get('std-string-like') == 'true'
804
+
805
+ class TypedefInfo:
806
+ """
807
+ TypedefInfo class -- information about typedefs
808
+
809
+ Attributes:
810
+ name name of the typedef
811
+ used 0/1
812
+ """
813
+ #tokenizer.cpp/tokenizer::dump
814
+
815
+ name = None
816
+ used = None
817
+ file = None
818
+ linenr = None
819
+ column = None
820
+
821
+ def __init__(self, element):
822
+ self.name = element.get('name')
823
+ _load_location(self, element)
824
+ self.used = (element.get('used') == '1')
825
+
826
+ class Value:
827
+ """
828
+ Value class
829
+
830
+ Attributes:
831
+ intvalue integer value
832
+ tokvalue token value
833
+ floatvalue float value
834
+ movedvalue
835
+ uninit
836
+ containerSize container size
837
+ bufferSize buffer size
838
+ lifetimeScope Local/Argument/SubFunction/ThisPointer/ThisValue
839
+ lifetimeKind Object/SubObject/Lambda/Iterator/Address
840
+ symbolicDelta
841
+ condition condition where this Value comes from
842
+ bound Upper/Lower/Point
843
+ valueKind known/possible/impossible/inconclusive
844
+ path 0/1/2/3/..
845
+ """
846
+ #token.cpp/token::printValueFlow
847
+
848
+ intvalue = None
849
+ tokvalue = None
850
+ floatvalue = None
851
+ containerSize = None
852
+ condition = None
853
+ valueKind = None
854
+
855
+ def isKnown(self):
856
+ return self.valueKind and self.valueKind == 'known'
857
+
858
+ def isPossible(self):
859
+ return self.valueKind and self.valueKind == 'possible'
860
+
861
+ def isImpossible(self):
862
+ return self.valueKind and self.valueKind == 'impossible'
863
+
864
+ def isInconclusive(self):
865
+ return self.valueKind and self.valueKind == 'inconclusive'
866
+
867
+ def __init__(self, element):
868
+ self.intvalue = element.get('intvalue')
869
+ if self.intvalue:
870
+ self.intvalue = int(self.intvalue)
871
+ self._tokvalueId = element.get('tokvalue')
872
+ self.floatvalue = element.get('floatvalue')
873
+ self.movedvalue = element.get('movedvalue')
874
+ self.uninit = element.get('uninit')
875
+ self.bufferSize = element.get('buffer-size')
876
+ self.containerSize = element.get('container-size')
877
+ self.iteratorStart = element.get('iterator-start')
878
+ self.iteratorEnd = element.get('iterator-end')
879
+ self._lifetimeId = element.get('lifetime')
880
+ self.lifetimeScope = element.get('lifetime-scope')
881
+ self.lifetimeKind = element.get('lifetime-kind')
882
+ self._symbolicId = element.get('symbolic')
883
+ self.symbolicDelta = element.get('symbolic-delta')
884
+ self.bound = element.get('bound')
885
+ self.condition = element.get('condition-line')
886
+ if self.condition:
887
+ self.condition = int(self.condition)
888
+ if element.get('known'):
889
+ self.valueKind = 'known'
890
+ elif element.get('possible'):
891
+ self.valueKind = 'possible'
892
+ elif element.get('impossible'):
893
+ self.valueKind = 'impossible'
894
+ elif element.get('inconclusive'):
895
+ self.valueKind = 'inconclusive'
896
+ self.path = element.get('path')
897
+
898
+ def setId(self, IdMap):
899
+ self.tokvalue = IdMap.get(self._tokvalueId)
900
+ self.lifetime = IdMap.get(self._lifetimeId)
901
+ self.symbolic = IdMap.get(self._symbolicId)
902
+
903
+ def __repr__(self):
904
+ attrs = ["intvalue", "tokvalue", "floatvalue", "movedvalue", "uninit",
905
+ "bufferSize", "containerSize", "condition", "valueKind"]
906
+ return "{}({})".format(
907
+ "Value",
908
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
909
+ )
910
+
911
+
912
+ class ValueFlow:
913
+ """
914
+ ValueFlow::Value class
915
+ Each possible value has a ValueFlow::Value item.
916
+ Each ValueFlow::Value either has a intvalue or tokvalue
917
+ C++ class:
918
+ https://cppcheck.sourceforge.io/devinfo/doxyoutput/classValueFlow_1_1Value.html
919
+
920
+ Attributes:
921
+ values Possible values
922
+ """
923
+
924
+ Id = None
925
+ values = None
926
+
927
+ def __init__(self, element):
928
+ self.Id = element.get('id')
929
+ self.values = []
930
+
931
+ def __repr__(self):
932
+ attrs = ["Id", "values"]
933
+ return "{}({})".format(
934
+ "ValueFlow",
935
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
936
+ )
937
+
938
+
939
+ class Suppression:
940
+ """
941
+ Suppression class
942
+ This class contains a suppression entry to suppress a warning.
943
+
944
+ Attributes
945
+ errorId The id string of the error to suppress, can be a wildcard
946
+ fileName The name of the file to suppress warnings for, can include wildcards
947
+ lineNumber The number of the line to suppress warnings from, can be 0 to represent any line
948
+ symbolName The name of the symbol to match warnings for, can include wildcards
949
+ lineBegin The first line to suppress warnings from
950
+ lineEnd The last line to suppress warnings from
951
+ suppressionType The type of suppression which is applied (unique = None (default), file, block, blockBegin, blockEnd, macro)
952
+ """
953
+
954
+ errorId = None
955
+ fileName = None
956
+ lineNumber = None
957
+ symbolName = None
958
+ lineBegin = None
959
+ lineEnd = None
960
+ suppressionType = None
961
+
962
+ def __init__(self, element):
963
+ self.errorId = element.get('errorId')
964
+ self.fileName = element.get('fileName')
965
+ self.lineNumber = element.get('lineNumber')
966
+ self.symbolName = element.get('symbolName')
967
+ self.lineBegin = element.get('lineBegin')
968
+ self.lineEnd = element.get('lineEnd')
969
+ self.suppressionType = element.get('type')
970
+
971
+ def __repr__(self):
972
+ attrs = ["errorId", "fileName", "lineNumber", "symbolName", "lineBegin", "lineEnd","suppressionType"]
973
+ return "{}({})".format(
974
+ "Suppression",
975
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
976
+ )
977
+
978
+ def isMatch(self, file, line, message, errorId):
979
+ # Line Suppression
980
+ if ((self.fileName is None or fnmatch(file, self.fileName))
981
+ and (self.suppressionType is None) # Verify use of default suppression type (None = unique)
982
+ and (self.lineNumber is not None and int(line) == int(self.lineNumber))
983
+ and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*'))
984
+ and fnmatch(errorId, self.errorId)):
985
+ return True
986
+ # File Suppression
987
+ if ((self.fileName is None or fnmatch(file, self.fileName))
988
+ and (self.suppressionType is not None and self.suppressionType == "file") # Verify use of file (global) suppression type
989
+ and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*'))
990
+ and fnmatch(errorId, self.errorId)):
991
+ return True
992
+ # Block Suppression Mode
993
+ if ((self.fileName is None or fnmatch(file, self.fileName))
994
+ and (self.suppressionType is not None and self.suppressionType == "block") # Type for Block suppression
995
+ and (self.lineBegin is not None and int(line) > int(self.lineBegin)) # Code Match is between the Block suppression
996
+ and (self.lineEnd is not None and int(line) < int(self.lineEnd)) # Code Match is between the Block suppression
997
+ and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*'))
998
+ and fnmatch(errorId, self.errorId)):
999
+ return True
1000
+ # Other Suppression (Globaly set via suppression file or cli command)
1001
+ if ((self.fileName is None or fnmatch(file, self.fileName))
1002
+ and (self.suppressionType is None)
1003
+ and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*'))
1004
+ and fnmatch(errorId, self.errorId)):
1005
+ return True
1006
+ return False
1007
+
1008
+
1009
+ class Configuration:
1010
+ """
1011
+ Configuration class
1012
+ This class contains the directives, tokens, scopes, functions,
1013
+ variables, value flows, and suppressions for one configuration.
1014
+
1015
+ Attributes:
1016
+ name Name of the configuration, "" for default
1017
+ directives List of Directive items
1018
+ macro_usage List of used macros
1019
+ preprocessor_if_conditions List of preprocessor if conditions that was evaluated during preprocessing
1020
+ tokenlist List of Token items
1021
+ scopes List of Scope items
1022
+ containers List of Container items
1023
+ functions List of Function items
1024
+ variables List of Variable items
1025
+ valueflow List of ValueFlow values
1026
+ standards List of Standards values
1027
+ """
1028
+
1029
+ name = ''
1030
+ directives = []
1031
+ macro_usage = []
1032
+ preprocessor_if_conditions = []
1033
+ tokenlist = []
1034
+ scopes = []
1035
+ containers = []
1036
+ functions = []
1037
+ variables = []
1038
+ typedefInfo = []
1039
+ valueflow = []
1040
+ standards = None
1041
+ clang_warnings = []
1042
+
1043
+ def __init__(self, name):
1044
+ self.name = name
1045
+ self.directives = []
1046
+ self.macro_usage = []
1047
+ self.preprocessor_if_conditions = []
1048
+ self.tokenlist = []
1049
+ self.scopes = []
1050
+ self.containers = []
1051
+ self.functions = []
1052
+ self.variables = []
1053
+ self.typedefInfo = []
1054
+ self.valueflow = []
1055
+ self.standards = Standards()
1056
+ self.clang_warnings = []
1057
+
1058
+ def set_tokens_links(self):
1059
+ """Set next/previous links between tokens."""
1060
+ prev = None
1061
+ for token in self.tokenlist:
1062
+ token.previous = prev
1063
+ if prev:
1064
+ prev.next = token
1065
+ prev = token
1066
+
1067
+ def set_id_map(self, arguments):
1068
+ IdMap = {None: None, '0': None, '00000000': None, '0000000000000000': None, '0x0': None}
1069
+ for token in self.tokenlist:
1070
+ IdMap[token.Id] = token
1071
+ for scope in self.scopes:
1072
+ IdMap[scope.Id] = scope
1073
+ for container in self.containers:
1074
+ IdMap[container.Id] = container
1075
+ for function in self.functions:
1076
+ IdMap[function.Id] = function
1077
+ for variable in self.variables:
1078
+ IdMap[variable.Id] = variable
1079
+ for variable in arguments:
1080
+ IdMap[variable.Id] = variable
1081
+ for values in self.valueflow:
1082
+ IdMap[values.Id] = values.values
1083
+ for token in self.tokenlist:
1084
+ token.setId(IdMap)
1085
+ for scope in self.scopes:
1086
+ scope.setId(IdMap)
1087
+ #for container in self.containers:
1088
+ # container.setId(IdMap)
1089
+ for function in self.functions:
1090
+ function.setId(IdMap)
1091
+ for variable in self.variables:
1092
+ variable.setId(IdMap)
1093
+ for variable in arguments:
1094
+ variable.setId(IdMap)
1095
+
1096
+ def setIdMap(self, functions_arguments):
1097
+ """Set relationships between objects stored in this configuration.
1098
+ :param functions_arguments: List of Variable objects which are function arguments
1099
+ """
1100
+ self.set_tokens_links()
1101
+ self.set_id_map(functions_arguments)
1102
+
1103
+
1104
+ class Platform:
1105
+ """
1106
+ Platform class
1107
+ This class contains type sizes
1108
+
1109
+ Attributes:
1110
+ name Name of the platform: unspecified/native/win32A/win32W/win64/unix32/unix64/platformFile
1111
+ char_bit CHAR_BIT value
1112
+ short_bit SHORT_BIT value
1113
+ int_bit INT_BIT value
1114
+ long_bit LONG_BIT value
1115
+ long_long_bit LONG_LONG_BIT value
1116
+ pointer_bit POINTER_BIT value
1117
+ """
1118
+
1119
+ name = ''
1120
+ char_bit = 0
1121
+ short_bit = 0
1122
+ int_bit = 0
1123
+ long_bit = 0
1124
+ long_long_bit = 0
1125
+ pointer_bit = 0
1126
+
1127
+ def __init__(self, platformnode):
1128
+ self.name = platformnode.get('name')
1129
+ self.char_bit = int(platformnode.get('char_bit'))
1130
+ self.short_bit = int(platformnode.get('short_bit'))
1131
+ self.int_bit = int(platformnode.get('int_bit'))
1132
+ self.long_bit = int(platformnode.get('long_bit'))
1133
+ self.long_long_bit = int(platformnode.get('long_long_bit'))
1134
+ self.pointer_bit = int(platformnode.get('pointer_bit'))
1135
+
1136
+ def __repr__(self):
1137
+ attrs = ["name", "char_bit", "short_bit", "int_bit",
1138
+ "long_bit", "long_long_bit", "pointer_bit"]
1139
+ return "{}({})".format(
1140
+ "Platform",
1141
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
1142
+ )
1143
+
1144
+
1145
+ class Standards:
1146
+ """
1147
+ Standards class
1148
+ This class contains versions of standards that were used for the cppcheck
1149
+
1150
+ Attributes:
1151
+ c C Standard used
1152
+ cpp C++ Standard used
1153
+ posix If Posix was used
1154
+ """
1155
+
1156
+ c = ""
1157
+ cpp = ""
1158
+ posix = False
1159
+
1160
+ def set_c(self, node):
1161
+ self.c = node.get("version")
1162
+
1163
+ def set_cpp(self, node):
1164
+ self.cpp = node.get("version")
1165
+
1166
+ def set_posix(self, node):
1167
+ self.posix = node.get("posix") is not None
1168
+
1169
+ def __repr__(self):
1170
+ attrs = ["c", "cpp", "posix"]
1171
+ return "{}({})".format(
1172
+ "Standards",
1173
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
1174
+ )
1175
+
1176
+
1177
+ class CppcheckData:
1178
+ """
1179
+ Class that makes cppcheck dump data available
1180
+ Contains a list of Configuration instances
1181
+
1182
+ Attributes:
1183
+ filename Path to Cppcheck dump file
1184
+ rawTokens List of rawToken elements
1185
+ suppressions List of Suppressions
1186
+ files Source files for elements occurred in this configuration
1187
+
1188
+ To iterate through all configurations use such code:
1189
+ @code
1190
+ data = cppcheckdata.parsedump(...)
1191
+ for cfg in data.configurations:
1192
+ print('cfg: ' + cfg.name)
1193
+ @endcode
1194
+
1195
+ To iterate through all tokens in each configuration use such code:
1196
+ @code
1197
+ data = cppcheckdata.parsedump(...)
1198
+ for cfg in data.configurations:
1199
+ print('cfg: ' + cfg.name)
1200
+ code = ''
1201
+ for token in cfg.tokenlist:
1202
+ code = code + token.str + ' '
1203
+ print(' ' + code)
1204
+ @endcode
1205
+
1206
+ To iterate through all scopes (functions, types, etc) use such code:
1207
+ @code
1208
+ data = cppcheckdata.parsedump(...)
1209
+ for cfg in data.configurations:
1210
+ print('cfg: ' + cfg.name)
1211
+ for scope in cfg.scopes:
1212
+ print(' type:' + scope.type + ' name:' + scope.className)
1213
+ @endcode
1214
+ """
1215
+
1216
+ def __init__(self, filename):
1217
+ """
1218
+ :param filename: Path to Cppcheck dump file
1219
+ """
1220
+ self.filename = filename
1221
+ self.rawTokens = []
1222
+ self.platform = None
1223
+ self.suppressions = []
1224
+ self.files = [] # source files for elements occurred in this configuration
1225
+
1226
+ platform_done = False
1227
+ rawtokens_done = False
1228
+ suppressions_done = False
1229
+
1230
+ # Parse general configuration options from <dumps> node
1231
+ # We intentionally don't clean node resources here because we
1232
+ # want to serialize in memory only small part of the XML tree.
1233
+ for event, node in ElementTree.iterparse(self.filename, events=('start', 'end')):
1234
+ if platform_done and rawtokens_done and suppressions_done:
1235
+ break
1236
+ if node.tag == 'platform' and event == 'start':
1237
+ self.platform = Platform(node)
1238
+ platform_done = True
1239
+ elif node.tag == 'rawtokens' and event == 'end':
1240
+ for rawtokens_node in node:
1241
+ if rawtokens_node.tag == 'file':
1242
+ self.files.append(rawtokens_node.get('name'))
1243
+ elif rawtokens_node.tag == 'tok':
1244
+ tok = Token(rawtokens_node)
1245
+ tok.file = self.files[int(rawtokens_node.get('fileIndex'))]
1246
+ self.rawTokens.append(tok)
1247
+ rawtokens_done = True
1248
+ elif node.tag == 'suppressions' and event == 'end':
1249
+ for suppressions_node in node:
1250
+ self.suppressions.append(Suppression(suppressions_node))
1251
+ suppressions_done = True
1252
+
1253
+ global current_dumpfile_suppressions
1254
+ current_dumpfile_suppressions = self.suppressions
1255
+
1256
+ # Set links between rawTokens.
1257
+ for i in range(len(self.rawTokens)-1):
1258
+ self.rawTokens[i+1].previous = self.rawTokens[i]
1259
+ self.rawTokens[i].next = self.rawTokens[i+1]
1260
+
1261
+ @property
1262
+ def configurations(self):
1263
+ """
1264
+ Return the list of all available Configuration objects.
1265
+ """
1266
+ return list(self.iterconfigurations())
1267
+
1268
+ def iterconfigurations(self):
1269
+ """
1270
+ Create and return iterator for the available Configuration objects.
1271
+ The iterator loops over all Configurations in the dump file tree, in document order.
1272
+ """
1273
+ cfg = None
1274
+ cfg_arguments = [] # function arguments for Configuration node initialization
1275
+ cfg_function = None
1276
+ cfg_valueflow = None
1277
+
1278
+ # Iterating <varlist> in a <scope>.
1279
+ iter_scope_varlist = False
1280
+
1281
+ # Iterating <typedef-info>
1282
+ iter_typedef_info = False
1283
+
1284
+ # Iterating <directive>
1285
+ iter_directive = False
1286
+
1287
+ # Use iterable objects to traverse XML tree for dump files incrementally.
1288
+ # Iterative approach is required to avoid large memory consumption.
1289
+ # Calling .clear() is necessary to let the element be garbage collected.
1290
+ for event, node in ElementTree.iterparse(self.filename, events=('start', 'end')):
1291
+ # Serialize new configuration node
1292
+ if node.tag == 'dump':
1293
+ if event == 'start':
1294
+ cfg = Configuration(node.get('cfg'))
1295
+ continue
1296
+ elif event == 'end':
1297
+ cfg.setIdMap(cfg_arguments)
1298
+ yield cfg
1299
+ cfg = None
1300
+ cfg_arguments = []
1301
+
1302
+ elif node.tag == 'clang-warning' and event == 'start':
1303
+ cfg.clang_warnings.append({'file': node.get('file'),
1304
+ 'line': int(node.get('line')),
1305
+ 'column': int(node.get('column')),
1306
+ 'message': node.get('message')})
1307
+ # Parse standards
1308
+ elif node.tag == "standards" and event == 'start':
1309
+ continue
1310
+ elif node.tag == 'c' and event == 'start':
1311
+ cfg.standards.set_c(node)
1312
+ elif node.tag == 'cpp' and event == 'start':
1313
+ cfg.standards.set_cpp(node)
1314
+ elif node.tag == 'posix' and event == 'start':
1315
+ cfg.standards.set_posix(node)
1316
+
1317
+ # Parse directives list
1318
+ elif node.tag == 'directive':
1319
+ if event == 'start':
1320
+ cfg.directives.append(Directive(node))
1321
+ iter_directive = True
1322
+ elif event == 'end':
1323
+ iter_directive = False
1324
+ # Parse macro usage
1325
+ elif node.tag == 'macro' and event == 'start':
1326
+ cfg.macro_usage.append(MacroUsage(node))
1327
+
1328
+ # Preprocessor #if/#elif condition
1329
+ elif node.tag == "if-cond" and event == 'start':
1330
+ cfg.preprocessor_if_conditions.append(PreprocessorIfCondition(node))
1331
+
1332
+ # Parse tokens
1333
+ elif node.tag == 'tokenlist' and event == 'start':
1334
+ continue
1335
+ elif node.tag == 'token' and event == 'start' and not iter_directive:
1336
+ cfg.tokenlist.append(Token(node))
1337
+
1338
+ # Parse scopes
1339
+ elif node.tag == 'scopes' and event == 'start':
1340
+ continue
1341
+ elif node.tag == 'scope' and event == 'start':
1342
+ cfg.scopes.append(Scope(node))
1343
+ elif node.tag == 'varlist':
1344
+ if event == 'start':
1345
+ iter_scope_varlist = True
1346
+ elif event == 'end':
1347
+ iter_scope_varlist = False
1348
+
1349
+ # Parse functions
1350
+ elif node.tag == 'functionList' and event == 'start':
1351
+ continue
1352
+ elif node.tag == 'function':
1353
+ if event == 'start':
1354
+ cfg_function = Function(node, cfg.scopes[-1])
1355
+ continue
1356
+ elif event == 'end':
1357
+ cfg.functions.append(cfg_function)
1358
+ cfg_function = None
1359
+
1360
+ # Parse function arguments
1361
+ elif node.tag == 'arg' and event == 'start':
1362
+ arg_nr = int(node.get('nr'))
1363
+ arg_variable_id = node.get('variable')
1364
+ cfg_function.argumentId[arg_nr] = arg_variable_id
1365
+
1366
+ # Parse variables
1367
+ elif node.tag == 'var' and event == 'start':
1368
+ if iter_scope_varlist:
1369
+ cfg.scopes[-1].varlistId.append(node.get('id'))
1370
+ else:
1371
+ var = Variable(node)
1372
+ if var.nameTokenId:
1373
+ cfg.variables.append(var)
1374
+ else:
1375
+ cfg_arguments.append(var)
1376
+
1377
+ # Parse containers
1378
+ elif node.tag == 'containers' and event == 'start':
1379
+ continue
1380
+ elif node.tag == 'container' and event == 'start':
1381
+ cfg.containers.append(Container(node))
1382
+
1383
+ # Parse typedef info
1384
+ elif node.tag == 'typedef-info':
1385
+ iter_typedef_info = (event == 'start')
1386
+ elif iter_typedef_info and node.tag == 'info' and event == 'start':
1387
+ cfg.typedefInfo.append(TypedefInfo(node))
1388
+
1389
+ # Parse template-token
1390
+ #elif node.tag == 'TokenAndName' and event == 'start': #todo add processing of containers
1391
+ # cfg.containers.append(Container(node))
1392
+
1393
+ # Parse valueflows (list of values)
1394
+ elif node.tag == 'valueflow' and event == 'start':
1395
+ continue
1396
+ elif node.tag == 'values':
1397
+ if event == 'start':
1398
+ cfg_valueflow = ValueFlow(node)
1399
+ continue
1400
+ elif event == 'end':
1401
+ cfg.valueflow.append(cfg_valueflow)
1402
+ cfg_valueflow = None
1403
+
1404
+ # Parse values
1405
+ elif node.tag == 'value' and event == 'start':
1406
+ cfg_valueflow.values.append(Value(node))
1407
+
1408
+ # Remove links to the sibling nodes
1409
+ node.clear()
1410
+
1411
+ def __repr__(self):
1412
+ attrs = ["configurations", "platform"]
1413
+ return "{}({})".format(
1414
+ "CppcheckData",
1415
+ ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
1416
+ )
1417
+
1418
+
1419
+ # Get function arguments
1420
+ def getArgumentsRecursive(tok, arguments):
1421
+ if tok is None:
1422
+ return
1423
+ if tok.str == ',':
1424
+ getArgumentsRecursive(tok.astOperand1, arguments)
1425
+ getArgumentsRecursive(tok.astOperand2, arguments)
1426
+ else:
1427
+ arguments.append(tok)
1428
+
1429
+
1430
+ def getArguments(ftok):
1431
+ if (not ftok.isName) or (ftok.next is None) or ftok.next.str != '(':
1432
+ return None
1433
+ args = []
1434
+ getArgumentsRecursive(ftok.next.astOperand2, args)
1435
+ return args
1436
+
1437
+
1438
+ def parsedump(filename):
1439
+ """
1440
+ parse a cppcheck dump file
1441
+ """
1442
+ return CppcheckData(filename)
1443
+
1444
+
1445
+ def astIsFloat(token):
1446
+ """
1447
+ Check if type of ast node is float/double
1448
+ """
1449
+
1450
+ if not token:
1451
+ return False
1452
+ if token.str == '.':
1453
+ return astIsFloat(token.astOperand2)
1454
+ if token.str in '+-*/%':
1455
+ return astIsFloat(token.astOperand1) or astIsFloat(token.astOperand2)
1456
+ if not token.variable:
1457
+ # float literal?
1458
+ if token.str[0].isdigit():
1459
+ for c in token.str:
1460
+ if c == 'f' or c == '.' or c == 'E':
1461
+ return True
1462
+ return False
1463
+ typeToken = token.variable.typeStartToken
1464
+ endToken = token.variable.typeEndToken
1465
+ while typeToken != endToken:
1466
+ if typeToken.str == 'float' or typeToken.str == 'double':
1467
+ return True
1468
+ typeToken = typeToken.next
1469
+ if typeToken.str == 'float' or typeToken.str == 'double':
1470
+ return True
1471
+ return False
1472
+
1473
+
1474
+ class CppCheckFormatter(argparse.HelpFormatter):
1475
+ """
1476
+ Properly formats multiline argument helps
1477
+ """
1478
+ def _split_lines(self, text, width):
1479
+ # this is the RawTextHelpFormatter._split_lines
1480
+ if text.startswith('R|'):
1481
+ return text[2:].splitlines()
1482
+ return argparse.HelpFormatter._split_lines(self, text, width)
1483
+
1484
+
1485
+ def ArgumentParser():
1486
+ """
1487
+ Returns an argparse argument parser with an already-added
1488
+ argument definition for -t/--template
1489
+ """
1490
+ parser = argparse.ArgumentParser(formatter_class=CppCheckFormatter)
1491
+ parser.add_argument('-t', '--template', metavar='<text>',
1492
+ default='{callstack}: ({severity}) {message}',
1493
+ help="R|Format the error messages. E.g.\n"
1494
+ "'{file}:{line},{severity},{id},{message}' or\n"
1495
+ "'{file}({line}):({severity}) {message}' or\n"
1496
+ "'{callstack} {message}'\n"
1497
+ "Pre-defined templates: gcc, vs, edit")
1498
+ parser.add_argument("dumpfile", nargs='*',
1499
+ help="Path of dump files from cppcheck.")
1500
+ parser.add_argument("--cli",
1501
+ help="Addon is executed from Cppcheck",
1502
+ action="store_true")
1503
+ parser.add_argument("--file-list", metavar='<text>',
1504
+ default=None,
1505
+ help="file list in a text file")
1506
+ parser.add_argument("-q", "--quiet",
1507
+ help='do not print "Checking ..." lines',
1508
+ action="store_true")
1509
+ return parser
1510
+
1511
+
1512
+ def get_files(args):
1513
+ """Return dump_files, ctu_info_files"""
1514
+ all_files = args.dumpfile
1515
+ if args.file_list:
1516
+ with open(args.file_list, 'rt') as f:
1517
+ for line in f.readlines():
1518
+ all_files.append(line.rstrip())
1519
+ dump_files = []
1520
+ ctu_info_files = []
1521
+ for f in all_files:
1522
+ if f.endswith('.ctu-info'):
1523
+ ctu_info_files.append(f)
1524
+ else:
1525
+ dump_files.append(f)
1526
+ return dump_files, ctu_info_files
1527
+
1528
+ def simpleMatch(token, pattern):
1529
+ for p in pattern.split(' '):
1530
+ if not token or token.str != p:
1531
+ return False
1532
+ token = token.next
1533
+ return True
1534
+
1535
+ patterns = {
1536
+ '%any%': lambda tok: tok,
1537
+ '%assign%': lambda tok: tok if tok.isAssignmentOp else None,
1538
+ '%comp%': lambda tok: tok if tok.isComparisonOp else None,
1539
+ '%name%': lambda tok: tok if tok.isName else None,
1540
+ '%op%': lambda tok: tok if tok.isOp else None,
1541
+ '%or%': lambda tok: tok if tok.str == '|' else None,
1542
+ '%oror%': lambda tok: tok if tok.str == '||' else None,
1543
+ '%var%': lambda tok: tok if tok.variable else None,
1544
+ '(*)': lambda tok: tok.link if tok.str == '(' 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 == '<' and tok.link else None,
1548
+ }
1549
+
1550
+ def match_atom(token, p):
1551
+ if not token:
1552
+ return None
1553
+ if not p:
1554
+ return None
1555
+ if token.str == p:
1556
+ return token
1557
+ if p in ['!', '|', '||', '%', '!=', '*']:
1558
+ return None
1559
+ if p in patterns:
1560
+ return patterns[p](token)
1561
+ if '|' in p:
1562
+ for x in p.split('|'):
1563
+ t = match_atom(token, x)
1564
+ if t:
1565
+ return t
1566
+ elif p.startswith('!!'):
1567
+ t = match_atom(token, p[2:])
1568
+ if not t:
1569
+ return token
1570
+ elif p.startswith('**'):
1571
+ a = p[2:]
1572
+ t = token
1573
+ while t:
1574
+ if match_atom(t, a):
1575
+ return t
1576
+ if t.link and t.str in ['(', '[', '<', '{']:
1577
+ t = t.link
1578
+ t = t.next
1579
+ return None
1580
+
1581
+ class MatchResult:
1582
+ def __init__(self, matches, bindings=None, keys=None):
1583
+ self.__dict__.update(bindings or {})
1584
+ self._matches = matches
1585
+ self._keys = keys or []
1586
+
1587
+ def __bool__(self):
1588
+ return self._matches
1589
+
1590
+ def __nonzero__(self):
1591
+ return self._matches
1592
+
1593
+ def __getattr__(self, k):
1594
+ if k in self._keys:
1595
+ return None
1596
+ else:
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
+ # dumpfile ends with ".dump"
1692
+ ctu_info_file = dumpfile[:-4] + "ctu-info"
1693
+ with open(ctu_info_file, 'at') as f:
1694
+ msg = {'summary': summary_type, 'data': summary_data}
1695
+ f.write(json.dumps(msg) + '\n')
1696
+
1697
+
1698
+ def get_path_premium_addon():
1699
+ p = pathlib.Path(sys.argv[0]).parent.parent
1700
+
1701
+ for ext in ('.exe', ''):
1702
+ p1 = os.path.join(p, 'premiumaddon' + ext)
1703
+ p2 = os.path.join(p, 'cppcheck' + ext)
1704
+ if os.path.isfile(p1) and os.path.isfile(p2):
1705
+ return p1
1706
+ return None
1707
+
1708
+
1709
+ def cmd_output(cmd):
1710
+ with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
1711
+ comm = p.communicate()
1712
+ out = comm[0]
1713
+ if p.returncode == 1 and len(comm[1]) > 2:
1714
+ out = comm[1]
1715
+ return out.decode(encoding='utf-8', errors='ignore')