//! `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) => {
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()
}
}
}
-
-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))
-}
}"#,
)
}
+
+ #[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!()}
+ }
+}
+"#,
+ )
+ }
}
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
//
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())
},
);
};
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
//
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())
}
use test_utils::mark;
use crate::{
- utils::{render_snippet, Cursor, FamousDefs},
+ utils::{mod_path_to_ast, render_snippet, Cursor, FamousDefs},
AssistContext, AssistId, AssistKind, Assists,
};
}
fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> {
- 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() {
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'))
find_path::PrefixKind,
item_scope::ItemInNs,
nameres::ModuleSource,
- path::ModPath,
+ path::{ModPath, PathKind},
type_ref::{Mutability, TypeRef},
};
pub use hir_expand::{
// These are negative re-exports: pub using these names is forbidden, they
// should remain private to hir internals.
#[allow(unused)]
-use {
- hir_def::path::{Path, PathKind},
- hir_expand::hygiene::Hygiene,
-};
+use {hir_def::path::Path, hir_expand::hygiene::Hygiene};
hygiene::Hygiene,
name::{AsName, Name},
};
-use syntax::ast::{self, make};
+use syntax::ast::{self};
use crate::{
type_ref::{TypeBound, TypeRef},
}
self.segments.first()
}
-
- pub fn to_ast_path(&self) -> ast::Path {
- let mut segments = Vec::new();
- let mut is_abs = false;
- match self.kind {
- PathKind::Plain => {}
- PathKind::Super(0) => segments.push(make::path_segment_self()),
- PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
- PathKind::Crate => segments.push(make::path_segment_crate()),
- PathKind::Abs => is_abs = true,
- PathKind::DollarCrate(_) => (),
- }
-
- segments.extend(
- self.segments
- .iter()
- .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
- );
- make::path_from_segments(segments, is_abs)
- }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]