diff options
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r-- | crates/ra_assists/src/add_explicit_type.rs | 89 | ||||
-rw-r--r-- | crates/ra_assists/src/add_missing_impl_members.rs | 15 | ||||
-rw-r--r-- | crates/ra_assists/src/fill_match_arms.rs | 10 | ||||
-rw-r--r-- | crates/ra_assists/src/fill_struct_fields.rs | 12 | ||||
-rw-r--r-- | crates/ra_assists/src/inline_local_variable.rs | 11 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/split_import.rs | 5 |
7 files changed, 112 insertions, 32 deletions
diff --git a/crates/ra_assists/src/add_explicit_type.rs b/crates/ra_assists/src/add_explicit_type.rs new file mode 100644 index 000000000..cb0ac9885 --- /dev/null +++ b/crates/ra_assists/src/add_explicit_type.rs | |||
@@ -0,0 +1,89 @@ | |||
1 | use hir::{ | ||
2 | HirDisplay, Ty, | ||
3 | db::HirDatabase, | ||
4 | }; | ||
5 | use ra_syntax::{ | ||
6 | SyntaxKind, | ||
7 | ast::{LetStmt, PatKind, NameOwner, AstNode} | ||
8 | }; | ||
9 | |||
10 | use crate::{AssistCtx, Assist, AssistId}; | ||
11 | |||
12 | /// Add explicit type assist. | ||
13 | pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
14 | let stmt = ctx.node_at_offset::<LetStmt>()?; | ||
15 | let expr = stmt.initializer()?; | ||
16 | let pat = stmt.pat()?; | ||
17 | // Must be a binding | ||
18 | let pat = match pat.kind() { | ||
19 | PatKind::BindPat(bind_pat) => bind_pat, | ||
20 | _ => return None, | ||
21 | }; | ||
22 | let pat_range = pat.syntax().range(); | ||
23 | // The binding must have a name | ||
24 | let name = pat.name()?; | ||
25 | let name_range = name.syntax().range(); | ||
26 | // Assist not applicable if the type has already been specified | ||
27 | if stmt.syntax().children_with_tokens().any(|child| child.kind() == SyntaxKind::COLON) { | ||
28 | return None; | ||
29 | } | ||
30 | // Infer type | ||
31 | let db = ctx.db; | ||
32 | let analyzer = hir::SourceAnalyzer::new(db, ctx.frange.file_id, stmt.syntax(), None); | ||
33 | let ty = analyzer.type_of(db, expr)?; | ||
34 | // Assist not applicable if the type is unknown | ||
35 | if is_unknown(&ty) { | ||
36 | return None; | ||
37 | } | ||
38 | |||
39 | ctx.add_action(AssistId("add_explicit_type"), "add explicit type", |edit| { | ||
40 | edit.target(pat_range); | ||
41 | edit.insert(name_range.end(), format!(": {}", ty.display(db))); | ||
42 | }); | ||
43 | ctx.build() | ||
44 | } | ||
45 | |||
46 | /// Returns true if any type parameter is unknown | ||
47 | fn is_unknown(ty: &Ty) -> bool { | ||
48 | match ty { | ||
49 | Ty::Unknown => true, | ||
50 | Ty::Apply(a_ty) => a_ty.parameters.iter().any(is_unknown), | ||
51 | _ => false, | ||
52 | } | ||
53 | } | ||
54 | |||
55 | #[cfg(test)] | ||
56 | mod tests { | ||
57 | use super::*; | ||
58 | |||
59 | use crate::helpers::{ check_assist, check_assist_target, check_assist_not_applicable }; | ||
60 | |||
61 | #[test] | ||
62 | fn add_explicit_type_target() { | ||
63 | check_assist_target(add_explicit_type, "fn f() { let a<|> = 1; }", "a"); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn add_explicit_type_works_for_simple_expr() { | ||
68 | check_assist( | ||
69 | add_explicit_type, | ||
70 | "fn f() { let a<|> = 1; }", | ||
71 | "fn f() { let a<|>: i32 = 1; }", | ||
72 | ); | ||
73 | } | ||
74 | |||
75 | #[test] | ||
76 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { | ||
77 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }"); | ||
78 | } | ||
79 | |||
80 | #[test] | ||
81 | fn add_explicit_type_not_applicable_if_ty_already_specified() { | ||
82 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: i32 = 1; }"); | ||
83 | } | ||
84 | |||
85 | #[test] | ||
86 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { | ||
87 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }"); | ||
88 | } | ||
89 | } | ||
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs index 19a2d05bc..100ebb7b6 100644 --- a/crates/ra_assists/src/add_missing_impl_members.rs +++ b/crates/ra_assists/src/add_missing_impl_members.rs | |||
@@ -2,7 +2,6 @@ use std::fmt::Write; | |||
2 | 2 | ||
3 | use crate::{Assist, AssistId, AssistCtx}; | 3 | use crate::{Assist, AssistId, AssistCtx}; |
4 | 4 | ||
5 | use hir::Resolver; | ||
6 | use hir::db::HirDatabase; | 5 | use hir::db::HirDatabase; |
7 | use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; | 6 | use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; |
8 | use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner}; | 7 | use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner}; |
@@ -46,9 +45,9 @@ fn add_missing_impl_members_inner( | |||
46 | let trait_def = { | 45 | let trait_def = { |
47 | let file_id = ctx.frange.file_id; | 46 | let file_id = ctx.frange.file_id; |
48 | let position = FilePosition { file_id, offset: impl_node.syntax().range().start() }; | 47 | let position = FilePosition { file_id, offset: impl_node.syntax().range().start() }; |
49 | let resolver = hir::source_binder::resolver_for_position(ctx.db, position); | 48 | let analyzer = hir::SourceAnalyzer::new(ctx.db, position.file_id, impl_node.syntax(), None); |
50 | 49 | ||
51 | resolve_target_trait_def(ctx.db, &resolver, impl_node)? | 50 | resolve_target_trait_def(ctx.db, &analyzer, impl_node)? |
52 | }; | 51 | }; |
53 | 52 | ||
54 | let missing_fns: Vec<_> = { | 53 | let missing_fns: Vec<_> = { |
@@ -122,14 +121,14 @@ fn add_missing_impl_members_inner( | |||
122 | /// implemented) to a `ast::TraitDef`. | 121 | /// implemented) to a `ast::TraitDef`. |
123 | fn resolve_target_trait_def( | 122 | fn resolve_target_trait_def( |
124 | db: &impl HirDatabase, | 123 | db: &impl HirDatabase, |
125 | resolver: &Resolver, | 124 | analyzer: &hir::SourceAnalyzer, |
126 | impl_block: &ast::ImplBlock, | 125 | impl_block: &ast::ImplBlock, |
127 | ) -> Option<TreeArc<ast::TraitDef>> { | 126 | ) -> Option<TreeArc<ast::TraitDef>> { |
128 | let ast_path = impl_block.target_trait().map(AstNode::syntax).and_then(ast::PathType::cast)?; | 127 | let ast_path = |
129 | let hir_path = ast_path.path().and_then(hir::Path::from_ast)?; | 128 | impl_block.target_trait().map(AstNode::syntax).and_then(ast::PathType::cast)?.path()?; |
130 | 129 | ||
131 | match resolver.resolve_path(db, &hir_path).take_types() { | 130 | match analyzer.resolve_path(db, &ast_path) { |
132 | Some(hir::Resolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).1), | 131 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).1), |
133 | _ => None, | 132 | _ => None, |
134 | } | 133 | } |
135 | } | 134 | } |
diff --git a/crates/ra_assists/src/fill_match_arms.rs b/crates/ra_assists/src/fill_match_arms.rs index da67ab667..45e327cd4 100644 --- a/crates/ra_assists/src/fill_match_arms.rs +++ b/crates/ra_assists/src/fill_match_arms.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::fmt::Write; | 1 | use std::fmt::Write; |
2 | 2 | ||
3 | use hir::{ | 3 | use hir::{ |
4 | AdtDef, FieldSource, source_binder, | 4 | AdtDef, FieldSource, |
5 | db::HirDatabase, | 5 | db::HirDatabase, |
6 | }; | 6 | }; |
7 | use ra_syntax::ast::{self, AstNode}; | 7 | use ra_syntax::ast::{self, AstNode}; |
@@ -20,12 +20,8 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
20 | } | 20 | } |
21 | 21 | ||
22 | let expr = match_expr.expr()?; | 22 | let expr = match_expr.expr()?; |
23 | let function = | 23 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None); |
24 | source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, expr.syntax())?; | 24 | let match_expr_ty = analyzer.type_of(ctx.db, expr)?; |
25 | let infer_result = function.infer(ctx.db); | ||
26 | let source_map = function.body_source_map(ctx.db); | ||
27 | let node_expr = source_map.node_expr(expr)?; | ||
28 | let match_expr_ty = infer_result[node_expr].clone(); | ||
29 | let enum_def = match_expr_ty.autoderef(ctx.db).find_map(|ty| match ty.as_adt() { | 25 | let enum_def = match_expr_ty.autoderef(ctx.db).find_map(|ty| match ty.as_adt() { |
30 | Some((AdtDef::Enum(e), _)) => Some(e), | 26 | Some((AdtDef::Enum(e), _)) => Some(e), |
31 | _ => None, | 27 | _ => None, |
diff --git a/crates/ra_assists/src/fill_struct_fields.rs b/crates/ra_assists/src/fill_struct_fields.rs index c7790dc72..663b4f669 100644 --- a/crates/ra_assists/src/fill_struct_fields.rs +++ b/crates/ra_assists/src/fill_struct_fields.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::fmt::Write; | 1 | use std::fmt::Write; |
2 | 2 | ||
3 | use hir::{AdtDef, db::HirDatabase, source_binder::function_from_child_node}; | 3 | use hir::{AdtDef, db::HirDatabase}; |
4 | 4 | ||
5 | use ra_syntax::ast::{self, AstNode}; | 5 | use ra_syntax::ast::{self, AstNode}; |
6 | 6 | ||
@@ -51,15 +51,13 @@ where | |||
51 | } | 51 | } |
52 | 52 | ||
53 | fn evaluate_struct_def_fields(&mut self) -> Option<()> { | 53 | fn evaluate_struct_def_fields(&mut self) -> Option<()> { |
54 | let function = function_from_child_node( | 54 | let analyzer = hir::SourceAnalyzer::new( |
55 | self.ctx.db, | 55 | self.ctx.db, |
56 | self.ctx.frange.file_id, | 56 | self.ctx.frange.file_id, |
57 | self.struct_lit.syntax(), | 57 | self.struct_lit.syntax(), |
58 | )?; | 58 | None, |
59 | let infer_result = function.infer(self.ctx.db); | 59 | ); |
60 | let source_map = function.body_source_map(self.ctx.db); | 60 | let struct_lit_ty = analyzer.type_of(self.ctx.db, self.struct_lit.into())?; |
61 | let node_expr = source_map.node_expr(self.struct_lit.into())?; | ||
62 | let struct_lit_ty = infer_result[node_expr].clone(); | ||
63 | let struct_def = match struct_lit_ty.as_adt() { | 61 | let struct_def = match struct_lit_ty.as_adt() { |
64 | Some((AdtDef::Struct(s), _)) => s, | 62 | Some((AdtDef::Struct(s), _)) => s, |
65 | _ => return None, | 63 | _ => return None, |
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs index 950c2910b..e0479ef13 100644 --- a/crates/ra_assists/src/inline_local_variable.rs +++ b/crates/ra_assists/src/inline_local_variable.rs | |||
@@ -1,7 +1,4 @@ | |||
1 | use hir::{ | 1 | use hir::db::HirDatabase; |
2 | db::HirDatabase, | ||
3 | source_binder::function_from_child_node, | ||
4 | }; | ||
5 | use ra_syntax::{ | 2 | use ra_syntax::{ |
6 | ast::{self, AstNode, AstToken, PatKind, ExprKind}, | 3 | ast::{self, AstNode, AstToken, PatKind, ExprKind}, |
7 | TextRange, | 4 | TextRange, |
@@ -29,10 +26,8 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
29 | } else { | 26 | } else { |
30 | let_stmt.syntax().range() | 27 | let_stmt.syntax().range() |
31 | }; | 28 | }; |
32 | 29 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, bind_pat.syntax(), None); | |
33 | let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?; | 30 | let refs = analyzer.find_all_refs(bind_pat); |
34 | let scope = function.scopes(ctx.db); | ||
35 | let refs = scope.find_all_refs(bind_pat); | ||
36 | 31 | ||
37 | let mut wrap_in_parens = vec![true; refs.len()]; | 32 | let mut wrap_in_parens = vec![true; refs.len()]; |
38 | 33 | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index c1514f8e5..ded401b63 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -86,6 +86,7 @@ where | |||
86 | } | 86 | } |
87 | 87 | ||
88 | mod add_derive; | 88 | mod add_derive; |
89 | mod add_explicit_type; | ||
89 | mod add_impl; | 90 | mod add_impl; |
90 | mod flip_comma; | 91 | mod flip_comma; |
91 | mod flip_binexpr; | 92 | mod flip_binexpr; |
@@ -103,6 +104,7 @@ mod add_missing_impl_members; | |||
103 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { | 104 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { |
104 | &[ | 105 | &[ |
105 | add_derive::add_derive, | 106 | add_derive::add_derive, |
107 | add_explicit_type::add_explicit_type, | ||
106 | add_impl::add_impl, | 108 | add_impl::add_impl, |
107 | change_visibility::change_visibility, | 109 | change_visibility::change_visibility, |
108 | fill_match_arms::fill_match_arms, | 110 | fill_match_arms::fill_match_arms, |
diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs index 4bf1852db..57e0efaf2 100644 --- a/crates/ra_assists/src/split_import.rs +++ b/crates/ra_assists/src/split_import.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | use std::iter::successors; | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | TextUnit, AstNode, SyntaxKind::COLONCOLON, | 5 | TextUnit, AstNode, SyntaxKind::COLONCOLON, |
4 | ast, | 6 | ast, |
5 | algo::generate, | ||
6 | }; | 7 | }; |
7 | 8 | ||
8 | use crate::{AssistCtx, Assist, AssistId}; | 9 | use crate::{AssistCtx, Assist, AssistId}; |
@@ -10,7 +11,7 @@ use crate::{AssistCtx, Assist, AssistId}; | |||
10 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 11 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; | 12 | let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; |
12 | let path = ast::Path::cast(colon_colon.parent())?; | 13 | let path = ast::Path::cast(colon_colon.parent())?; |
13 | let top_path = generate(Some(path), |it| it.parent_path()).last()?; | 14 | let top_path = successors(Some(path), |it| it.parent_path()).last()?; |
14 | 15 | ||
15 | let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); | 16 | let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); |
16 | if use_tree.is_none() { | 17 | if use_tree.is_none() { |