fix: Implement default member to resolve IdentPat

This commit is contained in:
sgasho 2025-08-11 22:19:50 +09:00
parent d307bc614e
commit 8ab683759e
2 changed files with 102 additions and 8 deletions

View file

@ -2418,6 +2418,55 @@ pub struct MyStruct;
impl other_file_2::Trait for MyStruct { impl other_file_2::Trait for MyStruct {
$0type Iter; $0type Iter;
}"#,
);
}
#[test]
fn test_qualify_ident_pat_in_default_members() {
check_assist(
add_missing_default_members,
r#"
//- /lib.rs crate:b new_source_root:library
pub enum State {
Active,
Inactive,
}
use State::*;
pub trait Checker {
fn check(&self) -> State;
fn is_active(&self) -> bool {
match self.check() {
Active => true,
Inactive => false,
}
}
}
//- /main.rs crate:a deps:b
struct MyChecker;
impl b::Checker for MyChecker {
fn check(&self) -> b::State {
todo!();
}$0
}"#,
r#"
struct MyChecker;
impl b::Checker for MyChecker {
fn check(&self) -> b::State {
todo!();
}
$0fn is_active(&self) -> bool {
match self.check() {
b::State::Active => true,
b::State::Inactive => false,
}
}
}"#, }"#,
); );
} }

View file

@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
use span::Edition; use span::Edition;
use syntax::{ use syntax::{
NodeOrToken, SyntaxNode, NodeOrToken, SyntaxNode,
ast::{self, AstNode, HasGenericArgs, make}, ast::{self, AstNode, HasGenericArgs, HasName, make},
syntax_editor::{self, SyntaxEditor}, syntax_editor::{self, SyntaxEditor},
}; };
@ -315,32 +315,49 @@ impl Ctx<'_> {
} }
fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode { fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode {
fn find_child_paths(root_path: &SyntaxNode) -> Vec<ast::Path> { fn find_child_paths_and_ident_pats(
let mut result = Vec::new(); root_path: &SyntaxNode,
) -> Vec<Either<ast::Path, ast::IdentPat>> {
let mut result: Vec<Either<ast::Path, ast::IdentPat>> = Vec::new();
for child in root_path.children() { for child in root_path.children() {
if let Some(child_path) = ast::Path::cast(child.clone()) { if let Some(child_path) = ast::Path::cast(child.clone()) {
result.push(child_path); result.push(either::Left(child_path));
} else if let Some(child_ident_pat) = ast::IdentPat::cast(child.clone()) {
result.push(either::Right(child_ident_pat));
} else { } else {
result.extend(find_child_paths(&child)); result.extend(find_child_paths_and_ident_pats(&child));
} }
} }
result result
} }
let root_path = path.clone_subtree(); let root_path = path.clone_subtree();
let result = find_child_paths(&root_path);
let result = find_child_paths_and_ident_pats(&root_path);
let mut editor = SyntaxEditor::new(root_path.clone()); let mut editor = SyntaxEditor::new(root_path.clone());
for sub_path in result { for sub_path in result {
let new = self.transform_path(sub_path.syntax()); let new = self.transform_path(sub_path.syntax());
editor.replace(sub_path.syntax(), new); editor.replace(sub_path.syntax(), new);
} }
let update_sub_item = editor.finish().new_root().clone().clone_subtree(); let update_sub_item = editor.finish().new_root().clone().clone_subtree();
let item = find_child_paths(&update_sub_item); let item = find_child_paths_and_ident_pats(&update_sub_item);
let mut editor = SyntaxEditor::new(update_sub_item); let mut editor = SyntaxEditor::new(update_sub_item);
for sub_path in item { for sub_path in item {
self.transform_path_(&mut editor, &sub_path); self.transform_path_or_ident_pat(&mut editor, &sub_path);
} }
editor.finish().new_root().clone() editor.finish().new_root().clone()
} }
fn transform_path_or_ident_pat(
&self,
editor: &mut SyntaxEditor,
item: &Either<ast::Path, ast::IdentPat>,
) -> Option<()> {
match item {
Either::Left(path) => self.transform_path_(editor, path),
Either::Right(ident_pat) => self.transform_ident_pat(editor, ident_pat),
}
}
fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> { fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> {
if path.qualifier().is_some() { if path.qualifier().is_some() {
@ -515,6 +532,34 @@ impl Ctx<'_> {
} }
Some(()) Some(())
} }
fn transform_ident_pat(
&self,
editor: &mut SyntaxEditor,
ident_pat: &ast::IdentPat,
) -> Option<()> {
let name = ident_pat.name()?;
let temp_path = make::path_from_text(&name.text());
let resolution = self.source_scope.speculative_resolve(&temp_path)?;
match resolution {
hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => {
let cfg = ImportPathConfig {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
allow_unstable: true,
};
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
editor.replace(ident_pat.syntax(), res.syntax());
Some(())
}
_ => None,
}
}
} }
// FIXME: It would probably be nicer if we could get this via HIR (i.e. get the // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the