forked from danmar/cppcheck
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcppcheckdata.py
executable file
·1144 lines (997 loc) · 38.1 KB
/
cppcheckdata.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
cppcheckdata
This is a Python module that helps you access Cppcheck dump data.
License: No restrictions, use this as you need.
"""
import argparse
import json
import sys
from xml.etree import ElementTree
from fnmatch import fnmatch
EXIT_CODE = 0
current_dumpfile_suppressions = []
class Directive:
"""
Directive class. Contains information about each preprocessor directive in the source code.
Attributes:
str The directive line, with all C or C++ comments removed
file Name of (possibly included) file where directive is defined
linenr Line number in (possibly included) file where directive is defined
To iterate through all directives use such code:
@code
data = cppcheckdata.parsedump(...)
for cfg in data.configurations:
for directive in cfg.directives:
print(directive.str)
@endcode
"""
str = None
file = None
linenr = None
column = 0
def __init__(self, element):
self.str = element.get('str')
self.file = element.get('file')
self.linenr = int(element.get('linenr'))
def __repr__(self):
attrs = ["str", "file", "linenr"]
return "{}({})".format(
"Directive",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
class ValueType:
"""
ValueType class. Contains (promoted) type information for each node in the AST.
"""
type = None
sign = None
bits = 0
constness = 0
pointer = 0
typeScopeId = None
typeScope = None
originalTypeName = None
def __init__(self, element):
self.type = element.get('valueType-type')
self.sign = element.get('valueType-sign')
bits = element.get('valueType-bits')
if bits:
self.bits = int(bits)
self.typeScopeId = element.get('valueType-typeScope')
self.originalTypeName = element.get('valueType-originalTypeName')
constness = element.get('valueType-constness')
if constness:
self.constness = int(constness)
else:
self.constness = 0
pointer = element.get('valueType-pointer')
if pointer:
self.pointer = int(pointer)
else:
self.pointer = 0
def __repr__(self):
attrs = ["type", "sign", "bits", "typeScopeId", "originalTypeName",
"constness", "constness", "pointer"]
return "{}({})".format(
"ValueType",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
def setId(self, IdMap):
self.typeScope = IdMap[self.typeScopeId]
def isIntegral(self):
return self.type in {'bool', 'char', 'short', 'int', 'long', 'long long'}
def isFloat(self):
return self.type in {'float', 'double', 'long double'}
def isEnum(self):
return self.typeScope and self.typeScope.type == "Enum"
class Token:
"""
Token class. Contains information about each token in the source code.
The CppcheckData.tokenlist is a list of Token items
C++ class: http://cppcheck.net/devinfo/doxyoutput/classToken.html
Attributes:
str Token string
next Next token in tokenlist. For last token, next is None.
previous Previous token in tokenlist. For first token, previous is None.
link Linked token in tokenlist. Each '(', '[' and '{' are linked to the
corresponding '}', ']' and ')'. For templates, the '<' is linked to
the corresponding '>'.
scope Scope information for this token. See the Scope class.
isName Is this token a symbol name
isNumber Is this token a number, for example 123, 12.34
isInt Is this token a int value such as 1234
isFloat Is this token a int value such as 12.34
isString Is this token a string literal such as "hello"
strlen string length for string literal
isChar Is this token a char literal such as 'x'
isOp Is this token a operator
isArithmeticalOp Is this token a arithmetic operator
isAssignmentOp Is this token a assignment operator
isComparisonOp Is this token a comparison operator
isLogicalOp Is this token a logical operator: && ||
isUnsigned Is this token a unsigned type
isSigned Is this token a signed type
isExpandedMacro Is this token a expanded macro token
isSplittedVarDeclComma Is this a comma changed to semicolon in a splitted variable declaration ('int a,b;' => 'int a; int b;')
isSplittedVarDeclEq Is this a '=' changed to semicolon in a splitted variable declaration ('int a=5;' => 'int a; a=5;')
varId varId for token, each variable has a unique non-zero id
variable Variable information for this token. See the Variable class.
function If this token points at a function call, this attribute has the Function
information. See the Function class.
values Possible values of token
valueType type information
typeScope type scope (token->type()->classScope)
astParent ast parent
astOperand1 ast operand1
astOperand2 ast operand2
file file name
linenr line number
column column
To iterate through all tokens use such code:
@code
data = cppcheckdata.parsedump(...)
for cfg in data.configurations:
code = ''
for token in cfg.tokenlist:
code = code + token.str + ' '
print(code)
@endcode
"""
Id = None
str = None
next = None
previous = None
linkId = None
link = None
scopeId = None
scope = None
isName = False
isNumber = False
isInt = False
isFloat = False
isString = False
strlen = None
isChar = False
isOp = False
isArithmeticalOp = False
isAssignmentOp = False
isComparisonOp = False
isLogicalOp = False
isUnsigned = False
isSigned = False
isExpandedMacro = False
isSplittedVarDeclComma = False
isSplittedVarDeclEq = False
varId = None
variableId = None
variable = None
functionId = None
function = None
valuesId = None
values = None
valueType = None
typeScopeId = None
typeScope = None
astParentId = None
astParent = None
astOperand1Id = None
astOperand1 = None
astOperand2Id = None
astOperand2 = None
file = None
linenr = None
column = None
def __init__(self, element):
self.Id = element.get('id')
self.str = element.get('str')
self.next = None
self.previous = None
self.scopeId = element.get('scope')
self.scope = None
type = element.get('type')
if type == 'name':
self.isName = True
if element.get('isUnsigned'):
self.isUnsigned = True
if element.get('isSigned'):
self.isSigned = True
elif type == 'number':
self.isNumber = True
if element.get('isInt'):
self.isInt = True
elif element.get('isFloat'):
self.isFloat = True
elif type == 'string':
self.isString = True
self.strlen = int(element.get('strlen'))
elif type == 'char':
self.isChar = True
elif type == 'op':
self.isOp = True
if element.get('isArithmeticalOp'):
self.isArithmeticalOp = True
elif element.get('isAssignmentOp'):
self.isAssignmentOp = True
elif element.get('isComparisonOp'):
self.isComparisonOp = True
elif element.get('isLogicalOp'):
self.isLogicalOp = True
if element.get('isExpandedMacro'):
self.isExpandedMacro = True
if element.get('isSplittedVarDeclComma'):
self.isSplittedVarDeclComma = True
if element.get('isSplittedVarDeclEq'):
self.isSplittedVarDeclEq = True
self.linkId = element.get('link')
self.link = None
if element.get('varId'):
self.varId = int(element.get('varId'))
self.variableId = element.get('variable')
self.variable = None
self.functionId = element.get('function')
self.function = None
self.valuesId = element.get('values')
self.values = None
if element.get('valueType-type'):
self.valueType = ValueType(element)
else:
self.valueType = None
self.typeScopeId = element.get('type-scope')
self.typeScope = None
self.astParentId = element.get('astParent')
self.astParent = None
self.astOperand1Id = element.get('astOperand1')
self.astOperand1 = None
self.astOperand2Id = element.get('astOperand2')
self.astOperand2 = None
self.file = element.get('file')
self.linenr = int(element.get('linenr'))
self.column = int(element.get('column'))
def __repr__(self):
attrs = ["Id", "str", "scopeId", "isName", "isUnsigned", "isSigned",
"isNumber", "isInt", "isFloat", "isString", "strlen",
"isChar", "isOp", "isArithmeticalOp", "isComparisonOp",
"isLogicalOp", "isExpandedMacro", "isSplittedVarDeclComma",
"isSplittedVarDeclEq","linkId", "varId", "variableId",
"functionId", "valuesId", "valueType", "typeScopeId",
"astParentId", "astOperand1Id", "file", "linenr", "column"]
return "{}({})".format(
"Token",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
def setId(self, IdMap):
self.scope = IdMap[self.scopeId]
self.link = IdMap[self.linkId]
self.variable = IdMap[self.variableId]
self.function = IdMap[self.functionId]
self.values = IdMap[self.valuesId]
self.typeScope = IdMap[self.typeScopeId]
self.astParent = IdMap[self.astParentId]
self.astOperand1 = IdMap[self.astOperand1Id]
self.astOperand2 = IdMap[self.astOperand2Id]
if self.valueType:
self.valueType.setId(IdMap)
def getValue(self, v):
"""
Get value if it exists
Returns None if it doesn't exist
"""
if not self.values:
return None
for value in self.values:
if value.intvalue == v:
return value
return None
def getKnownIntValue(self):
"""
If token has a known int value then return that.
Otherwise returns None
"""
if not self.values:
return None
for value in self.values:
if value.valueKind == 'known':
return value.intvalue
return None
class Scope:
"""
Scope. Information about global scope, function scopes, class scopes, inner scopes, etc.
C++ class: http://cppcheck.net/devinfo/doxyoutput/classScope.html
Attributes
bodyStart The { Token for this scope
bodyEnd The } Token for this scope
className Name of this scope.
For a function scope, this is the function name;
For a class scope, this is the class name.
function If this scope belongs at a function call, this attribute
has the Function information. See the Function class.
type Type of scope: Global, Function, Class, If, While
"""
Id = None
bodyStartId = None
bodyStart = None
bodyEndId = None
bodyEnd = None
className = None
functionId = None
function = None
nestedInId = None
nestedIn = None
type = None
isExecutable = None
varlistId = None
varlist = None
def __init__(self, element):
self.Id = element.get('id')
self.className = element.get('className')
self.functionId = element.get('function')
self.function = None
self.bodyStartId = element.get('bodyStart')
self.bodyStart = None
self.bodyEndId = element.get('bodyEnd')
self.bodyEnd = None
self.nestedInId = element.get('nestedIn')
self.nestedIn = None
self.type = element.get('type')
self.isExecutable = (self.type in ('Function', 'If', 'Else', 'For', 'While', 'Do',
'Switch', 'Try', 'Catch', 'Unconditional', 'Lambda'))
self.varlistId = list()
self.varlist = list()
def __repr__(self):
attrs = ["Id", "className", "functionId", "bodyStartId", "bodyEndId",
"nestedInId", "nestedIn", "type", "isExecutable"]
return "{}({})".format(
"Scope",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
def setId(self, IdMap):
self.bodyStart = IdMap[self.bodyStartId]
self.bodyEnd = IdMap[self.bodyEndId]
self.nestedIn = IdMap[self.nestedInId]
self.function = IdMap[self.functionId]
for v in self.varlistId:
self.varlist.append(IdMap[v])
class Function:
"""
Information about a function
C++ class:
http://cppcheck.net/devinfo/doxyoutput/classFunction.html
Attributes
argument Argument list
tokenDef Token in function definition
isVirtual Is this function is virtual
isImplicitlyVirtual Is this function is virtual this in the base classes
isStatic Is this function is static
"""
Id = None
argument = None
argumentId = None
tokenDef = None
tokenDefId = None
name = None
type = None
isVirtual = None
isImplicitlyVirtual = None
isStatic = None
nestedIn = None
def __init__(self, element, nestedIn):
self.Id = element.get('id')
self.tokenDefId = element.get('tokenDef')
self.name = element.get('name')
self.type = element.get('type')
isVirtual = element.get('isVirtual')
self.isVirtual = (isVirtual and isVirtual == 'true')
isImplicitlyVirtual = element.get('isImplicitlyVirtual')
self.isImplicitlyVirtual = (isImplicitlyVirtual and isImplicitlyVirtual == 'true')
isStatic = element.get('isStatic')
self.isStatic = (isStatic and isStatic == 'true')
self.nestedIn = nestedIn
self.argument = {}
self.argumentId = {}
def __repr__(self):
attrs = ["Id", "tokenDefId", "name", "type", "isVirtual",
"isImplicitlyVirtual", "isStatic", "argumentId"]
return "{}({})".format(
"Function",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
def setId(self, IdMap):
for argnr, argid in self.argumentId.items():
self.argument[argnr] = IdMap[argid]
self.tokenDef = IdMap[self.tokenDefId]
class Variable:
"""
Information about a variable
C++ class:
http://cppcheck.net/devinfo/doxyoutput/classVariable.html
Attributes:
nameToken Name token in variable declaration
typeStartToken Start token of variable declaration
typeEndToken End token of variable declaration
access Global/Local/Namespace/Public/Protected/Public/Throw/Argument
scope Variable scope
isArgument Is this variable a function argument?
isArray Is this variable an array?
isClass Is this variable a class or struct?
isConst Is this variable a const variable?
isGlobal Is this variable a global variable?
isExtern Is this variable an extern variable?
isLocal Is this variable a local variable?
isPointer Is this variable a pointer
isReference Is this variable a reference
isStatic Is this variable static?
constness Variable constness (same encoding as ValueType::constness)
"""
Id = None
nameTokenId = None
nameToken = None
typeStartTokenId = None
typeStartToken = None
typeEndTokenId = None
typeEndToken = None
access = None
scopeId = None
scope = None
isArgument = False
isArray = False
isClass = False
isConst = False
isExtern = False
isGlobal = False
isLocal = False
isPointer = False
isReference = False
isStatic = False
constness = 0
def __init__(self, element):
self.Id = element.get('id')
self.nameTokenId = element.get('nameToken')
self.nameToken = None
self.typeStartTokenId = element.get('typeStartToken')
self.typeStartToken = None
self.typeEndTokenId = element.get('typeEndToken')
self.typeEndToken = None
self.access = element.get('access')
self.scopeId = element.get('scope')
self.scope = None
self.isArgument = element.get('isArgument') == 'true'
self.isArray = element.get('isArray') == 'true'
self.isClass = element.get('isClass') == 'true'
self.isConst = element.get('isConst') == 'true'
self.isGlobal = element.get('access') == 'Global'
self.isExtern = element.get('isExtern') == 'true'
self.isLocal = element.get('isLocal') == 'true'
self.isPointer = element.get('isPointer') == 'true'
self.isReference = element.get('isReference') == 'true'
self.isStatic = element.get('isStatic') == 'true'
self.constness = element.get('constness')
if self.constness:
self.constness = int(self.constness)
def __repr__(self):
attrs = ["Id", "nameTokenId", "typeStartTokenId", "typeEndTokenId",
"access", "scopeId", "isArgument", "isArray", "isClass",
"isConst", "isGlobal", "isExtern", "isLocal", "isPointer",
"isReference", "isStatic", "constness", ]
return "{}({})".format(
"Variable",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
def setId(self, IdMap):
self.nameToken = IdMap[self.nameTokenId]
self.typeStartToken = IdMap[self.typeStartTokenId]
self.typeEndToken = IdMap[self.typeEndTokenId]
self.scope = IdMap[self.scopeId]
class Value:
"""
Value class
Attributes:
intvalue integer value
tokvalue token value
floatvalue float value
containerSize container size
condition condition where this Value comes from
valueKind 'known' or 'possible'
inconclusive Is value inconclusive?
"""
intvalue = None
tokvalue = None
floatvalue = None
containerSize = None
condition = None
valueKind = None
inconclusive = False
def isKnown(self):
return self.valueKind and self.valueKind == 'known'
def isPossible(self):
return self.valueKind and self.valueKind == 'possible'
def __init__(self, element):
self.intvalue = element.get('intvalue')
if self.intvalue:
self.intvalue = int(self.intvalue)
self.tokvalue = element.get('tokvalue')
self.floatvalue = element.get('floatvalue')
self.containerSize = element.get('container-size')
self.condition = element.get('condition-line')
if self.condition:
self.condition = int(self.condition)
if element.get('known'):
self.valueKind = 'known'
elif element.get('possible'):
self.valueKind = 'possible'
if element.get('inconclusive'):
self.inconclusive = True
def __repr__(self):
attrs = ["intvalue", "tokvalue", "floatvalue", "containerSize",
"condition", "valueKind", "inconclusive"]
return "{}({})".format(
"Value",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
class ValueFlow:
"""
ValueFlow::Value class
Each possible value has a ValueFlow::Value item.
Each ValueFlow::Value either has a intvalue or tokvalue
C++ class:
http://cppcheck.net/devinfo/doxyoutput/classValueFlow_1_1Value.html
Attributes:
values Possible values
"""
Id = None
values = None
def __init__(self, element):
self.Id = element.get('id')
self.values = []
def __repr__(self):
attrs = ["Id", "values"]
return "{}({})".format(
"ValueFlow",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
class Suppression:
"""
Suppression class
This class contains a suppression entry to suppress a warning.
Attributes
errorId The id string of the error to suppress, can be a wildcard
fileName The name of the file to suppress warnings for, can include wildcards
lineNumber The number of the line to suppress warnings from, can be 0 to represent any line
symbolName The name of the symbol to match warnings for, can include wildcards
"""
errorId = None
fileName = None
lineNumber = None
symbolName = None
def __init__(self, element):
self.errorId = element.get('errorId')
self.fileName = element.get('fileName')
self.lineNumber = element.get('lineNumber')
self.symbolName = element.get('symbolName')
def __repr__(self):
attrs = ['errorId' , "fileName", "lineNumber", "symbolName"]
return "{}({})".format(
"Suppression",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
def isMatch(self, file, line, message, errorId):
if ((self.fileName is None or fnmatch(file, self.fileName))
and (self.lineNumber is None or int(line) == int(self.lineNumber))
and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*'))
and fnmatch(errorId, self.errorId)):
return True
return False
class Configuration:
"""
Configuration class
This class contains the directives, tokens, scopes, functions,
variables, value flows, and suppressions for one configuration.
Attributes:
name Name of the configuration, "" for default
directives List of Directive items
tokenlist List of Token items
scopes List of Scope items
functions List of Function items
variables List of Variable items
valueflow List of ValueFlow values
standards List of Standards values
"""
name = ''
directives = []
tokenlist = []
scopes = []
functions = []
variables = []
valueflow = []
standards = None
def __init__(self, name):
self.name = name
self.directives = []
self.tokenlist = []
self.scopes = []
self.functions = []
self.variables = []
self.valueflow = []
self.standards = Standards()
def set_tokens_links(self):
"""Set next/previous links between tokens."""
prev = None
for token in self.tokenlist:
token.previous = prev
if prev:
prev.next = token
prev = token
def set_id_map(self, arguments):
IdMap = {None: None, '0': None, '00000000': None, '0000000000000000': None}
for token in self.tokenlist:
IdMap[token.Id] = token
for scope in self.scopes:
IdMap[scope.Id] = scope
for function in self.functions:
IdMap[function.Id] = function
for variable in self.variables:
IdMap[variable.Id] = variable
for variable in arguments:
IdMap[variable.Id] = variable
for values in self.valueflow:
IdMap[values.Id] = values.values
for token in self.tokenlist:
token.setId(IdMap)
for scope in self.scopes:
scope.setId(IdMap)
for function in self.functions:
function.setId(IdMap)
for variable in self.variables:
variable.setId(IdMap)
for variable in arguments:
variable.setId(IdMap)
def setIdMap(self, functions_arguments):
"""Set relationships between objects stored in this configuration.
:param functions_arguments: List of Variable objects which are function arguments
"""
self.set_tokens_links()
self.set_id_map(functions_arguments)
class Platform:
"""
Platform class
This class contains type sizes
Attributes:
name Name of the platform
char_bit CHAR_BIT value
short_bit SHORT_BIT value
int_bit INT_BIT value
long_bit LONG_BIT value
long_long_bit LONG_LONG_BIT value
pointer_bit POINTER_BIT value
"""
name = ''
char_bit = 0
short_bit = 0
int_bit = 0
long_bit = 0
long_long_bit = 0
pointer_bit = 0
def __init__(self, platformnode):
self.name = platformnode.get('name')
self.char_bit = int(platformnode.get('char_bit'))
self.short_bit = int(platformnode.get('short_bit'))
self.int_bit = int(platformnode.get('int_bit'))
self.long_bit = int(platformnode.get('long_bit'))
self.long_long_bit = int(platformnode.get('long_long_bit'))
self.pointer_bit = int(platformnode.get('pointer_bit'))
def __repr__(self):
attrs = ["name", "char_bit", "short_bit", "int_bit",
"long_bit", "long_long_bit", "pointer_bit"]
return "{}({})".format(
"Platform",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
class Standards:
"""
Standards class
This class contains versions of standards that were used for the cppcheck
Attributes:
c C Standard used
cpp C++ Standard used
posix If Posix was used
"""
c = ""
cpp = ""
posix = False
def set_c(self, node):
self.c = node.get("version")
def set_cpp(self, node):
self.cpp = node.get("version")
def set_posix(self, node):
self.posix = node.get("posix") is not None
def __repr__(self):
attrs = ["c", "cpp", "posix"]
return "{}({})".format(
"Standards",
", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs))
)
class CppcheckData:
"""
Class that makes cppcheck dump data available
Contains a list of Configuration instances
Attributes:
filename Path to Cppcheck dump file
rawTokens List of rawToken elements
suppressions List of Suppressions
files Source files for elements occurred in this configuration
To iterate through all configurations use such code:
@code
data = cppcheckdata.parsedump(...)
for cfg in data.configurations:
print('cfg: ' + cfg.name)
@endcode
To iterate through all tokens in each configuration use such code:
@code
data = cppcheckdata.parsedump(...)
for cfg in data.configurations:
print('cfg: ' + cfg.name)
code = ''
for token in cfg.tokenlist:
code = code + token.str + ' '
print(' ' + code)
@endcode
To iterate through all scopes (functions, types, etc) use such code:
@code
data = cppcheckdata.parsedump(...)
for cfg in data.configurations:
print('cfg: ' + cfg.name)
for scope in cfg.scopes:
print(' type:' + scope.type + ' name:' + scope.className)
@endcode
"""
def __init__(self, filename):
"""
:param filename: Path to Cppcheck dump file
"""
self.filename = filename
self.rawTokens = []
self.platform = None
self.suppressions = []
self.files = []
platform_done = False
rawtokens_done = False
suppressions_done = False
# Parse general configuration options from <dumps> node
# We intentionally don't clean node resources here because we
# want to serialize in memory only small part of the XML tree.
for event, node in ElementTree.iterparse(self.filename, events=('start', 'end')):
if platform_done and rawtokens_done and suppressions_done:
break
if node.tag == 'platform' and event == 'start':
self.platform = Platform(node)
platform_done = True
elif node.tag == 'rawtokens' and event == 'end':
for rawtokens_node in node:
if rawtokens_node.tag == 'file':
self.files.append(rawtokens_node.get('name'))
elif rawtokens_node.tag == 'tok':
tok = Token(rawtokens_node)
tok.file = self.files[int(rawtokens_node.get('fileIndex'))]
self.rawTokens.append(tok)
rawtokens_done = True
elif node.tag == 'suppressions' and event == 'end':
for suppressions_node in node:
self.suppressions.append(Suppression(suppressions_node))
suppressions_done = True
global current_dumpfile_suppressions
current_dumpfile_suppressions = self.suppressions
# Set links between rawTokens.
for i in range(len(self.rawTokens)-1):
self.rawTokens[i+1].previous = self.rawTokens[i]
self.rawTokens[i].next = self.rawTokens[i+1]
@property
def configurations(self):
"""
Return the list of all available Configuration objects.
"""
return list(self.iterconfigurations())
def iterconfigurations(self):
"""
Create and return iterator for the available Configuration objects.
The iterator loops over all Configurations in the dump file tree, in document order.
"""
cfg = None
cfg_arguments = [] # function arguments for Configuration node initialization
cfg_function = None
cfg_valueflow = None
# Iterating <varlist> in a <scope>.
iter_scope_varlist = False
# Use iterable objects to traverse XML tree for dump files incrementally.
# Iterative approach is required to avoid large memory consumption.
# Calling .clear() is necessary to let the element be garbage collected.
for event, node in ElementTree.iterparse(self.filename, events=('start', 'end')):
# Serialize new configuration node
if node.tag == 'dump':
if event == 'start':
cfg = Configuration(node.get('cfg'))
continue
elif event == 'end':
cfg.setIdMap(cfg_arguments)
yield cfg
cfg = None
cfg_arguments = []
# Parse standards
elif node.tag == "standards" and event == 'start':
continue
elif node.tag == 'c' and event == 'start':
cfg.standards.set_c(node)
elif node.tag == 'cpp' and event == 'start':
cfg.standards.set_cpp(node)
elif node.tag == 'posix' and event == 'start':
cfg.standards.set_posix(node)
# Parse directives list
elif node.tag == 'directive' and event == 'start':
cfg.directives.append(Directive(node))
# Parse tokens
elif node.tag == 'tokenlist' and event == 'start':
continue
elif node.tag == 'token' and event == 'start':
cfg.tokenlist.append(Token(node))
# Parse scopes
elif node.tag == 'scopes' and event == 'start':
continue
elif node.tag == 'scope' and event == 'start':
cfg.scopes.append(Scope(node))
elif node.tag == 'varlist':
if event == 'start':
iter_scope_varlist = True
elif event == 'end':
iter_scope_varlist = False
# Parse functions
elif node.tag == 'functionList' and event == 'start':
continue
elif node.tag == 'function':
if event == 'start':
cfg_function = Function(node, cfg.scopes[-1])
continue
elif event == 'end':
cfg.functions.append(cfg_function)
cfg_function = None
# Parse function arguments
elif node.tag == 'arg' and event == 'start':
arg_nr = int(node.get('nr'))
arg_variable_id = node.get('variable')
cfg_function.argumentId[arg_nr] = arg_variable_id
# Parse variables
elif node.tag == 'var' and event == 'start':
if iter_scope_varlist:
cfg.scopes[-1].varlistId.append(node.get('id'))
else:
var = Variable(node)
if var.nameTokenId:
cfg.variables.append(var)
else:
cfg_arguments.append(var)
# Parse valueflows (list of values)
elif node.tag == 'valueflow' and event == 'start':
continue
elif node.tag == 'values':
if event == 'start':
cfg_valueflow = ValueFlow(node)