11from dataclasses import dataclass , field
22from enum import Enum
3- from typing import TYPE_CHECKING , Any , Optional , Tuple
3+ from typing import TYPE_CHECKING , Any , Callable , Optional , Tuple , TypeVar , cast
44
55from ...common .lsp_types import Position , Range
66from ..utils .ast_utils import Token , range_from_token
77
88if TYPE_CHECKING :
99 from .library_doc import KeywordDoc
1010
11+ _F = TypeVar ("_F" , bound = Callable [..., Any ])
12+
13+
14+ _NOT_SET = object ()
15+
16+
17+ def single_call (func : _F ) -> _F :
18+ name = f"__A_{ func .__name__ } __result"
19+
20+ def wrapper (self : Any , * args : Any , ** kwargs : Any ) -> Any :
21+
22+ result = self .__dict__ .get (name , _NOT_SET )
23+ if result is _NOT_SET :
24+ result = func (self , * args , ** kwargs )
25+ self .__dict__ [name ] = result
26+ return result
27+
28+ return cast (_F , wrapper )
29+
1130
1231@dataclass
1332class SourceEntity :
@@ -24,6 +43,7 @@ def range(self) -> Range:
2443 end = Position (line = self .end_line_no - 1 , character = self .end_col_offset ),
2544 )
2645
46+ @single_call
2747 def __hash__ (self ) -> int :
2848 return hash ((self .line_no , self .col_offset , self .end_line_no , self .end_col_offset , self .source ))
2949
@@ -52,6 +72,7 @@ class LibraryImport(Import):
5272 args : Tuple [str , ...] = ()
5373 alias : Optional [str ] = None
5474
75+ @single_call
5576 def __hash__ (self ) -> int :
5677 return hash (
5778 (
@@ -65,6 +86,7 @@ def __hash__(self) -> int:
6586
6687@dataclass
6788class ResourceImport (Import ):
89+ @single_call
6890 def __hash__ (self ) -> int :
6991 return hash (
7092 (
@@ -78,6 +100,7 @@ def __hash__(self) -> int:
78100class VariablesImport (Import ):
79101 args : Tuple [str , ...] = ()
80102
103+ @single_call
81104 def __hash__ (self ) -> int :
82105 return hash (
83106 (
@@ -94,14 +117,13 @@ class InvalidVariableError(Exception):
94117
95118class VariableMatcher :
96119 def __init__ (self , name : str ) -> None :
97- from robot .variables .search import VariableSearcher
120+ from robot .variables .search import search_variable
98121
99122 from ..utils .match import normalize
100123
101124 self .name = name
102125
103- searcher = VariableSearcher ("$@&%" , ignore_errors = True )
104- match = searcher .search (name )
126+ match = search_variable (name , "$@&%" , ignore_errors = True )
105127
106128 if match .base is None :
107129 raise InvalidVariableError (f"Invalid variable '{ name } '" )
@@ -112,13 +134,12 @@ def __init__(self, name: str) -> None:
112134
113135 def __eq__ (self , o : object ) -> bool :
114136 from robot .utils .normalizing import normalize
115- from robot .variables .search import VariableSearcher
137+ from robot .variables .search import search_variable
116138
117139 if isinstance (o , VariableMatcher ):
118140 return o .normalized_name == self .normalized_name
119141 elif isinstance (o , str ):
120- searcher = VariableSearcher ("$@&%" , ignore_errors = True )
121- match = searcher .search (o )
142+ match = search_variable (o , "$@&%" , ignore_errors = True )
122143 base = match .base
123144 normalized = str (normalize (base ))
124145 return self .normalized_name == normalized
@@ -165,6 +186,7 @@ def matcher(self) -> VariableMatcher:
165186 self .__matcher = VariableMatcher (self .name )
166187 return self .__matcher
167188
189+ @single_call
168190 def __hash__ (self ) -> int :
169191 return hash ((type (self ), self .name , self .type , self .range , self .source ))
170192
@@ -193,6 +215,7 @@ def range(self) -> Range:
193215class LocalVariableDefinition (VariableDefinition ):
194216 type : VariableDefinitionType = VariableDefinitionType .LOCAL_VARIABLE
195217
218+ @single_call
196219 def __hash__ (self ) -> int :
197220 return hash ((type (self ), self .name , self .type , self .range , self .source ))
198221
@@ -202,6 +225,7 @@ class BuiltInVariableDefinition(VariableDefinition):
202225 type : VariableDefinitionType = VariableDefinitionType .BUILTIN_VARIABLE
203226 resolvable : bool = True
204227
228+ @single_call
205229 def __hash__ (self ) -> int :
206230 return hash ((type (self ), self .name , self .type ))
207231
@@ -211,6 +235,7 @@ class CommandLineVariableDefinition(VariableDefinition):
211235 type : VariableDefinitionType = VariableDefinitionType .COMMAND_LINE_VARIABLE
212236 resolvable : bool = True
213237
238+ @single_call
214239 def __hash__ (self ) -> int :
215240 return hash ((type (self ), self .name , self .type ))
216241
@@ -220,6 +245,7 @@ class ArgumentDefinition(VariableDefinition):
220245 type : VariableDefinitionType = VariableDefinitionType .ARGUMENT
221246 keyword_doc : Optional ["KeywordDoc" ] = None
222247
248+ @single_call
223249 def __hash__ (self ) -> int :
224250 return hash ((type (self ), self .name , self .type , self .range , self .source ))
225251
@@ -228,6 +254,7 @@ def __hash__(self) -> int:
228254class ImportedVariableDefinition (VariableDefinition ):
229255 type : VariableDefinitionType = VariableDefinitionType .IMPORTED_VARIABLE
230256
257+ @single_call
231258 def __hash__ (self ) -> int :
232259 return hash ((type (self ), self .name , self .type , self .source ))
233260
@@ -237,6 +264,7 @@ class EnvironmentVariableDefinition(VariableDefinition):
237264 type : VariableDefinitionType = VariableDefinitionType .ENVIRONMENT_VARIABLE
238265 resolvable : bool = True
239266
267+ @single_call
240268 def __hash__ (self ) -> int :
241269 return hash ((type (self ), self .name , self .type ))
242270
@@ -246,5 +274,6 @@ class VariableNotFoundDefinition(VariableDefinition):
246274 type : VariableDefinitionType = VariableDefinitionType .VARIABLE_NOT_FOUND
247275 resolvable : bool = False
248276
277+ @single_call
249278 def __hash__ (self ) -> int :
250279 return hash ((type (self ), self .name , self .type ))
0 commit comments