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
@@ -101,25 +101,43 @@ def __init__(
101101 self .isRedeclaration = False
102102 self ._assert_invariants ()
103103
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.
105107 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+
109111 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 )
117113 if self .declaration :
118114 self .declaration .symbol = self
119115
120116 # Do symbol addition after self._children has been initialised.
121117 self ._add_function_params ()
122118
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+
123141 def _fill_empty (self , declaration : ASTDeclaration , docname : str , line : int ) -> None :
124142 self ._assert_invariants ()
125143 assert self .declaration is None
@@ -160,23 +178,16 @@ def _add_function_params(self) -> None:
160178 Symbol .debug_indent -= 1
161179
162180 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
173184
174185 def clear_doc (self , docname : str ) -> None :
175186 if docname not in self ._childrenByDocname :
176- for child in self ._childrenByName . values () :
187+ for child in self ._children :
177188 child .clear_doc (docname )
178189 return
179- for sChild in self ._childrenByDocname [docname ]:
190+ for sChild in self ._childrenByDocname [docname ]. values () :
180191 sChild .declaration = None
181192 sChild .docname = None
182193 sChild .line = None
@@ -186,29 +197,18 @@ def clear_doc(self, docname: str) -> None:
186197 sChild .siblingBelow .siblingAbove = sChild .siblingAbove
187198 sChild .siblingAbove = None
188199 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 )
194202 del self ._childrenByDocname [docname ]
195203
196204 def get_all_symbols (self ) -> Iterator [Symbol ]:
197205 yield self
198- for sChild in self ._childrenByName . values () :
206+ for sChild in self ._children :
199207 yield from sChild .get_all_symbols ()
200208
201209 @property
202210 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
212212
213213 def get_lookup_key (self ) -> LookupKey :
214214 # The pickle files for the environment and for each document are distinct.
@@ -275,37 +275,46 @@ def _symbol_lookup(
275275 # walk up until we find the first identifier
276276 firstName = names [0 ]
277277 while parentSymbol .parent :
278- if str ( firstName ) in parentSymbol ._childrenByName :
278+ if firstName . name in parentSymbol ._childrenByName :
279279 break
280280 parentSymbol = parentSymbol .parent
281281
282+ if Symbol .debug_lookup :
283+ Symbol .debug_print ("starting point:" )
284+ logger .debug (parentSymbol .to_string (Symbol .debug_indent + 1 ), end = "" )
285+
282286 # and now the actual lookup
283287 for ident in names [:- 1 ]:
284- name = str ( ident )
288+ name = ident . name
285289 if name in parentSymbol ._childrenByName :
286290 symbol = parentSymbol ._childrenByName [name ]
287291 else :
288292 symbol = onMissingQualifiedSymbol (parentSymbol , ident )
289293 if symbol is None :
294+ if Symbol .debug_lookup :
295+ Symbol .debug_indent -= 2
290296 return None
291297 parentSymbol = symbol
292298
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+
293303 # handle the last name
294304 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 )
300307 if not symbol and recurseInAnon :
301308 for child in parentSymbol ._anonChildren :
302309 if name in child ._childrenByName :
303310 symbol = child ._childrenByName [name ]
304311 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 )
309318
310319 def _add_symbols (
311320 self ,
@@ -481,12 +490,12 @@ def merge_with(self, other: Symbol, docnames: list[str],
481490 Symbol .debug_print ("merge_with:" )
482491
483492 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
486495 if otherName not in self ._childrenByName :
487496 # TODO: hmm, should we prune by docnames?
488- self ._childrenByName [otherName ] = otherChild
489497 otherChild .parent = self
498+ self ._add_child (otherChild )
490499 otherChild ._assert_invariants ()
491500 continue
492501 ourChild = self ._childrenByName [otherName ]
@@ -556,7 +565,7 @@ def find_identifier(self, ident: ASTIdentifier,
556565 Symbol .debug_indent -= 2
557566 if matchSelf and current .ident == ident :
558567 return current
559- name = str ( ident )
568+ name = ident . name
560569 if name in current ._childrenByName :
561570 return current ._childrenByName [name ]
562571 if recurseInAnon :
@@ -575,22 +584,16 @@ def direct_lookup(self, key: LookupKey) -> Symbol | None:
575584 Symbol .debug_indent += 1
576585 s = self
577586 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 )
583588 if Symbol .debug_lookup :
584- Symbol .debug_print ("name: " , name )
589+ Symbol .debug_print ("name: " , ident . name )
585590 Symbol .debug_print ("id: " , id_ )
586591 if s is not None :
587592 logger .debug (s .to_string (Symbol .debug_indent + 1 ), end = "" )
588593 else :
589594 Symbol .debug_print ("not found" )
590595 if s is None :
591- if Symbol .debug_lookup :
592- Symbol .debug_indent -= 2
593- return None
596+ break
594597 if Symbol .debug_lookup :
595598 Symbol .debug_indent -= 2
596599 return s
@@ -630,7 +633,7 @@ def to_string(self, indent: int) -> str:
630633 res .append ('::' )
631634 else :
632635 if self .ident :
633- res .append (str ( self .ident ) )
636+ res .append (self .ident . name )
634637 else :
635638 res .append (str (self .declaration ))
636639 if self .declaration :
@@ -646,5 +649,4 @@ def to_string(self, indent: int) -> str:
646649 return '' .join (res )
647650
648651 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