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
@@ -102,25 +102,43 @@ def __init__(
102
102
self .isRedeclaration = False
103
103
self ._assert_invariants ()
104
104
105
- # Remember to modify Symbol.remove if modifications to the parent change.
105
+ # These properties store the same children for different access
106
+ # patterns. Symbol._add_child and Symbol._remove_child should be
107
+ # used for modifying them.
106
108
self ._childrenByName : dict [str , Symbol ] = {}
107
- self ._childrenByDocname : dict [str , list [ Symbol ]] = {}
108
- self ._anonChildren : list [Symbol ] = []
109
- # note: _children includes _anonChildren
109
+ self ._childrenByDocname : dict [str , dict [ str , Symbol ]] = {}
110
+ self ._anonChildren : set [Symbol ] = set ()
111
+
110
112
if self .parent :
111
- self .parent ._childrenByName [str (self .ident )] = self
112
- if self .docname in self .parent ._childrenByDocname :
113
- self .parent ._childrenByDocname [self .docname ].append (self )
114
- else :
115
- self .parent ._childrenByDocname [self .docname ] = [self ]
116
- if ident .is_anon ():
117
- self .parent ._anonChildren .append (self )
113
+ self .parent ._add_child (self )
118
114
if self .declaration :
119
115
self .declaration .symbol = self
120
116
121
117
# Do symbol addition after self._children has been initialised.
122
118
self ._add_function_params ()
123
119
120
+ @property
121
+ def _children (self ) -> Sequence [Symbol ]:
122
+ return self ._childrenByName .values ()
123
+
124
+ def _add_child (self , child : Symbol ) -> None :
125
+ name = child .ident .name
126
+ self ._childrenByName [name ] = child
127
+ if child .docname not in self ._childrenByDocname :
128
+ self ._childrenByDocname [child .docname ] = {}
129
+ self ._childrenByDocname [child .docname ][name ] = child
130
+ if child .ident .is_anon ():
131
+ self ._anonChildren .add (child )
132
+
133
+ def _remove_child (self , child : Symbol ) -> None :
134
+ name = child .ident .name
135
+ self ._childrenByName .pop (name )
136
+ siblings = self ._childrenByDocname .get (child .docname , {})
137
+ if name in siblings :
138
+ siblings .pop (name )
139
+ if child .ident .is_anon () and child in self ._anonChildren :
140
+ self ._anonChildren .remove (child )
141
+
124
142
def _fill_empty (self , declaration : ASTDeclaration , docname : str , line : int ) -> None :
125
143
self ._assert_invariants ()
126
144
assert self .declaration is None
@@ -161,23 +179,16 @@ def _add_function_params(self) -> None:
161
179
Symbol .debug_indent -= 1
162
180
163
181
def remove (self ) -> None :
164
- if self .parent is None :
165
- return
166
- name = str (self .ident )
167
- assert name in self .parent ._childrenByName
168
- del self .parent ._childrenByName [name ]
169
- if self .docname in self .parent ._childrenByDocname :
170
- del self .parent ._childrenByDocname [self .docname ]
171
- if self .ident .is_anon ():
172
- self .parent ._anonChildren .remove (self )
173
- self .parent = None
182
+ if self .parent :
183
+ self .parent ._remove_child (self )
184
+ self .parent = None
174
185
175
186
def clear_doc (self , docname : str ) -> None :
176
187
if docname not in self ._childrenByDocname :
177
- for child in self ._childrenByName . values () :
188
+ for child in self ._children :
178
189
child .clear_doc (docname )
179
190
return
180
- for sChild in self ._childrenByDocname [docname ]:
191
+ for sChild in self ._childrenByDocname [docname ]. values () :
181
192
sChild .declaration = None
182
193
sChild .docname = None
183
194
sChild .line = None
@@ -187,29 +198,18 @@ def clear_doc(self, docname: str) -> None:
187
198
sChild .siblingBelow .siblingAbove = sChild .siblingAbove
188
199
sChild .siblingAbove = None
189
200
sChild .siblingBelow = None
190
- name = str (sChild .ident )
191
- if name in self ._childrenByName :
192
- del self ._childrenByName [name ]
193
- if sChild .ident .is_anon ():
194
- self ._anonChildren .remove (sChild )
201
+
202
+ self ._remove_child (sChild )
195
203
del self ._childrenByDocname [docname ]
196
204
197
205
def get_all_symbols (self ) -> Iterator [Symbol ]:
198
206
yield self
199
- for sChild in self ._childrenByName . values () :
207
+ for sChild in self ._children :
200
208
yield from sChild .get_all_symbols ()
201
209
202
210
@property
203
211
def children (self ) -> Iterator [Symbol ]:
204
- yield from self ._childrenByName .values ()
205
-
206
- @property
207
- def children_recurse_anon (self ) -> Iterator [Symbol ]:
208
- for c in self ._childrenByName .values ():
209
- yield c
210
- if not c .ident .is_anon ():
211
- continue
212
- yield from c .children_recurse_anon
212
+ yield from self ._children
213
213
214
214
def get_lookup_key (self ) -> LookupKey :
215
215
# The pickle files for the environment and for each document are distinct.
@@ -276,7 +276,7 @@ def _symbol_lookup(
276
276
# walk up until we find the first identifier
277
277
firstName = names [0 ]
278
278
while parentSymbol .parent :
279
- if str ( firstName ) in parentSymbol ._childrenByName :
279
+ if firstName . name in parentSymbol ._childrenByName :
280
280
break
281
281
parentSymbol = parentSymbol .parent
282
282
@@ -286,12 +286,14 @@ def _symbol_lookup(
286
286
287
287
# and now the actual lookup
288
288
for ident in names [:- 1 ]:
289
- name = str ( ident )
289
+ name = ident . name
290
290
if name in parentSymbol ._childrenByName :
291
291
symbol = parentSymbol ._childrenByName [name ]
292
292
else :
293
293
symbol = onMissingQualifiedSymbol (parentSymbol , ident )
294
294
if symbol is None :
295
+ if Symbol .debug_lookup :
296
+ Symbol .debug_indent -= 2
295
297
return None
296
298
parentSymbol = symbol
297
299
@@ -301,20 +303,19 @@ def _symbol_lookup(
301
303
302
304
# handle the last name
303
305
ident = names [- 1 ]
304
- name = str (ident )
305
- symbol = None
306
- if name in parentSymbol ._childrenByName :
307
- symbol = parentSymbol ._childrenByName [name ]
308
-
306
+ name = ident .name
307
+ symbol = parentSymbol ._childrenByName .get (name )
309
308
if not symbol and recurseInAnon :
310
309
for child in parentSymbol ._anonChildren :
311
310
if name in child ._childrenByName :
312
311
symbol = child ._childrenByName [name ]
313
312
break
314
- if symbol :
315
- return SymbolLookupResult ([symbol ], parentSymbol , ident )
316
- else :
317
- return SymbolLookupResult ([], parentSymbol , ident )
313
+
314
+ if Symbol .debug_lookup :
315
+ Symbol .debug_indent -= 2
316
+
317
+ result = [symbol ] if symbol else []
318
+ return SymbolLookupResult (result , parentSymbol , ident )
318
319
319
320
def _add_symbols (
320
321
self ,
@@ -490,12 +491,12 @@ def merge_with(self, other: Symbol, docnames: list[str],
490
491
Symbol .debug_print ("merge_with:" )
491
492
492
493
assert other is not None
493
- for otherChild in other ._childrenByName . values () :
494
- otherName = str ( otherChild .ident )
494
+ for otherChild in other ._children :
495
+ otherName = otherChild .ident . name
495
496
if otherName not in self ._childrenByName :
496
497
# TODO: hmm, should we prune by docnames?
497
- self ._childrenByName [otherName ] = otherChild
498
498
otherChild .parent = self
499
+ self ._add_child (otherChild )
499
500
otherChild ._assert_invariants ()
500
501
continue
501
502
ourChild = self ._childrenByName [otherName ]
@@ -565,7 +566,7 @@ def find_identifier(self, ident: ASTIdentifier,
565
566
Symbol .debug_indent -= 2
566
567
if matchSelf and current .ident == ident :
567
568
return current
568
- name = str ( ident )
569
+ name = ident . name
569
570
if name in current ._childrenByName :
570
571
return current ._childrenByName [name ]
571
572
if recurseInAnon :
@@ -584,22 +585,16 @@ def direct_lookup(self, key: LookupKey) -> Symbol | None:
584
585
Symbol .debug_indent += 1
585
586
s = self
586
587
for ident , id_ in key .data :
587
- res = None
588
- name = str (ident )
589
- if name in s ._childrenByName :
590
- res = s ._childrenByName [name ]
591
- s = res
588
+ s = s ._childrenByName .get (ident .name )
592
589
if Symbol .debug_lookup :
593
- Symbol .debug_print ("name: " , name )
590
+ Symbol .debug_print ("name: " , ident . name )
594
591
Symbol .debug_print ("id: " , id_ )
595
592
if s is not None :
596
593
logger .debug (s .to_string (Symbol .debug_indent + 1 , addEndNewline = False ))
597
594
else :
598
595
Symbol .debug_print ("not found" )
599
596
if s is None :
600
- if Symbol .debug_lookup :
601
- Symbol .debug_indent -= 2
602
- return None
597
+ break
603
598
if Symbol .debug_lookup :
604
599
Symbol .debug_indent -= 2
605
600
return s
@@ -639,7 +634,7 @@ def to_string(self, indent: int, *, addEndNewline: bool = True) -> str:
639
634
res .append ('::' )
640
635
else :
641
636
if self .ident :
642
- res .append (str ( self .ident ) )
637
+ res .append (self .ident . name )
643
638
else :
644
639
res .append (str (self .declaration ))
645
640
if self .declaration :
@@ -656,5 +651,4 @@ def to_string(self, indent: int, *, addEndNewline: bool = True) -> str:
656
651
return '' .join (res )
657
652
658
653
def dump (self , indent : int ) -> str :
659
- return '' .join ([self .to_string (indent ),
660
- * (c .dump (indent + 1 ) for c in self ._childrenByName .values ())])
654
+ return '' .join ([self .to_string (indent ), * (c .dump (indent + 1 ) for c in self ._children )])
0 commit comments