7676from robotcode .robot .utils .ast import (
7777 cached_isinstance ,
7878 get_variable_token ,
79+ iter_nodes ,
7980 range_from_token ,
8081 strip_variable_token ,
8182)
8283from robotcode .robot .utils .markdownformatter import MarkDownFormatter
8384from robotcode .robot .utils .match import normalize , normalize_namespace
84- from robotcode .robot .utils .stubs import HasError , HasErrors
8585
8686from ..utils .variables import contains_variable
8787
@@ -239,7 +239,6 @@ def __init__(
239239 self ._can_have_embedded = can_have_embedded and not is_namespace
240240 self ._is_namespace = is_namespace
241241 self ._normalized_name : Optional [str ] = None
242- self ._embedded_arguments : Any = None
243242
244243 @property
245244 def normalized_name (self ) -> str :
@@ -248,15 +247,12 @@ def normalized_name(self) -> str:
248247
249248 return self ._normalized_name
250249
251- @property
250+ @functools . cached_property
252251 def embedded_arguments (self ) -> Any :
253- if self ._embedded_arguments is None :
254- if self ._can_have_embedded :
255- self ._embedded_arguments = _get_embedded_arguments (self .name )
256- else :
257- self ._embedded_arguments = ()
252+ if self ._can_have_embedded :
253+ return _get_embedded_arguments (self .name ) or ()
258254
259- return self . _embedded_arguments
255+ return ()
260256
261257 if get_robot_version () >= (6 , 0 ):
262258
@@ -269,7 +265,7 @@ def __match_embedded(self, name: str) -> bool:
269265 return self .embedded_arguments .name .match (name ) is not None
270266
271267 def __eq__ (self , o : object ) -> bool :
272- if cached_isinstance ( o , KeywordMatcher ) :
268+ if type ( o ) is KeywordMatcher :
273269 if self ._is_namespace != o ._is_namespace :
274270 return False
275271
@@ -667,13 +663,11 @@ def __post_init__(self) -> None:
667663 def __str__ (self ) -> str :
668664 return f"{ self .name } ({ ', ' .join (str (arg ) for arg in self .arguments )} )"
669665
670- @property
666+ @functools . cached_property
671667 def matcher (self ) -> KeywordMatcher :
672- if not hasattr (self , "__matcher" ):
673- self .__matcher = KeywordMatcher (self .name )
674- return self .__matcher
668+ return KeywordMatcher (self .name )
675669
676- @property
670+ @functools . cached_property
677671 def is_deprecated (self ) -> bool :
678672 return self .deprecated or DEPRECATED_PATTERN .match (self .doc ) is not None
679673
@@ -685,13 +679,13 @@ def is_resource_keyword(self) -> bool:
685679 def is_library_keyword (self ) -> bool :
686680 return self .libtype == "LIBRARY"
687681
688- @property
682+ @functools . cached_property
689683 def deprecated_message (self ) -> str :
690684 if (m := DEPRECATED_PATTERN .match (self .doc )) is not None :
691685 return m .group ("message" ).strip ()
692686 return ""
693687
694- @property
688+ @functools . cached_property
695689 def name_range (self ) -> Range :
696690 if self .name_token is not None :
697691 return range_from_token (self .name_token )
@@ -709,7 +703,7 @@ def is_private(self) -> bool:
709703
710704 return "robot:private" in self .normalized_tags ()
711705
712- @property
706+ @functools . cached_property
713707 def range (self ) -> Range :
714708 if self .name_token is not None :
715709 return range_from_token (self .name_token )
@@ -820,7 +814,7 @@ def escape_pipe(s: str) -> str:
820814
821815 return result
822816
823- @property
817+ @functools . cached_property
824818 def signature (self ) -> str :
825819 return (
826820 f'({ self .type } ) "{ self .name } ": ('
@@ -2716,15 +2710,16 @@ def get_model_doc(
27162710 append_model_errors : bool = True ,
27172711) -> LibraryDoc :
27182712 errors : List [Error ] = []
2719- keyword_name_nodes : List [KeywordName ] = []
2720- keywords_nodes : List [Keyword ] = []
2721- for node in ast .walk (model ):
2722- if isinstance (node , Keyword ):
2723- keywords_nodes .append (node )
2724- if isinstance (node , KeywordName ):
2725- keyword_name_nodes .append (node )
2726-
2727- error = node .error if isinstance (node , HasError ) else None
2713+ keyword_name_nodes : Dict [int , KeywordName ] = {}
2714+ keywords_nodes : Dict [int , Keyword ] = {}
2715+ for node in iter_nodes (model ):
2716+ if cached_isinstance (node , Keyword ):
2717+ node .lineno
2718+ keywords_nodes [node .lineno ] = node
2719+ if cached_isinstance (node , KeywordName ):
2720+ keyword_name_nodes [node .lineno ] = node
2721+
2722+ error = getattr (node , "error" , None )
27282723 if error is not None :
27292724 errors .append (
27302725 Error (
@@ -2735,7 +2730,7 @@ def get_model_doc(
27352730 )
27362731 )
27372732 if append_model_errors :
2738- node_errors = node . errors if isinstance (node , HasErrors ) else None
2733+ node_errors = getattr (node , "errors" , None )
27392734 if node_errors is not None :
27402735 for e in node_errors :
27412736 errors .append (
@@ -2748,16 +2743,15 @@ def get_model_doc(
27482743 )
27492744
27502745 def get_keyword_name_token_from_line (line : int ) -> Optional [Token ]:
2751- for keyword_name in keyword_name_nodes :
2752- if keyword_name .lineno == line :
2753- return cast (Token , keyword_name .get_token (RobotToken .KEYWORD_NAME ))
2754-
2755- return None
2746+ keyword_name = keyword_name_nodes .get (line , None )
2747+ if keyword_name is None :
2748+ return None
2749+ return cast (Token , keyword_name .get_token (RobotToken .KEYWORD_NAME ))
27562750
27572751 def get_argument_definitions_from_line (
27582752 line : int ,
27592753 ) -> List [ArgumentDefinition ]:
2760- keyword_node = next (( k for k in keywords_nodes if k . lineno == line ) , None )
2754+ keyword_node = keywords_nodes . get ( line , None )
27612755 if keyword_node is None :
27622756 return []
27632757
0 commit comments