@@ -53,6 +53,7 @@ use ruff_python_ast::ExprDict;
5353use ruff_python_ast:: ExprList ;
5454use ruff_python_ast:: ExprName ;
5555use ruff_python_ast:: Identifier ;
56+ use ruff_python_ast:: Keyword ;
5657use ruff_python_ast:: ModModule ;
5758use ruff_python_ast:: ParameterWithDefault ;
5859use ruff_python_ast:: Stmt ;
@@ -204,6 +205,29 @@ enum CalleeKind {
204205 Unknown ,
205206}
206207
208+ fn callee_kind_from_call ( call : & ExprCall ) -> CalleeKind {
209+ match call. func . as_ref ( ) {
210+ Expr :: Name ( name) => CalleeKind :: Function ( Ast :: expr_name_identifier ( name. clone ( ) ) ) ,
211+ Expr :: Attribute ( attr) => CalleeKind :: Method ( attr. value . range ( ) , attr. attr . clone ( ) ) ,
212+ _ => CalleeKind :: Unknown ,
213+ }
214+ }
215+
216+ /// Generic helper to visit keyword arguments with a custom handler.
217+ /// The handler receives the keyword index and reference, and returns true to stop iteration.
218+ /// This function will also take in a generic function which is used a filter
219+ fn visit_keyword_arguments_until_match < F > ( call : & ExprCall , mut filter : F ) -> bool
220+ where
221+ F : FnMut ( usize , & Keyword ) -> bool ,
222+ {
223+ for ( j, kw) in call. arguments . keywords . iter ( ) . enumerate ( ) {
224+ if filter ( j, kw) {
225+ return true ;
226+ }
227+ }
228+ false
229+ }
230+
207231#[ derive( Debug ) ]
208232enum PatternMatchParameterKind {
209233 // Name defined using `as`
@@ -432,11 +456,7 @@ impl IdentifierWithContext {
432456
433457 fn from_keyword_argument ( id : & Identifier , call : & ExprCall ) -> Self {
434458 let identifier = id. clone ( ) ;
435- let callee_kind = match call. func . as_ref ( ) {
436- Expr :: Name ( name) => CalleeKind :: Function ( Ast :: expr_name_identifier ( name. clone ( ) ) ) ,
437- Expr :: Attribute ( attr) => CalleeKind :: Method ( attr. value . range ( ) , attr. attr . clone ( ) ) ,
438- _ => CalleeKind :: Unknown ,
439- } ;
459+ let callee_kind = callee_kind_from_call ( call) ;
440460 Self {
441461 identifier,
442462 context : IdentifierContext :: KeywordArgument ( callee_kind) ,
@@ -910,7 +930,7 @@ impl<'a> Transaction<'a> {
910930 res : & mut Option < ( TextRange , TextRange , ActiveArgument ) > ,
911931 ) -> bool {
912932 let kwarg_start_idx = call. arguments . args . len ( ) ;
913- for ( j, kw) in call . arguments . keywords . iter ( ) . enumerate ( ) {
933+ visit_keyword_arguments_until_match ( call , | j, kw| {
914934 if kw. range . contains_inclusive ( find) {
915935 Self :: visit_finding_signature_range ( & kw. value , find, res) ;
916936 if res. is_some ( ) {
@@ -921,10 +941,11 @@ impl<'a> Transaction<'a> {
921941 None => ActiveArgument :: Positional ( kwarg_start_idx + j) ,
922942 } ;
923943 * res = Some ( ( call. func . range ( ) , call. arguments . range , active_argument) ) ;
924- return true ;
944+ true
945+ } else {
946+ false
925947 }
926- }
927- false
948+ } )
928949 }
929950
930951 /// Finds the callable(s) (multiple if overloads exist) at position in document, returning them, chosen overload index, and arg index
@@ -2098,6 +2119,40 @@ impl<'a> Transaction<'a> {
20982119 . unwrap_or_default ( )
20992120 }
21002121
2122+ #[ allow( dead_code) ]
2123+ pub ( self ) fn collect_local_keyword_arguments_by_name (
2124+ & self ,
2125+ handle : & Handle ,
2126+ expected_name : & Name ,
2127+ ) -> Vec < ( Identifier , CalleeKind ) > {
2128+ let Some ( mod_module) = self . get_ast ( handle) else {
2129+ return Vec :: new ( ) ;
2130+ } ;
2131+
2132+ fn collect_kwargs (
2133+ x : & Expr ,
2134+ expected_name : & Name ,
2135+ results : & mut Vec < ( Identifier , CalleeKind ) > ,
2136+ ) {
2137+ if let Expr :: Call ( call) = x {
2138+ visit_keyword_arguments_until_match ( call, |_j, kw| {
2139+ if let Some ( arg_identifier) = & kw. arg
2140+ && arg_identifier. id ( ) == expected_name
2141+ {
2142+ let callee_kind = callee_kind_from_call ( call) ;
2143+ results. push ( ( arg_identifier. clone ( ) , callee_kind) ) ;
2144+ }
2145+ false
2146+ } ) ;
2147+ }
2148+ x. recurse ( & mut |x| collect_kwargs ( x, expected_name, results) ) ;
2149+ }
2150+
2151+ let mut results = Vec :: new ( ) ;
2152+ mod_module. visit ( & mut |x| collect_kwargs ( x, expected_name, & mut results) ) ;
2153+ results
2154+ }
2155+
21012156 fn local_variable_references_from_local_definition (
21022157 & self ,
21032158 handle : & Handle ,
0 commit comments