add qualify code-action

This commit is contained in:
Aria Desires 2025-12-13 16:43:22 -05:00
parent bb464ed924
commit 72ef51b7bc
2 changed files with 71 additions and 0 deletions

View File

@ -38,6 +38,11 @@ pub fn code_actions(
{ {
actions.extend(import_quick_fix); actions.extend(import_quick_fix);
} }
if is_unresolved_reference
&& let Some(import_quick_fix) = create_qualify_symbol_quick_fix(db, file, diagnostic_range)
{
actions.extend(import_quick_fix);
}
// Suggest just suppressing the lint (always a valid option, but never ideal) // Suggest just suppressing the lint (always a valid option, but never ideal)
actions.push(QuickFix { actions.push(QuickFix {
@ -69,6 +74,26 @@ fn create_import_symbol_quick_fix(
) )
} }
fn create_qualify_symbol_quick_fix(
db: &dyn Db,
file: File,
diagnostic_range: TextRange,
) -> Option<impl Iterator<Item = QuickFix>> {
let parsed = parsed_module(db, file).load(db);
let node = covering_node(parsed.syntax().into(), diagnostic_range).node();
let symbol = &node.expr_name()?.id;
Some(
completion::missing_qualifications(db, file, &parsed, symbol, node)
.into_iter()
.map(|import| QuickFix {
title: import.label,
edits: vec![import.edit],
preferred: true,
}),
)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -82,6 +82,29 @@ impl<'db> Completions<'db> {
.collect() .collect()
} }
fn into_qualified(mut self, range: TextRange) -> Vec<ImportEdit> {
self.items.sort_by(compare_suggestions);
self.items
.dedup_by(|c1, c2| (&c1.name, c1.module_name) == (&c2.name, c2.module_name));
self.items
.into_iter()
.filter_map(|item| {
if item.import.is_none() {
Some(ImportEdit {
label: format!("qualify {}", item.insert.as_ref()?),
edit: Edit::replacement(
item.insert?.into_string(),
range.start(),
range.end(),
),
})
} else {
None
}
})
.collect()
}
/// Attempts to adds the given completion to this collection. /// Attempts to adds the given completion to this collection.
/// ///
/// When added, `true` is returned. /// When added, `true` is returned.
@ -578,6 +601,29 @@ pub(crate) fn missing_imports(
completions.into_imports() completions.into_imports()
} }
pub(crate) fn missing_qualifications(
db: &dyn Db,
file: File,
parsed: &ParsedModuleRef,
symbol: &str,
node: AnyNodeRef,
) -> Vec<ImportEdit> {
let mut completions = Completions::exactly(db, symbol);
let scoped = ScopedTarget { node };
add_unimported_completions(
db,
file,
parsed,
scoped,
|module_name: &ModuleName, symbol: &str| {
ImportRequest::import(module_name.as_str(), symbol).force()
},
&mut completions,
);
completions.into_qualified(node.range())
}
/// Adds completions derived from keywords. /// Adds completions derived from keywords.
/// ///
/// This should generally only be used when offering "scoped" completions. /// This should generally only be used when offering "scoped" completions.