@@ -1237,27 +1237,30 @@ def __init__(self, filename):
12371237 # Parse general configuration options from <dumps> node
12381238 # We intentionally don't clean node resources here because we
12391239 # 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
1240+ # The file handle is closed explicitly since the iterator may
1241+ # break early and Python 3.13+ warns about unclosed iterators.
1242+ with open (self .filename , 'rb' ) as dumpfile :
1243+ for event , node in ElementTree .iterparse (dumpfile , events = ('start' , 'end' )):
1244+ if platform_done and rawtokens_done and suppressions_done :
1245+ break
1246+ if node .tag == 'dumps' :
1247+ self .language = node .get ('language' )
1248+ if node .tag == 'platform' and event == 'start' :
1249+ self .platform = Platform (node )
1250+ platform_done = True
1251+ elif node .tag == 'rawtokens' and event == 'end' :
1252+ for rawtokens_node in node :
1253+ if rawtokens_node .tag == 'file' :
1254+ self .files .append (rawtokens_node .get ('name' ))
1255+ elif rawtokens_node .tag == 'tok' :
1256+ tok = Token (rawtokens_node )
1257+ tok .file = self .files [int (rawtokens_node .get ('fileIndex' ))]
1258+ self .rawTokens .append (tok )
1259+ rawtokens_done = True
1260+ elif node .tag == 'suppressions' and event == 'end' :
1261+ for suppressions_node in node :
1262+ self .suppressions .append (Suppression (suppressions_node ))
1263+ suppressions_done = True
12611264
12621265 global current_dumpfile_suppressions
12631266 current_dumpfile_suppressions = self .suppressions
@@ -1296,126 +1299,130 @@ def iterconfigurations(self):
12961299 # Use iterable objects to traverse XML tree for dump files incrementally.
12971300 # Iterative approach is required to avoid large memory consumption.
12981301 # 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' ))
1302+ # The file handle is closed explicitly since the generator may
1303+ # be closed before the iterator is exhausted (Python 3.13+
1304+ # warns about unclosed iterators).
1305+ with open (self .filename , 'rb' ) as dumpfile :
1306+ for event , node in ElementTree .iterparse (dumpfile , events = ('start' , 'end' )):
1307+ # Serialize new <dump> node contents
1308+ if node .tag == 'dump' :
1309+ if event == 'start' :
1310+ cfg = Configuration (node .get ('cfg' ))
1311+ continue
1312+ if event == 'end' :
1313+ cfg .setIdMap (cfg_arguments )
1314+ yield cfg
1315+ cfg = None
1316+ cfg_arguments = []
1317+
1318+ elif node .tag == 'clang-warning' and event == 'start' :
1319+ cfg .clang_warnings .append ({'file' : node .get ('file' ),
1320+ 'line' : int (node .get ('line' )),
1321+ 'column' : int (node .get ('column' )),
1322+ 'message' : node .get ('message' )})
1323+ # Parse standards
1324+ elif node .tag == "standards" and event == 'start' :
13041325 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 and not iter_typedef_info :
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 ])
1326+ elif node .tag == 'c' and event == 'start' :
1327+ cfg .standards .set_c (node )
1328+ elif node .tag == 'cpp' and event == 'start' :
1329+ cfg .standards .set_cpp (node )
1330+ elif node .tag == 'posix' and event == 'start' :
1331+ cfg .standards .set_posix (node )
1332+
1333+ # Parse directives list
1334+ elif node .tag == 'directive' :
1335+ if event == 'start' :
1336+ cfg .directives .append (Directive (node ))
1337+ iter_directive = True
1338+ elif event == 'end' :
1339+ iter_directive = False
1340+ # Parse macro usage
1341+ elif node .tag == 'macro' and event == 'start' :
1342+ cfg .macro_usage .append (MacroUsage (node ))
1343+
1344+ # Preprocessor #if/#elif condition
1345+ elif node .tag == "if-cond" and event == 'start' :
1346+ cfg .preprocessor_if_conditions .append (PreprocessorIfCondition (node ))
1347+
1348+ # Parse tokens
1349+ elif node .tag == 'tokenlist' and event == 'start' :
13641350 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 )
1351+ elif node .tag == 'token' and event == 'start' and not iter_directive and not iter_typedef_info :
1352+ cfg .tokenlist .append (Token (node ))
1353+
1354+ # Parse scopes
1355+ elif node .tag == 'scopes' and event == 'start' :
1356+ continue
1357+ elif node .tag == 'scope' and event == 'start' :
1358+ cfg .scopes .append (Scope (node ))
1359+ elif node .tag == 'varlist' :
1360+ if event == 'start' :
1361+ iter_scope_varlist = True
1362+ elif event == 'end' :
1363+ iter_scope_varlist = False
1364+
1365+ # Parse functions
1366+ elif node .tag == 'functionList' and event == 'start' :
1367+ continue
1368+ elif node .tag == 'function' :
1369+ if event == 'start' :
1370+ cfg_function = Function (node , cfg .scopes [- 1 ])
1371+ continue
1372+ if event == 'end' :
1373+ cfg .functions .append (cfg_function )
1374+ cfg_function = None
1375+
1376+ # Parse function arguments
1377+ elif node .tag == 'arg' and event == 'start' :
1378+ arg_nr = int (node .get ('nr' ))
1379+ arg_variable_id = node .get ('variable' )
1380+ cfg_function .argumentId [arg_nr ] = arg_variable_id
1381+
1382+ # Parse variables
1383+ elif node .tag == 'var' and event == 'start' :
1384+ if iter_scope_varlist :
1385+ cfg .scopes [- 1 ].varlistId .append (node .get ('id' ))
13831386 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 )
1387+ var = Variable (node )
1388+ if var .nameTokenId :
1389+ cfg .variables .append (var )
1390+ else :
1391+ cfg_arguments .append (var )
1392+
1393+ # Parse containers
1394+ elif node .tag == 'containers' and event == 'start' :
14081395 continue
1409- if event == 'end' :
1410- cfg .valueflow .append (cfg_valueflow )
1411- cfg_valueflow = None
1396+ elif node .tag == 'container' and event == 'start' :
1397+ cfg .containers .append (Container (node ))
1398+
1399+ # Parse typedef info
1400+ elif node .tag == 'typedef-info' :
1401+ iter_typedef_info = (event == 'start' )
1402+ elif iter_typedef_info and node .tag == 'info' and event == 'start' :
1403+ cfg .typedefInfo .append (TypedefInfo (node ))
14121404
1413- # Parse values
1414- elif node .tag == 'value ' and event == 'start' :
1415- cfg_valueflow . values .append (Value (node ))
1405+ # Parse template-token
1406+ # elif node.tag == 'TokenAndName ' and event == 'start': #todo add processing of containers
1407+ # cfg.containers .append(Container (node))
14161408
1417- # Remove links to the sibling nodes
1418- node .clear ()
1409+ # Parse valueflows (list of values)
1410+ elif node .tag == 'valueflow' and event == 'start' :
1411+ continue
1412+ elif node .tag == 'values' :
1413+ if event == 'start' :
1414+ cfg_valueflow = ValueFlow (node )
1415+ continue
1416+ if event == 'end' :
1417+ cfg .valueflow .append (cfg_valueflow )
1418+ cfg_valueflow = None
1419+
1420+ # Parse values
1421+ elif node .tag == 'value' and event == 'start' :
1422+ cfg_valueflow .values .append (Value (node ))
1423+
1424+ # Remove links to the sibling nodes
1425+ node .clear ()
14191426
14201427 def __repr__ (self ):
14211428 attrs = ["configurations" , "platform" ]
0 commit comments