Skip to content

Commit 9a548b2

Browse files
John Van Schultzmeta-codesync[bot]
authored andcommitted
Add function to collect keyword arguments based on name.
Summary: This diff introduces a function which when given a name will find all local uses of that name which are keyword arguments. In a future diff, this function will be used to collect all those references, which will will then be narrowed down to only those which belong to the defining function. Reviewed By: kinto0 Differential Revision: D86868371 fbshipit-source-id: dfeedd1ab85f0818916343f6bbd1b92b21192dc9
1 parent 0315aad commit 9a548b2

File tree

1 file changed

+64
-9
lines changed

1 file changed

+64
-9
lines changed

pyrefly/lib/state/lsp.rs

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use ruff_python_ast::ExprDict;
5353
use ruff_python_ast::ExprList;
5454
use ruff_python_ast::ExprName;
5555
use ruff_python_ast::Identifier;
56+
use ruff_python_ast::Keyword;
5657
use ruff_python_ast::ModModule;
5758
use ruff_python_ast::ParameterWithDefault;
5859
use 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)]
208232
enum 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

Comments
 (0)