From 2090b534fc249a493823bb8e9039c0123aa0b90e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 6 Oct 2020 16:19:18 +0200 Subject: Move ModPath->ast::Path function to IDE layer closes #6092 --- crates/assists/src/ast_transform.rs | 17 ++++----------- .../src/handlers/add_missing_impl_members.rs | 25 ++++++++++++++++++++++ crates/assists/src/handlers/auto_import.rs | 7 ++++-- .../handlers/extract_struct_from_enum_variant.rs | 8 ++++--- crates/assists/src/handlers/fill_match_arms.rs | 4 ++-- crates/assists/src/utils.rs | 21 ++++++++++++++++++ 6 files changed, 62 insertions(+), 20 deletions(-) (limited to 'crates/assists/src') diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs index 4307e0191..ac72f3f02 100644 --- a/crates/assists/src/ast_transform.rs +++ b/crates/assists/src/ast_transform.rs @@ -1,13 +1,14 @@ //! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined. -use rustc_hash::FxHashMap; - use hir::{HirDisplay, PathResolution, SemanticsScope}; +use rustc_hash::FxHashMap; use syntax::{ algo::SyntaxRewriter, ast::{self, AstNode}, SyntaxNode, }; +use crate::utils::mod_path_to_ast; + pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N { SyntaxRewriter::from_fn(|element| match element { syntax::SyntaxElement::Node(n) => { @@ -189,7 +190,7 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> { match resolution { PathResolution::Def(def) => { let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?; - let mut path = path_to_ast(found_path); + let mut path = mod_path_to_ast(&found_path); let type_args = p .segment() @@ -210,13 +211,3 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> { } } } - -pub(crate) fn path_to_ast(path: hir::ModPath) -> ast::Path { - let parse = ast::SourceFile::parse(&path.to_string()); - parse - .tree() - .syntax() - .descendants() - .find_map(ast::Path::cast) - .unwrap_or_else(|| panic!("failed to parse path {:?}, `{}`", path, path)) -} diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index 51b5a2eb0..4c400f287 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs @@ -820,4 +820,29 @@ impl Tr for () { }"#, ) } + + #[test] + fn weird_path() { + check_assist( + add_missing_impl_members, + r#" +trait Test { + fn foo(&self, x: crate) +} +impl Test for () { + <|> +} +"#, + r#" +trait Test { + fn foo(&self, x: crate) +} +impl Test for () { + fn foo(&self, x: crate) { + ${0:todo!()} + } +} +"#, + ) + } } diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 357ff6392..d3ee98e5f 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs @@ -13,7 +13,10 @@ use syntax::{ SyntaxNode, }; -use crate::{utils::insert_use, AssistContext, AssistId, AssistKind, Assists, GroupLabel}; +use crate::{ + utils::insert_use, utils::mod_path_to_ast, AssistContext, AssistId, AssistKind, Assists, + GroupLabel, +}; // Assist: auto_import // @@ -54,7 +57,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> range, |builder| { let new_syntax = - insert_use(&scope, import.to_ast_path(), ctx.config.insert_use.merge); + insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge); builder.replace(syntax.text_range(), new_syntax.to_string()) }, ); diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index f5f03ef36..7f4f80b23 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs @@ -10,9 +10,10 @@ use syntax::{ }; use crate::{ - assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists, + assist_context::AssistBuilder, + utils::{insert_use, mod_path_to_ast, ImportScope}, + AssistContext, AssistId, AssistKind, Assists, }; -use insert_use::ImportScope; // Assist: extract_struct_from_enum_variant // @@ -111,7 +112,8 @@ fn insert_import( let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; let syntax = scope.as_syntax_node(); - let new_syntax = insert_use(&scope, mod_path.to_ast_path(), ctx.config.insert_use.merge); + let new_syntax = + insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); // FIXME: this will currently panic as multiple imports will have overlapping text ranges builder.replace(syntax.text_range(), new_syntax.to_string()) } diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs index 3d9bdb2bf..676f5ad92 100644 --- a/crates/assists/src/handlers/fill_match_arms.rs +++ b/crates/assists/src/handlers/fill_match_arms.rs @@ -7,7 +7,7 @@ use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; use test_utils::mark; use crate::{ - utils::{render_snippet, Cursor, FamousDefs}, + utils::{mod_path_to_ast, render_snippet, Cursor, FamousDefs}, AssistContext, AssistId, AssistKind, Assists, }; @@ -192,7 +192,7 @@ fn resolve_tuple_of_enum_def( } fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option { - let path = crate::ast_transform::path_to_ast(module.find_use_path(db, ModuleDef::from(var))?); + let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though let pat: ast::Pat = match var.source(db).value.kind() { diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index b0511ceb6..eb69c49a4 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -19,6 +19,27 @@ use crate::assist_config::SnippetCap; pub use insert_use::MergeBehaviour; pub(crate) use insert_use::{insert_use, ImportScope}; +pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { + let mut segments = Vec::new(); + let mut is_abs = false; + match path.kind { + hir::PathKind::Plain => {} + hir::PathKind::Super(0) => segments.push(make::path_segment_self()), + hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())), + hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => { + segments.push(make::path_segment_crate()) + } + hir::PathKind::Abs => is_abs = true, + } + + segments.extend( + path.segments + .iter() + .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))), + ); + make::path_from_segments(segments, is_abs) +} + pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { extract_trivial_expression(&block) .filter(|expr| !expr.syntax().text().contains_char('\n')) -- cgit v1.2.3