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