Skip to content

Commit 4d75430

Browse files
committed
Qualify some paths in 'add missing impl members'
1 parent 460fa71 commit 4d75430

File tree

6 files changed

+128
-3
lines changed

6 files changed

+128
-3
lines changed

crates/ra_assists/src/assists/add_missing_impl_members.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ fn add_missing_impl_members_inner(
139139

140140
ctx.add_assist(AssistId(assist_id), label, |edit| {
141141
let n_existing_items = impl_item_list.impl_items().count();
142+
let module = hir::SourceAnalyzer::new(
143+
db,
144+
hir::InFile::new(file_id.into(), impl_node.syntax()),
145+
None,
146+
)
147+
.module();
142148
let substs = get_syntactic_substs(impl_node).unwrap_or_default();
143149
let generic_def: hir::GenericDef = trait_.into();
144150
let substs_by_param: HashMap<_, _> = generic_def
@@ -150,6 +156,10 @@ fn add_missing_impl_members_inner(
150156
.collect();
151157
let items = missing_items
152158
.into_iter()
159+
.map(|it| match module {
160+
Some(module) => qualify_paths(db, hir::InFile::new(file_id.into(), it), module),
161+
None => it,
162+
})
153163
.map(|it| {
154164
substitute_type_params(db, hir::InFile::new(file_id.into(), it), &substs_by_param)
155165
})
@@ -227,6 +237,41 @@ fn substitute_type_params<N: AstNode>(
227237
}
228238
}
229239

240+
use hir::PathResolution;
241+
242+
// TODO handle partial paths, with generic args
243+
// TODO handle value ns?
244+
245+
fn qualify_paths<N: AstNode>(db: &impl HirDatabase, node: hir::InFile<N>, from: hir::Module) -> N {
246+
let path_replacements = node
247+
.value
248+
.syntax()
249+
.descendants()
250+
.filter_map(ast::Path::cast)
251+
.filter_map(|p| {
252+
let analyzer = hir::SourceAnalyzer::new(db, node.with_value(p.syntax()), None);
253+
let resolution = analyzer.resolve_path(db, &p)?;
254+
match resolution {
255+
PathResolution::Def(def) => {
256+
let found_path = from.find_path(db, def)?;
257+
Some((p, found_path.to_ast()))
258+
}
259+
PathResolution::Local(_)
260+
| PathResolution::TypeParam(_)
261+
| PathResolution::SelfType(_) => None,
262+
PathResolution::Macro(_) => None,
263+
PathResolution::AssocItem(_) => None,
264+
}
265+
})
266+
.collect::<Vec<_>>();
267+
268+
if path_replacements.is_empty() {
269+
node.value
270+
} else {
271+
edit::replace_descendants(&node.value, path_replacements.into_iter())
272+
}
273+
}
274+
230275
/// Given an `ast::ImplBlock`, resolves the target trait (the one being
231276
/// implemented) to a `ast::TraitDef`.
232277
fn resolve_target_trait_def(
@@ -406,14 +451,14 @@ impl Foo for S {
406451
add_missing_impl_members,
407452
"
408453
mod foo {
409-
struct Bar;
454+
pub struct Bar;
410455
trait Foo { fn foo(&self, bar: Bar); }
411456
}
412457
struct S;
413458
impl foo::Foo for S { <|> }",
414459
"
415460
mod foo {
416-
struct Bar;
461+
pub struct Bar;
417462
trait Foo { fn foo(&self, bar: Bar); }
418463
}
419464
struct S;

crates/ra_hir/src/code_model.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,19 @@ impl Module {
227227
pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module {
228228
Module::new(self.krate(), module_id)
229229
}
230+
231+
pub fn find_path(
232+
self,
233+
db: &impl DefDatabase,
234+
item: ModuleDef,
235+
) -> Option<hir_def::path::ModPath> {
236+
// FIXME expose namespace choice
237+
hir_def::find_path::find_path(
238+
db,
239+
hir_def::item_scope::ItemInNs::Types(item.into()),
240+
self.into(),
241+
)
242+
}
230243
}
231244

232245
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

crates/ra_hir/src/from_id.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ impl From<ModuleDefId> for ModuleDef {
9191
}
9292
}
9393

94+
impl From<ModuleDef> for ModuleDefId {
95+
fn from(id: ModuleDef) -> Self {
96+
match id {
97+
ModuleDef::Module(it) => ModuleDefId::ModuleId(it.into()),
98+
ModuleDef::Function(it) => ModuleDefId::FunctionId(it.into()),
99+
ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()),
100+
ModuleDef::EnumVariant(it) => ModuleDefId::EnumVariantId(it.into()),
101+
ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()),
102+
ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()),
103+
ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()),
104+
ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()),
105+
ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it),
106+
}
107+
}
108+
}
109+
94110
impl From<DefWithBody> for DefWithBodyId {
95111
fn from(def: DefWithBody) -> Self {
96112
match def {

crates/ra_hir/src/source_binder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ impl SourceAnalyzer {
205205
}
206206
}
207207

208+
pub fn module(&self) -> Option<crate::code_model::Module> {
209+
Some(crate::code_model::Module { id: self.resolver.module_id()? })
210+
}
211+
208212
fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
209213
let src = InFile { file_id: self.file_id, value: expr };
210214
self.body_source_map.as_ref()?.node_expr(src)

crates/ra_hir_def/src/path.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
22
mod lower;
33

4-
use std::{iter, sync::Arc};
4+
use std::{fmt::Display, iter, sync::Arc};
55

66
use hir_expand::{
77
hygiene::Hygiene,
@@ -78,6 +78,12 @@ impl ModPath {
7878
}
7979
self.segments.first()
8080
}
81+
82+
pub fn to_ast(&self) -> ast::Path {
83+
use ast::AstNode;
84+
let parse = ast::SourceFile::parse(&self.to_string());
85+
parse.tree().syntax().descendants().find_map(ast::Path::cast).unwrap()
86+
}
8187
}
8288

8389
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -248,6 +254,42 @@ impl From<Name> for ModPath {
248254
}
249255
}
250256

257+
impl Display for ModPath {
258+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259+
let mut first_segment = true;
260+
let mut add_segment = |s| {
261+
if !first_segment {
262+
f.write_str("::")?;
263+
}
264+
first_segment = false;
265+
f.write_str(s)?;
266+
Ok(())
267+
};
268+
match self.kind {
269+
PathKind::Plain => {}
270+
PathKind::Super(n) => {
271+
if n == 0 {
272+
add_segment("self")?;
273+
}
274+
for _ in 0..n {
275+
add_segment("super")?;
276+
}
277+
}
278+
PathKind::Crate => add_segment("crate")?,
279+
PathKind::Abs => add_segment("")?,
280+
PathKind::DollarCrate(_) => add_segment("$crate")?,
281+
}
282+
for segment in &self.segments {
283+
if !first_segment {
284+
f.write_str("::")?;
285+
}
286+
first_segment = false;
287+
write!(f, "{}", segment)?;
288+
}
289+
Ok(())
290+
}
291+
}
292+
251293
pub use hir_expand::name as __name;
252294

253295
#[macro_export]

crates/ra_hir_def/src/resolver.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ impl Resolver {
411411
})
412412
}
413413

414+
pub fn module_id(&self) -> Option<ModuleId> {
415+
let (def_map, local_id) = self.module()?;
416+
Some(ModuleId { krate: def_map.krate, local_id })
417+
}
418+
414419
pub fn krate(&self) -> Option<CrateId> {
415420
self.module().map(|t| t.0.krate)
416421
}

0 commit comments

Comments
 (0)