11
11
from sphinx .util import logging
12
12
13
13
if TYPE_CHECKING :
14
- from collections .abc import Iterator
14
+ from collections .abc import Iterator , Sequence
15
15
16
16
from typing_extensions import Self
17
17
@@ -32,7 +32,7 @@ def __str__(self) -> str:
32
32
33
33
34
34
class SymbolLookupResult :
35
- def __init__ (self , symbols : list [Symbol ], parentSymbol : Symbol ,
35
+ def __init__ (self , symbols : Sequence [Symbol ], parentSymbol : Symbol ,
36
36
ident : ASTIdentifier ) -> None :
37
37
self .symbols = symbols
38
38
self .parentSymbol = parentSymbol
@@ -101,25 +101,43 @@ def __init__(
101
101
self .isRedeclaration = False
102
102
self ._assert_invariants ()
103
103
104
- # Remember to modify Symbol.remove if modifications to the parent change.
104
+ # These properties store the same children for different access
105
+ # patterns. Symbol._add_child and Symbol._remove_child should be
106
+ # used for modifying them.
105
107
self ._childrenByName : dict [str , Symbol ] = {}
106
- self ._childrenByDocname : dict [str , list [ Symbol ]] = {}
107
- self ._anonChildren : list [Symbol ] = []
108
- # note: _children includes _anonChildren
108
+ self ._childrenByDocname : dict [str , dict [ str , Symbol ]] = {}
109
+ self ._anonChildren : set [Symbol ] = set ()
110
+
109
111
if self .parent :
110
- self .parent ._childrenByName [str (self .ident )] = self
111
- if self .docname in self .parent ._childrenByDocname :
112
- self .parent ._childrenByDocname [self .docname ].append (self )
113
- else :
114
- self .parent ._childrenByDocname [self .docname ] = [self ]
115
- if ident .is_anon ():
116
- self .parent ._anonChildren .append (self )
112
+ self .parent ._add_child (self )
117
113
if self .declaration :
118
114
self .declaration .symbol = self
119
115
120
116
# Do symbol addition after self._children has been initialised.
121
117
self ._add_function_params ()
122
118
119
+ @property
120
+ def _children (self ) -> Sequence [Symbol ]:
121
+ return self ._childrenByName .values ()
122
+
123
+ def _add_child (self , child : Symbol ) -> None :
124
+ name = child .ident .name
125
+ self ._childrenByName [name ] = child
126
+ if child .docname not in self ._childrenByDocname :
127
+ self ._childrenByDocname [child .docname ] = {}
128
+ self ._childrenByDocname [child .docname ][name ] = child
129
+ if child .ident .is_anon ():
130
+ self ._anonChildren .add (child )
131
+
132
+ def _remove_child (self , child : Symbol ) -> None :
133
+ name = child .ident .name
134
+ self ._childrenByName .pop (name )
135
+ siblings = self ._childrenByDocname .get (child .docname , {})
136
+ if name in siblings :
137
+ siblings .pop (name )
138
+ if child .ident .is_anon () and child in self ._anonChildren :
139
+ self ._anonChildren .remove (child )
140
+
123
141
def _fill_empty (self , declaration : ASTDeclaration , docname : str , line : int ) -> None :
124
142
self ._assert_invariants ()
125
143
assert self .declaration is None
@@ -160,23 +178,16 @@ def _add_function_params(self) -> None:
160
178
Symbol .debug_indent -= 1
161
179
162
180
def remove (self ) -> None :
163
- if self .parent is None :
164
- return
165
- name = str (self .ident )
166
- assert name in self .parent ._childrenByName
167
- del self .parent ._childrenByName [name ]
168
- if self .docname in self .parent ._childrenByDocname :
169
- del self .parent ._childrenByDocname [self .docname ]
170
- if self .ident .is_anon ():
171
- self .parent ._anonChildren .remove (self )
172
- self .parent = None
181
+ if self .parent :
182
+ self .parent ._remove_child (self )
183
+ self .parent = None
173
184
174
185
def clear_doc (self , docname : str ) -> None :
175
186
if docname not in self ._childrenByDocname :
176
- for child in self ._childrenByName . values () :
187
+ for child in self ._children :
177
188
child .clear_doc (docname )
178
189
return
179
- for sChild in self ._childrenByDocname [docname ]:
190
+ for sChild in self ._childrenByDocname [docname ]. values () :
180
191
sChild .declaration = None
181
192
sChild .docname = None
182
193
sChild .line = None
@@ -186,29 +197,18 @@ def clear_doc(self, docname: str) -> None:
186
197
sChild .siblingBelow .siblingAbove = sChild .siblingAbove
187
198
sChild .siblingAbove = None
188
199
sChild .siblingBelow = None
189
- name = str (sChild .ident )
190
- if name in self ._childrenByName :
191
- del self ._childrenByName [name ]
192
- if sChild .ident .is_anon ():
193
- self ._anonChildren .remove (sChild )
200
+
201
+ self ._remove_child (sChild )
194
202
del self ._childrenByDocname [docname ]
195
203
196
204
def get_all_symbols (self ) -> Iterator [Symbol ]:
197
205
yield self
198
- for sChild in self ._childrenByName . values () :
206
+ for sChild in self ._children :
199
207
yield from sChild .get_all_symbols ()
200
208
201
209
@property
202
210
def children (self ) -> Iterator [Symbol ]:
203
- yield from self ._childrenByName .values ()
204
-
205
- @property
206
- def children_recurse_anon (self ) -> Iterator [Symbol ]:
207
- for c in self ._childrenByName .values ():
208
- yield c
209
- if not c .ident .is_anon ():
210
- continue
211
- yield from c .children_recurse_anon
211
+ yield from self ._children
212
212
213
213
def get_lookup_key (self ) -> LookupKey :
214
214
# The pickle files for the environment and for each document are distinct.
@@ -275,37 +275,46 @@ def _symbol_lookup(
275
275
# walk up until we find the first identifier
276
276
firstName = names [0 ]
277
277
while parentSymbol .parent :
278
- if str ( firstName ) in parentSymbol ._childrenByName :
278
+ if firstName . name in parentSymbol ._childrenByName :
279
279
break
280
280
parentSymbol = parentSymbol .parent
281
281
282
+ if Symbol .debug_lookup :
283
+ Symbol .debug_print ("starting point:" )
284
+ logger .debug (parentSymbol .to_string (Symbol .debug_indent + 1 ), end = "" )
285
+
282
286
# and now the actual lookup
283
287
for ident in names [:- 1 ]:
284
- name = str ( ident )
288
+ name = ident . name
285
289
if name in parentSymbol ._childrenByName :
286
290
symbol = parentSymbol ._childrenByName [name ]
287
291
else :
288
292
symbol = onMissingQualifiedSymbol (parentSymbol , ident )
289
293
if symbol is None :
294
+ if Symbol .debug_lookup :
295
+ Symbol .debug_indent -= 2
290
296
return None
291
297
parentSymbol = symbol
292
298
299
+ if Symbol .debug_lookup :
300
+ Symbol .debug_print ("handle last name from:" )
301
+ logger .debug (parentSymbol .to_string (Symbol .debug_indent + 1 ), end = "" )
302
+
293
303
# handle the last name
294
304
ident = names [- 1 ]
295
- name = str (ident )
296
- symbol = None
297
- if name in parentSymbol ._childrenByName :
298
- symbol = parentSymbol ._childrenByName [name ]
299
-
305
+ name = ident .name
306
+ symbol = parentSymbol ._childrenByName .get (name )
300
307
if not symbol and recurseInAnon :
301
308
for child in parentSymbol ._anonChildren :
302
309
if name in child ._childrenByName :
303
310
symbol = child ._childrenByName [name ]
304
311
break
305
- if symbol :
306
- return SymbolLookupResult ([symbol ], parentSymbol , ident )
307
- else :
308
- return SymbolLookupResult ([], parentSymbol , ident )
312
+
313
+ if Symbol .debug_lookup :
314
+ Symbol .debug_indent -= 2
315
+
316
+ result = [symbol ] if symbol else []
317
+ return SymbolLookupResult (result , parentSymbol , ident )
309
318
310
319
def _add_symbols (
311
320
self ,
@@ -481,12 +490,12 @@ def merge_with(self, other: Symbol, docnames: list[str],
481
490
Symbol .debug_print ("merge_with:" )
482
491
483
492
assert other is not None
484
- for otherChild in other ._childrenByName . values () :
485
- otherName = str ( otherChild .ident )
493
+ for otherChild in other ._children :
494
+ otherName = otherChild .ident . name
486
495
if otherName not in self ._childrenByName :
487
496
# TODO: hmm, should we prune by docnames?
488
- self ._childrenByName [otherName ] = otherChild
489
497
otherChild .parent = self
498
+ self ._add_child (otherChild )
490
499
otherChild ._assert_invariants ()
491
500
continue
492
501
ourChild = self ._childrenByName [otherName ]
@@ -556,7 +565,7 @@ def find_identifier(self, ident: ASTIdentifier,
556
565
Symbol .debug_indent -= 2
557
566
if matchSelf and current .ident == ident :
558
567
return current
559
- name = str ( ident )
568
+ name = ident . name
560
569
if name in current ._childrenByName :
561
570
return current ._childrenByName [name ]
562
571
if recurseInAnon :
@@ -575,22 +584,16 @@ def direct_lookup(self, key: LookupKey) -> Symbol | None:
575
584
Symbol .debug_indent += 1
576
585
s = self
577
586
for ident , id_ in key .data :
578
- res = None
579
- name = str (ident )
580
- if name in s ._childrenByName :
581
- res = s ._childrenByName [name ]
582
- s = res
587
+ s = s ._childrenByName .get (ident .name )
583
588
if Symbol .debug_lookup :
584
- Symbol .debug_print ("name: " , name )
589
+ Symbol .debug_print ("name: " , ident . name )
585
590
Symbol .debug_print ("id: " , id_ )
586
591
if s is not None :
587
592
logger .debug (s .to_string (Symbol .debug_indent + 1 ), end = "" )
588
593
else :
589
594
Symbol .debug_print ("not found" )
590
595
if s is None :
591
- if Symbol .debug_lookup :
592
- Symbol .debug_indent -= 2
593
- return None
596
+ break
594
597
if Symbol .debug_lookup :
595
598
Symbol .debug_indent -= 2
596
599
return s
@@ -630,7 +633,7 @@ def to_string(self, indent: int) -> str:
630
633
res .append ('::' )
631
634
else :
632
635
if self .ident :
633
- res .append (str ( self .ident ) )
636
+ res .append (self .ident . name )
634
637
else :
635
638
res .append (str (self .declaration ))
636
639
if self .declaration :
@@ -646,5 +649,4 @@ def to_string(self, indent: int) -> str:
646
649
return '' .join (res )
647
650
648
651
def dump (self , indent : int ) -> str :
649
- return '' .join ([self .to_string (indent ),
650
- * (c .dump (indent + 1 ) for c in self ._childrenByName .values ())])
652
+ return '' .join ([self .to_string (indent ), * (c .dump (indent + 1 ) for c in self ._children )])
0 commit comments