1111from sphinx .util import logging
1212
1313if TYPE_CHECKING :
14- from collections .abc import Iterator
14+ from collections .abc import Iterator , Sequence
1515
1616 from typing_extensions import Self
1717
@@ -32,7 +32,7 @@ def __str__(self) -> str:
3232
3333
3434class SymbolLookupResult :
35- def __init__ (self , symbols : list [Symbol ], parentSymbol : Symbol ,
35+ def __init__ (self , symbols : Sequence [Symbol ], parentSymbol : Symbol ,
3636 ident : ASTIdentifier ) -> None :
3737 self .symbols = symbols
3838 self .parentSymbol = parentSymbol
@@ -102,25 +102,43 @@ def __init__(
102102 self .isRedeclaration = False
103103 self ._assert_invariants ()
104104
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.
106108 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+
110112 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 )
118114 if self .declaration :
119115 self .declaration .symbol = self
120116
121117 # Do symbol addition after self._children has been initialised.
122118 self ._add_function_params ()
123119
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+
124142 def _fill_empty (self , declaration : ASTDeclaration , docname : str , line : int ) -> None :
125143 self ._assert_invariants ()
126144 assert self .declaration is None
@@ -161,23 +179,16 @@ def _add_function_params(self) -> None:
161179 Symbol .debug_indent -= 1
162180
163181 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
174185
175186 def clear_doc (self , docname : str ) -> None :
176187 if docname not in self ._childrenByDocname :
177- for child in self ._childrenByName . values () :
188+ for child in self ._children :
178189 child .clear_doc (docname )
179190 return
180- for sChild in self ._childrenByDocname [docname ]:
191+ for sChild in self ._childrenByDocname [docname ]. values () :
181192 sChild .declaration = None
182193 sChild .docname = None
183194 sChild .line = None
@@ -187,29 +198,18 @@ def clear_doc(self, docname: str) -> None:
187198 sChild .siblingBelow .siblingAbove = sChild .siblingAbove
188199 sChild .siblingAbove = None
189200 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 )
195203 del self ._childrenByDocname [docname ]
196204
197205 def get_all_symbols (self ) -> Iterator [Symbol ]:
198206 yield self
199- for sChild in self ._childrenByName . values () :
207+ for sChild in self ._children :
200208 yield from sChild .get_all_symbols ()
201209
202210 @property
203211 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
213213
214214 def get_lookup_key (self ) -> LookupKey :
215215 # The pickle files for the environment and for each document are distinct.
@@ -276,7 +276,7 @@ def _symbol_lookup(
276276 # walk up until we find the first identifier
277277 firstName = names [0 ]
278278 while parentSymbol .parent :
279- if str ( firstName ) in parentSymbol ._childrenByName :
279+ if firstName . name in parentSymbol ._childrenByName :
280280 break
281281 parentSymbol = parentSymbol .parent
282282
@@ -286,12 +286,14 @@ def _symbol_lookup(
286286
287287 # and now the actual lookup
288288 for ident in names [:- 1 ]:
289- name = str ( ident )
289+ name = ident . name
290290 if name in parentSymbol ._childrenByName :
291291 symbol = parentSymbol ._childrenByName [name ]
292292 else :
293293 symbol = onMissingQualifiedSymbol (parentSymbol , ident )
294294 if symbol is None :
295+ if Symbol .debug_lookup :
296+ Symbol .debug_indent -= 2
295297 return None
296298 parentSymbol = symbol
297299
@@ -301,20 +303,19 @@ def _symbol_lookup(
301303
302304 # handle the last name
303305 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 )
309308 if not symbol and recurseInAnon :
310309 for child in parentSymbol ._anonChildren :
311310 if name in child ._childrenByName :
312311 symbol = child ._childrenByName [name ]
313312 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 )
318319
319320 def _add_symbols (
320321 self ,
@@ -490,12 +491,12 @@ def merge_with(self, other: Symbol, docnames: list[str],
490491 Symbol .debug_print ("merge_with:" )
491492
492493 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
495496 if otherName not in self ._childrenByName :
496497 # TODO: hmm, should we prune by docnames?
497- self ._childrenByName [otherName ] = otherChild
498498 otherChild .parent = self
499+ self ._add_child (otherChild )
499500 otherChild ._assert_invariants ()
500501 continue
501502 ourChild = self ._childrenByName [otherName ]
@@ -565,7 +566,7 @@ def find_identifier(self, ident: ASTIdentifier,
565566 Symbol .debug_indent -= 2
566567 if matchSelf and current .ident == ident :
567568 return current
568- name = str ( ident )
569+ name = ident . name
569570 if name in current ._childrenByName :
570571 return current ._childrenByName [name ]
571572 if recurseInAnon :
@@ -584,22 +585,16 @@ def direct_lookup(self, key: LookupKey) -> Symbol | None:
584585 Symbol .debug_indent += 1
585586 s = self
586587 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 )
592589 if Symbol .debug_lookup :
593- Symbol .debug_print ("name: " , name )
590+ Symbol .debug_print ("name: " , ident . name )
594591 Symbol .debug_print ("id: " , id_ )
595592 if s is not None :
596593 logger .debug (s .to_string (Symbol .debug_indent + 1 , addEndNewline = False ))
597594 else :
598595 Symbol .debug_print ("not found" )
599596 if s is None :
600- if Symbol .debug_lookup :
601- Symbol .debug_indent -= 2
602- return None
597+ break
603598 if Symbol .debug_lookup :
604599 Symbol .debug_indent -= 2
605600 return s
@@ -639,7 +634,7 @@ def to_string(self, indent: int, *, addEndNewline: bool = True) -> str:
639634 res .append ('::' )
640635 else :
641636 if self .ident :
642- res .append (str ( self .ident ) )
637+ res .append (self .ident . name )
643638 else :
644639 res .append (str (self .declaration ))
645640 if self .declaration :
@@ -656,5 +651,4 @@ def to_string(self, indent: int, *, addEndNewline: bool = True) -> str:
656651 return '' .join (res )
657652
658653 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