aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/add_explicit_type.rs89
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs15
-rw-r--r--crates/ra_assists/src/fill_match_arms.rs10
-rw-r--r--crates/ra_assists/src/fill_struct_fields.rs12
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs11
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/split_import.rs5
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 @@
1use hir::{
2 HirDisplay, Ty,
3 db::HirDatabase,
4};
5use ra_syntax::{
6 SyntaxKind,
7 ast::{LetStmt, PatKind, NameOwner, AstNode}
8};
9
10use crate::{AssistCtx, Assist, AssistId};
11
12/// Add explicit type assist.
13pub(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
47fn 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)]
56mod 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
3use crate::{Assist, AssistId, AssistCtx}; 3use crate::{Assist, AssistId, AssistCtx};
4 4
5use hir::Resolver;
6use hir::db::HirDatabase; 5use hir::db::HirDatabase;
7use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; 6use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc};
8use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner}; 7use 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`.
123fn resolve_target_trait_def( 122fn 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 @@
1use std::fmt::Write; 1use std::fmt::Write;
2 2
3use hir::{ 3use hir::{
4 AdtDef, FieldSource, source_binder, 4 AdtDef, FieldSource,
5 db::HirDatabase, 5 db::HirDatabase,
6}; 6};
7use ra_syntax::ast::{self, AstNode}; 7use 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 @@
1use std::fmt::Write; 1use std::fmt::Write;
2 2
3use hir::{AdtDef, db::HirDatabase, source_binder::function_from_child_node}; 3use hir::{AdtDef, db::HirDatabase};
4 4
5use ra_syntax::ast::{self, AstNode}; 5use 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 @@
1use hir::{ 1use hir::db::HirDatabase;
2 db::HirDatabase,
3 source_binder::function_from_child_node,
4};
5use ra_syntax::{ 2use 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
88mod add_derive; 88mod add_derive;
89mod add_explicit_type;
89mod add_impl; 90mod add_impl;
90mod flip_comma; 91mod flip_comma;
91mod flip_binexpr; 92mod flip_binexpr;
@@ -103,6 +104,7 @@ mod add_missing_impl_members;
103fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { 104fn 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 @@
1use std::iter::successors;
2
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ 4use ra_syntax::{
3 TextUnit, AstNode, SyntaxKind::COLONCOLON, 5 TextUnit, AstNode, SyntaxKind::COLONCOLON,
4 ast, 6 ast,
5 algo::generate,
6}; 7};
7 8
8use crate::{AssistCtx, Assist, AssistId}; 9use crate::{AssistCtx, Assist, AssistId};
@@ -10,7 +11,7 @@ use crate::{AssistCtx, Assist, AssistId};
10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 11pub(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() {