From ef1326ee19c9ff707dcf96ce289102deedcf4d5f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 15 Jan 2020 18:48:28 +0100 Subject: [PATCH] More orthogonal path editing --- crates/ra_assists/src/ast_transform.rs | 13 ++++++-- crates/ra_syntax/src/ast/edit.rs | 42 ++++++++++++++++++++++++++ crates/ra_syntax/src/ast/make.rs | 18 ++--------- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index eac2903d148..56b7588efb6 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs @@ -2,7 +2,7 @@ use rustc_hash::FxHashMap; use hir::{db::HirDatabase, InFile, PathResolution}; -use ra_syntax::ast::{self, make, AstNode}; +use ra_syntax::ast::{self, AstNode}; pub trait AstTransform<'a> { fn get_substitution( @@ -134,11 +134,18 @@ fn get_substitution_inner( match resolution { PathResolution::Def(def) => { let found_path = from.find_use_path(self.db, def)?; - let args = p + let mut path = path_to_ast(found_path); + + let type_args = p .segment() .and_then(|s| s.type_arg_list()) .map(|arg_list| apply(self, node.with_value(arg_list))); - Some(make::path_with_type_arg_list(path_to_ast(found_path), args).syntax().clone()) + if let Some(type_args) = type_args { + let last_segment = path.segment().unwrap(); + path = path.with_segment(last_segment.with_type_args(type_args)) + } + + Some(path.syntax().clone()) } PathResolution::Local(_) | PathResolution::TypeParam(_) diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index d88a0cf4bf5..0e78d8b6377 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs @@ -207,6 +207,48 @@ pub fn remove_bounds(&self) -> ast::TypeParam { } } +impl ast::Path { + #[must_use] + pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { + if let Some(old) = self.segment() { + return replace_children( + self, + single_node(old.syntax().clone()), + iter::once(segment.syntax().clone().into()), + ); + } + self.clone() + } +} + +impl ast::PathSegment { + #[must_use] + pub fn with_type_args(&self, type_args: ast::TypeArgList) -> ast::PathSegment { + self._with_type_args(type_args, false) + } + + #[must_use] + pub fn with_turbo_fish(&self, type_args: ast::TypeArgList) -> ast::PathSegment { + self._with_type_args(type_args, true) + } + + fn _with_type_args(&self, type_args: ast::TypeArgList, turbo: bool) -> ast::PathSegment { + if let Some(old) = self.type_arg_list() { + return replace_children( + self, + single_node(old.syntax().clone()), + iter::once(type_args.syntax().clone().into()), + ); + } + let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); + if turbo { + to_insert.push(make::token(T![::]).into()); + } + to_insert.push(type_args.syntax().clone().into()); + insert_children(self, InsertPosition::Last, to_insert) + } +} + #[must_use] pub fn strip_attrs_and_docs(node: &N) -> N { N::cast(strip_attrs_and_docs_inner(node.syntax().clone())).unwrap() diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 4a79d0dec51..36e648180b4 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -2,7 +2,7 @@ //! of smaller pieces. use itertools::Itertools; -use crate::{algo, ast, AstNode, SourceFile, SyntaxKind, SyntaxToken}; +use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken}; pub fn name(text: &str) -> ast::Name { ast_from_text(&format!("mod {};", text)) @@ -21,20 +21,6 @@ pub fn path_qualified(qual: ast::Path, name_ref: ast::NameRef) -> ast::Path { fn path_from_text(text: &str) -> ast::Path { ast_from_text(text) } -pub fn path_with_type_arg_list(path: ast::Path, args: Option) -> ast::Path { - if let Some(args) = args { - let syntax = path.syntax(); - // FIXME: remove existing type args - let new_syntax = algo::insert_children( - syntax, - crate::algo::InsertPosition::Last, - &mut Some(args).into_iter().map(|n| n.syntax().clone().into()), - ); - ast::Path::cast(new_syntax).unwrap() - } else { - path - } -} pub fn record_field(name: ast::NameRef, expr: Option) -> ast::RecordField { return match expr { @@ -201,7 +187,7 @@ pub mod tokens { use once_cell::sync::Lazy; pub(super) static SOURCE_FILE: Lazy> = - Lazy::new(|| SourceFile::parse("const C: () = (1 != 1, 2 == 2)\n;")); + Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;")); pub fn comma() -> SyntaxToken { SOURCE_FILE