aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/call_info.rs16
-rw-r--r--crates/ra_ide_api/src/completion.rs19
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs30
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs10
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs12
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs9
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs35
-rw-r--r--crates/ra_ide_api/src/hover.rs50
-rw-r--r--crates/ra_ide_api/src/imp.rs51
-rw-r--r--crates/ra_ide_api/src/lib.rs31
-rw-r--r--crates/ra_ide_api/src/parent_module.rs11
-rw-r--r--crates/ra_ide_api/src/runnables.rs9
12 files changed, 114 insertions, 169 deletions
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index efa320d83..18b9508ef 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -1,6 +1,6 @@
1use std::cmp::{max, min}; 1use std::cmp::{max, min};
2 2
3use ra_db::{SyntaxDatabase, Cancelable}; 3use ra_db::SyntaxDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 AstNode, SyntaxNode, TextUnit, TextRange, 5 AstNode, SyntaxNode, TextUnit, TextRange,
6 SyntaxKind::FN_DEF, 6 SyntaxKind::FN_DEF,
@@ -11,21 +11,23 @@ use ra_syntax::{
11use crate::{FilePosition, CallInfo, db::RootDatabase}; 11use crate::{FilePosition, CallInfo, db::RootDatabase};
12 12
13/// Computes parameter information for the given call expression. 13/// Computes parameter information for the given call expression.
14pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable<Option<CallInfo>> { 14pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
15 let file = db.source_file(position.file_id); 15 let file = db.source_file(position.file_id);
16 let syntax = file.syntax(); 16 let syntax = file.syntax();
17 17
18 // Find the calling expression and it's NameRef 18 // Find the calling expression and it's NameRef
19 let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset)); 19 let calling_node = FnCallNode::with_node(syntax, position.offset)?;
20 let name_ref = ctry!(calling_node.name_ref()); 20 let name_ref = calling_node.name_ref()?;
21 21
22 // Resolve the function's NameRef (NOTE: this isn't entirely accurate). 22 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
23 let file_symbols = db.index_resolve(name_ref); 23 let file_symbols = db.index_resolve(name_ref);
24 let symbol = ctry!(file_symbols.into_iter().find(|it| it.ptr.kind() == FN_DEF)); 24 let symbol = file_symbols
25 .into_iter()
26 .find(|it| it.ptr.kind() == FN_DEF)?;
25 let fn_file = db.source_file(symbol.file_id); 27 let fn_file = db.source_file(symbol.file_id);
26 let fn_def = symbol.ptr.resolve(&fn_file); 28 let fn_def = symbol.ptr.resolve(&fn_file);
27 let fn_def = ast::FnDef::cast(&fn_def).unwrap(); 29 let fn_def = ast::FnDef::cast(&fn_def).unwrap();
28 let mut call_info = ctry!(CallInfo::new(fn_def)); 30 let mut call_info = CallInfo::new(fn_def)?;
29 // If we have a calling expression let's find which argument we are on 31 // If we have a calling expression let's find which argument we are on
30 let num_params = call_info.parameters.len(); 32 let num_params = call_info.parameters.len();
31 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 33 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
@@ -61,7 +63,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable
61 } 63 }
62 } 64 }
63 65
64 Ok(Some(call_info)) 66 Some(call_info)
65} 67}
66 68
67enum FnCallNode<'a> { 69enum FnCallNode<'a> {
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index ce777a771..b03ddd74c 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -12,7 +12,7 @@ use ra_db::SyntaxDatabase;
12 12
13use crate::{ 13use crate::{
14 db, 14 db,
15 Cancelable, FilePosition, 15 FilePosition,
16 completion::{ 16 completion::{
17 completion_item::{Completions, CompletionKind}, 17 completion_item::{Completions, CompletionKind},
18 completion_context::CompletionContext, 18 completion_context::CompletionContext,
@@ -43,12 +43,9 @@ pub use crate::completion::completion_item::{CompletionItem, InsertText, Complet
43/// `foo` *should* be present among the completion variants. Filtering by 43/// `foo` *should* be present among the completion variants. Filtering by
44/// identifier prefix/fuzzy match should be done higher in the stack, together 44/// identifier prefix/fuzzy match should be done higher in the stack, together
45/// with ordering of completions (currently this is done by the client). 45/// with ordering of completions (currently this is done by the client).
46pub(crate) fn completions( 46pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Option<Completions> {
47 db: &db::RootDatabase,
48 position: FilePosition,
49) -> Cancelable<Option<Completions>> {
50 let original_file = db.source_file(position.file_id); 47 let original_file = db.source_file(position.file_id);
51 let ctx = ctry!(CompletionContext::new(db, &original_file, position)?); 48 let ctx = CompletionContext::new(db, &original_file, position)?;
52 49
53 let mut acc = Completions::default(); 50 let mut acc = Completions::default();
54 51
@@ -57,11 +54,11 @@ pub(crate) fn completions(
57 complete_keyword::complete_use_tree_keyword(&mut acc, &ctx); 54 complete_keyword::complete_use_tree_keyword(&mut acc, &ctx);
58 complete_snippet::complete_expr_snippet(&mut acc, &ctx); 55 complete_snippet::complete_expr_snippet(&mut acc, &ctx);
59 complete_snippet::complete_item_snippet(&mut acc, &ctx); 56 complete_snippet::complete_item_snippet(&mut acc, &ctx);
60 complete_path::complete_path(&mut acc, &ctx)?; 57 complete_path::complete_path(&mut acc, &ctx);
61 complete_scope::complete_scope(&mut acc, &ctx)?; 58 complete_scope::complete_scope(&mut acc, &ctx);
62 complete_dot::complete_dot(&mut acc, &ctx)?; 59 complete_dot::complete_dot(&mut acc, &ctx);
63 60
64 Ok(Some(acc)) 61 Some(acc)
65} 62}
66 63
67#[cfg(test)] 64#[cfg(test)]
@@ -72,6 +69,6 @@ fn check_completion(code: &str, expected_completions: &str, kind: CompletionKind
72 } else { 69 } else {
73 single_file_with_position(code) 70 single_file_with_position(code)
74 }; 71 };
75 let completions = completions(&analysis.db, position).unwrap().unwrap(); 72 let completions = completions(&analysis.db, position).unwrap();
76 completions.assert_match(expected_completions, kind); 73 completions.assert_match(expected_completions, kind);
77} 74}
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index cb86ba9a3..473edc50e 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -1,29 +1,27 @@
1use hir::{Ty, Def}; 1use hir::{Ty, Def};
2 2
3use crate::Cancelable;
4use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem, CompletionItemKind}; 3use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem, CompletionItemKind};
5 4
6/// Complete dot accesses, i.e. fields or methods (currently only fields). 5/// Complete dot accesses, i.e. fields or methods (currently only fields).
7pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { 6pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
8 let (function, receiver) = match (&ctx.function, ctx.dot_receiver) { 7 let (function, receiver) = match (&ctx.function, ctx.dot_receiver) {
9 (Some(function), Some(receiver)) => (function, receiver), 8 (Some(function), Some(receiver)) => (function, receiver),
10 _ => return Ok(()), 9 _ => return,
11 }; 10 };
12 let infer_result = function.infer(ctx.db)?; 11 let infer_result = function.infer(ctx.db);
13 let syntax_mapping = function.body_syntax_mapping(ctx.db); 12 let syntax_mapping = function.body_syntax_mapping(ctx.db);
14 let expr = match syntax_mapping.node_expr(receiver) { 13 let expr = match syntax_mapping.node_expr(receiver) {
15 Some(expr) => expr, 14 Some(expr) => expr,
16 None => return Ok(()), 15 None => return,
17 }; 16 };
18 let receiver_ty = infer_result[expr].clone(); 17 let receiver_ty = infer_result[expr].clone();
19 if !ctx.is_call { 18 if !ctx.is_call {
20 complete_fields(acc, ctx, receiver_ty.clone())?; 19 complete_fields(acc, ctx, receiver_ty.clone());
21 } 20 }
22 complete_methods(acc, ctx, receiver_ty)?; 21 complete_methods(acc, ctx, receiver_ty);
23 Ok(())
24} 22}
25 23
26fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) -> Cancelable<()> { 24fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
27 for receiver in receiver.autoderef(ctx.db) { 25 for receiver in receiver.autoderef(ctx.db) {
28 match receiver { 26 match receiver {
29 Ty::Adt { def_id, .. } => { 27 Ty::Adt { def_id, .. } => {
@@ -35,7 +33,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
35 field.name().to_string(), 33 field.name().to_string(),
36 ) 34 )
37 .kind(CompletionItemKind::Field) 35 .kind(CompletionItemKind::Field)
38 .set_detail(field.ty(ctx.db)?.map(|ty| ty.to_string())) 36 .set_detail(field.ty(ctx.db).map(|ty| ty.to_string()))
39 .add_to(acc); 37 .add_to(acc);
40 } 38 }
41 } 39 }
@@ -53,14 +51,9 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
53 _ => {} 51 _ => {}
54 }; 52 };
55 } 53 }
56 Ok(())
57} 54}
58 55
59fn complete_methods( 56fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
60 acc: &mut Completions,
61 ctx: &CompletionContext,
62 receiver: Ty,
63) -> Cancelable<()> {
64 receiver.iterate_methods(ctx.db, |func| { 57 receiver.iterate_methods(ctx.db, |func| {
65 let sig = func.signature(ctx.db); 58 let sig = func.signature(ctx.db);
66 if sig.has_self_param() { 59 if sig.has_self_param() {
@@ -69,9 +62,8 @@ fn complete_methods(
69 .kind(CompletionItemKind::Method) 62 .kind(CompletionItemKind::Method)
70 .add_to(acc); 63 .add_to(acc);
71 } 64 }
72 Ok(None::<()>) 65 None::<()>
73 })?; 66 });
74 Ok(())
75} 67}
76 68
77#[cfg(test)] 69#[cfg(test)]
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 42468681a..1eded7658 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -1,16 +1,15 @@
1use crate::{ 1use crate::{
2 Cancelable,
3 completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, 2 completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext},
4}; 3};
5 4
6pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { 5pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
7 let (path, module) = match (&ctx.path_prefix, &ctx.module) { 6 let (path, module) = match (&ctx.path_prefix, &ctx.module) {
8 (Some(path), Some(module)) => (path.clone(), module), 7 (Some(path), Some(module)) => (path.clone(), module),
9 _ => return Ok(()), 8 _ => return,
10 }; 9 };
11 let def_id = match module.resolve_path(ctx.db, &path).take_types() { 10 let def_id = match module.resolve_path(ctx.db, &path).take_types() {
12 Some(it) => it, 11 Some(it) => it,
13 None => return Ok(()), 12 None => return,
14 }; 13 };
15 match def_id.resolve(ctx.db) { 14 match def_id.resolve(ctx.db) {
16 hir::Def::Module(module) => { 15 hir::Def::Module(module) => {
@@ -30,9 +29,8 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
30 .add_to(acc) 29 .add_to(acc)
31 }); 30 });
32 } 31 }
33 _ => return Ok(()), 32 _ => return,
34 }; 33 };
35 Ok(())
36} 34}
37 35
38#[cfg(test)] 36#[cfg(test)]
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 660c7d16e..699680748 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -1,18 +1,15 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2use ra_syntax::TextUnit; 2use ra_syntax::TextUnit;
3 3
4use crate::{ 4use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext};
5 Cancelable,
6 completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext},
7};
8 5
9pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { 6pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
10 if !ctx.is_trivial_path { 7 if !ctx.is_trivial_path {
11 return Ok(()); 8 return;
12 } 9 }
13 let module = match &ctx.module { 10 let module = match &ctx.module {
14 Some(it) => it, 11 Some(it) => it,
15 None => return Ok(()), 12 None => return,
16 }; 13 };
17 if let Some(function) = &ctx.function { 14 if let Some(function) = &ctx.function {
18 let scopes = function.scopes(ctx.db); 15 let scopes = function.scopes(ctx.db);
@@ -40,7 +37,6 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
40 .from_resolution(ctx, res) 37 .from_resolution(ctx, res)
41 .add_to(acc) 38 .add_to(acc)
42 }); 39 });
43 Ok(())
44} 40}
45 41
46fn complete_fn(acc: &mut Completions, scopes: &hir::ScopesWithSyntaxMapping, offset: TextUnit) { 42fn complete_fn(acc: &mut Completions, scopes: &hir::ScopesWithSyntaxMapping, offset: TextUnit) {
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index f5b5ed689..e537e0082 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7}; 7};
8use hir::source_binder; 8use hir::source_binder;
9 9
10use crate::{db, FilePosition, Cancelable}; 10use crate::{db, FilePosition};
11 11
12/// `CompletionContext` is created early during completion to figure out, where 12/// `CompletionContext` is created early during completion to figure out, where
13/// exactly is the cursor, syntax-wise. 13/// exactly is the cursor, syntax-wise.
@@ -41,10 +41,9 @@ impl<'a> CompletionContext<'a> {
41 db: &'a db::RootDatabase, 41 db: &'a db::RootDatabase,
42 original_file: &'a SourceFile, 42 original_file: &'a SourceFile,
43 position: FilePosition, 43 position: FilePosition,
44 ) -> Cancelable<Option<CompletionContext<'a>>> { 44 ) -> Option<CompletionContext<'a>> {
45 let module = source_binder::module_from_position(db, position); 45 let module = source_binder::module_from_position(db, position);
46 let leaf = 46 let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?;
47 ctry!(find_leaf_at_offset(original_file.syntax(), position.offset).left_biased());
48 let mut ctx = CompletionContext { 47 let mut ctx = CompletionContext {
49 db, 48 db,
50 leaf, 49 leaf,
@@ -63,7 +62,7 @@ impl<'a> CompletionContext<'a> {
63 is_call: false, 62 is_call: false,
64 }; 63 };
65 ctx.fill(original_file, position.offset); 64 ctx.fill(original_file, position.offset);
66 Ok(Some(ctx)) 65 Some(ctx)
67 } 66 }
68 67
69 fn fill(&mut self, original_file: &'a SourceFile, offset: TextUnit) { 68 fn fill(&mut self, original_file: &'a SourceFile, offset: TextUnit) {
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index cdd8e211d..b1becca03 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -1,4 +1,4 @@
1use ra_db::{FileId, Cancelable, SyntaxDatabase}; 1use ra_db::{FileId, SyntaxDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, ast, 3 AstNode, ast,
4 algo::find_node_at_offset, 4 algo::find_node_at_offset,
@@ -9,21 +9,18 @@ use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
9pub(crate) fn goto_definition( 9pub(crate) fn goto_definition(
10 db: &RootDatabase, 10 db: &RootDatabase,
11 position: FilePosition, 11 position: FilePosition,
12) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { 12) -> Option<RangeInfo<Vec<NavigationTarget>>> {
13 let file = db.source_file(position.file_id); 13 let file = db.source_file(position.file_id);
14 let syntax = file.syntax(); 14 let syntax = file.syntax();
15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
16 let navs = reference_definition(db, position.file_id, name_ref)?.to_vec(); 16 let navs = reference_definition(db, position.file_id, name_ref).to_vec();
17 return Ok(Some(RangeInfo::new( 17 return Some(RangeInfo::new(name_ref.syntax().range(), navs.to_vec()));
18 name_ref.syntax().range(),
19 navs.to_vec(),
20 )));
21 } 18 }
22 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { 19 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
23 let navs = ctry!(name_definition(db, position.file_id, name)?); 20 let navs = name_definition(db, position.file_id, name)?;
24 return Ok(Some(RangeInfo::new(name.syntax().range(), navs))); 21 return Some(RangeInfo::new(name.syntax().range(), navs));
25 } 22 }
26 Ok(None) 23 None
27} 24}
28 25
29pub(crate) enum ReferenceResult { 26pub(crate) enum ReferenceResult {
@@ -45,7 +42,7 @@ pub(crate) fn reference_definition(
45 db: &RootDatabase, 42 db: &RootDatabase,
46 file_id: FileId, 43 file_id: FileId,
47 name_ref: &ast::NameRef, 44 name_ref: &ast::NameRef,
48) -> Cancelable<ReferenceResult> { 45) -> ReferenceResult {
49 use self::ReferenceResult::*; 46 use self::ReferenceResult::*;
50 if let Some(function) = 47 if let Some(function) =
51 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()) 48 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())
@@ -54,7 +51,7 @@ pub(crate) fn reference_definition(
54 // First try to resolve the symbol locally 51 // First try to resolve the symbol locally
55 if let Some(entry) = scope.resolve_local_name(name_ref) { 52 if let Some(entry) = scope.resolve_local_name(name_ref) {
56 let nav = NavigationTarget::from_scope_entry(file_id, &entry); 53 let nav = NavigationTarget::from_scope_entry(file_id, &entry);
57 return Ok(Exact(nav)); 54 return Exact(nav);
58 }; 55 };
59 56
60 // Next check if it is a method 57 // Next check if it is a method
@@ -63,7 +60,7 @@ pub(crate) fn reference_definition(
63 .parent() 60 .parent()
64 .and_then(ast::MethodCallExpr::cast) 61 .and_then(ast::MethodCallExpr::cast)
65 { 62 {
66 let infer_result = function.infer(db)?; 63 let infer_result = function.infer(db);
67 let syntax_mapping = function.body_syntax_mapping(db); 64 let syntax_mapping = function.body_syntax_mapping(db);
68 let expr = ast::Expr::cast(method_call.syntax()).unwrap(); 65 let expr = ast::Expr::cast(method_call.syntax()).unwrap();
69 if let Some(def_id) = syntax_mapping 66 if let Some(def_id) = syntax_mapping
@@ -71,7 +68,7 @@ pub(crate) fn reference_definition(
71 .and_then(|it| infer_result.method_resolution(it)) 68 .and_then(|it| infer_result.method_resolution(it))
72 { 69 {
73 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)) { 70 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)) {
74 return Ok(Exact(target)); 71 return Exact(target);
75 } 72 }
76 }; 73 };
77 } 74 }
@@ -88,7 +85,7 @@ pub(crate) fn reference_definition(
88 let resolved = module.resolve_path(db, &path); 85 let resolved = module.resolve_path(db, &path);
89 if let Some(def_id) = resolved.take_types().or(resolved.take_values()) { 86 if let Some(def_id) = resolved.take_types().or(resolved.take_values()) {
90 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)) { 87 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)) {
91 return Ok(Exact(target)); 88 return Exact(target);
92 } 89 }
93 } 90 }
94 } 91 }
@@ -99,25 +96,25 @@ pub(crate) fn reference_definition(
99 .into_iter() 96 .into_iter()
100 .map(NavigationTarget::from_symbol) 97 .map(NavigationTarget::from_symbol)
101 .collect(); 98 .collect();
102 Ok(Approximate(navs)) 99 Approximate(navs)
103} 100}
104 101
105fn name_definition( 102fn name_definition(
106 db: &RootDatabase, 103 db: &RootDatabase,
107 file_id: FileId, 104 file_id: FileId,
108 name: &ast::Name, 105 name: &ast::Name,
109) -> Cancelable<Option<Vec<NavigationTarget>>> { 106) -> Option<Vec<NavigationTarget>> {
110 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 107 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
111 if module.has_semi() { 108 if module.has_semi() {
112 if let Some(child_module) = 109 if let Some(child_module) =
113 hir::source_binder::module_from_declaration(db, file_id, module) 110 hir::source_binder::module_from_declaration(db, file_id, module)
114 { 111 {
115 let nav = NavigationTarget::from_module(db, child_module); 112 let nav = NavigationTarget::from_module(db, child_module);
116 return Ok(Some(vec![nav])); 113 return Some(vec![nav]);
117 } 114 }
118 } 115 }
119 } 116 }
120 Ok(None) 117 None
121} 118}
122 119
123#[cfg(test)] 120#[cfg(test)]
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 0e9c48421..d91151c15 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,4 +1,4 @@
1use ra_db::{Cancelable, SyntaxDatabase}; 1use ra_db::{SyntaxDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TreeArc, 3 AstNode, SyntaxNode, TreeArc,
4 ast::self, 4 ast::self,
@@ -7,19 +7,16 @@ use ra_syntax::{
7 7
8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; 8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget};
9 9
10pub(crate) fn hover( 10pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<String>> {
11 db: &RootDatabase,
12 position: FilePosition,
13) -> Cancelable<Option<RangeInfo<String>>> {
14 let file = db.source_file(position.file_id); 11 let file = db.source_file(position.file_id);
15 let mut res = Vec::new(); 12 let mut res = Vec::new();
16 13
17 let mut range = None; 14 let mut range = None;
18 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
19 use crate::goto_definition::{ReferenceResult::*, reference_definition}; 16 use crate::goto_definition::{ReferenceResult::*, reference_definition};
20 let ref_result = reference_definition(db, position.file_id, name_ref)?; 17 let ref_result = reference_definition(db, position.file_id, name_ref);
21 match ref_result { 18 match ref_result {
22 Exact(nav) => res.extend(doc_text_for(db, nav)?), 19 Exact(nav) => res.extend(doc_text_for(db, nav)),
23 Approximate(navs) => { 20 Approximate(navs) => {
24 let mut msg = String::from("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support glob imports or traits."); 21 let mut msg = String::from("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support glob imports or traits.");
25 if !navs.is_empty() { 22 if !navs.is_empty() {
@@ -27,7 +24,7 @@ pub(crate) fn hover(
27 } 24 }
28 res.push(msg); 25 res.push(msg);
29 for nav in navs { 26 for nav in navs {
30 res.extend(doc_text_for(db, nav)?) 27 res.extend(doc_text_for(db, nav))
31 } 28 }
32 } 29 }
33 } 30 }
@@ -39,25 +36,24 @@ pub(crate) fn hover(
39 let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| { 36 let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| {
40 leaf.ancestors() 37 leaf.ancestors()
41 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) 38 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
42 }); 39 })?;
43 let node = ctry!(node);
44 let frange = FileRange { 40 let frange = FileRange {
45 file_id: position.file_id, 41 file_id: position.file_id,
46 range: node.range(), 42 range: node.range(),
47 }; 43 };
48 res.extend(type_of(db, frange)?.map(Into::into)); 44 res.extend(type_of(db, frange).map(Into::into));
49 range = Some(node.range()); 45 range = Some(node.range());
50 }; 46 };
51 47
52 let range = ctry!(range); 48 let range = range?;
53 if res.is_empty() { 49 if res.is_empty() {
54 return Ok(None); 50 return None;
55 } 51 }
56 let res = RangeInfo::new(range, res.join("\n\n---\n")); 52 let res = RangeInfo::new(range, res.join("\n\n---\n"));
57 Ok(Some(res)) 53 Some(res)
58} 54}
59 55
60pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option<String>> { 56pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
61 let file = db.source_file(frange.file_id); 57 let file = db.source_file(frange.file_id);
62 let syntax = file.syntax(); 58 let syntax = file.syntax();
63 let leaf_node = find_covering_node(syntax, frange.range); 59 let leaf_node = find_covering_node(syntax, frange.range);
@@ -67,34 +63,28 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option
67 .take_while(|it| it.range() == leaf_node.range()) 63 .take_while(|it| it.range() == leaf_node.range())
68 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some()) 64 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())
69 .unwrap_or(leaf_node); 65 .unwrap_or(leaf_node);
70 let parent_fn = ctry!(node.ancestors().find_map(ast::FnDef::cast)); 66 let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?;
71 let function = ctry!(hir::source_binder::function_from_source( 67 let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?;
72 db, 68 let infer = function.infer(db);
73 frange.file_id,
74 parent_fn
75 ));
76 let infer = function.infer(db)?;
77 let syntax_mapping = function.body_syntax_mapping(db); 69 let syntax_mapping = function.body_syntax_mapping(db);
78 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) { 70 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) {
79 Ok(Some(infer[expr].to_string())) 71 Some(infer[expr].to_string())
80 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) { 72 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) {
81 Ok(Some(infer[pat].to_string())) 73 Some(infer[pat].to_string())
82 } else { 74 } else {
83 Ok(None) 75 None
84 } 76 }
85} 77}
86 78
87// FIXME: this should not really use navigation target. Rather, approximatelly 79// FIXME: this should not really use navigation target. Rather, approximatelly
88// resovled symbol should return a `DefId`. 80// resovled symbol should return a `DefId`.
89fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Cancelable<Option<String>> { 81fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
90 let result = match (nav.description(db), nav.docs(db)) { 82 match (nav.description(db), nav.docs(db)) {
91 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), 83 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs),
92 (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"), 84 (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"),
93 (None, Some(docs)) => Some(docs), 85 (None, Some(docs)) => Some(docs),
94 _ => None, 86 _ => None,
95 }; 87 }
96
97 Ok(result)
98} 88}
99 89
100impl NavigationTarget { 90impl NavigationTarget {
diff --git a/crates/ra_ide_api/src/imp.rs b/crates/ra_ide_api/src/imp.rs
index 8b2cd6e27..a21cae624 100644
--- a/crates/ra_ide_api/src/imp.rs
+++ b/crates/ra_ide_api/src/imp.rs
@@ -110,14 +110,11 @@ impl db::RootDatabase {
110 }; 110 };
111 vec![krate.crate_id()] 111 vec![krate.crate_id()]
112 } 112 }
113 pub(crate) fn find_all_refs( 113 pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
114 &self,
115 position: FilePosition,
116 ) -> Cancelable<Vec<(FileId, TextRange)>> {
117 let file = self.source_file(position.file_id); 114 let file = self.source_file(position.file_id);
118 // Find the binding associated with the offset 115 // Find the binding associated with the offset
119 let (binding, descr) = match find_binding(self, &file, position)? { 116 let (binding, descr) = match find_binding(self, &file, position) {
120 None => return Ok(Vec::new()), 117 None => return Vec::new(),
121 Some(it) => it, 118 Some(it) => it,
122 }; 119 };
123 120
@@ -134,36 +131,30 @@ impl db::RootDatabase {
134 .map(|ref_desc| (position.file_id, ref_desc.range)), 131 .map(|ref_desc| (position.file_id, ref_desc.range)),
135 ); 132 );
136 133
137 return Ok(ret); 134 return ret;
138 135
139 fn find_binding<'a>( 136 fn find_binding<'a>(
140 db: &db::RootDatabase, 137 db: &db::RootDatabase,
141 source_file: &'a SourceFile, 138 source_file: &'a SourceFile,
142 position: FilePosition, 139 position: FilePosition,
143 ) -> Cancelable<Option<(&'a ast::BindPat, hir::Function)>> { 140 ) -> Option<(&'a ast::BindPat, hir::Function)> {
144 let syntax = source_file.syntax(); 141 let syntax = source_file.syntax();
145 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { 142 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
146 let descr = ctry!(source_binder::function_from_child_node( 143 let descr = source_binder::function_from_child_node(
147 db, 144 db,
148 position.file_id, 145 position.file_id,
149 binding.syntax(), 146 binding.syntax(),
150 )); 147 )?;
151 return Ok(Some((binding, descr))); 148 return Some((binding, descr));
152 }; 149 };
153 let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset)); 150 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
154 let descr = ctry!(source_binder::function_from_child_node( 151 let descr =
155 db, 152 source_binder::function_from_child_node(db, position.file_id, name_ref.syntax())?;
156 position.file_id,
157 name_ref.syntax(),
158 ));
159 let scope = descr.scopes(db); 153 let scope = descr.scopes(db);
160 let resolved = ctry!(scope.resolve_local_name(name_ref)); 154 let resolved = scope.resolve_local_name(name_ref)?;
161 let resolved = resolved.ptr().resolve(source_file); 155 let resolved = resolved.ptr().resolve(source_file);
162 let binding = ctry!(find_node_at_offset::<ast::BindPat>( 156 let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?;
163 syntax, 157 Some((binding, descr))
164 resolved.range().end()
165 ));
166 Ok(Some((binding, descr)))
167 } 158 }
168 } 159 }
169 160
@@ -180,7 +171,7 @@ impl db::RootDatabase {
180 }) 171 })
181 .collect::<Vec<_>>(); 172 .collect::<Vec<_>>();
182 if let Some(m) = source_binder::module_from_file_id(self, file_id) { 173 if let Some(m) = source_binder::module_from_file_id(self, file_id) {
183 for (name_node, problem) in m.problems(self)? { 174 for (name_node, problem) in m.problems(self) {
184 let source_root = self.file_source_root(file_id); 175 let source_root = self.file_source_root(file_id);
185 let diag = match problem { 176 let diag = match problem {
186 Problem::UnresolvedModule { candidate } => { 177 Problem::UnresolvedModule { candidate } => {
@@ -239,13 +230,8 @@ impl db::RootDatabase {
239 .collect() 230 .collect()
240 } 231 }
241 232
242 pub(crate) fn rename( 233 pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> {
243 &self, 234 self.find_all_refs(position)
244 position: FilePosition,
245 new_name: &str,
246 ) -> Cancelable<Vec<SourceFileEdit>> {
247 let res = self
248 .find_all_refs(position)?
249 .iter() 235 .iter()
250 .map(|(file_id, text_range)| SourceFileEdit { 236 .map(|(file_id, text_range)| SourceFileEdit {
251 file_id: *file_id, 237 file_id: *file_id,
@@ -255,8 +241,7 @@ impl db::RootDatabase {
255 builder.finish() 241 builder.finish()
256 }, 242 },
257 }) 243 })
258 .collect::<Vec<_>>(); 244 .collect::<Vec<_>>()
259 Ok(res)
260 } 245 }
261 pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> { 246 pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> {
262 let name = name_ref.text(); 247 let name = name_ref.text();
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 0f690fc84..ea5267ad9 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -9,15 +9,6 @@
9//! 9//!
10//! The sibling `ra_ide_api_light` handles thouse bits of IDE functionality 10//! The sibling `ra_ide_api_light` handles thouse bits of IDE functionality
11//! which are restricted to a single file and need only syntax. 11//! which are restricted to a single file and need only syntax.
12macro_rules! ctry {
13 ($expr:expr) => {
14 match $expr {
15 None => return Ok(None),
16 Some(it) => it,
17 }
18 };
19}
20
21mod db; 12mod db;
22mod imp; 13mod imp;
23pub mod mock_analysis; 14pub mod mock_analysis;
@@ -58,9 +49,11 @@ pub use ra_ide_api_light::{
58 LineIndex, LineCol, translate_offset_with_edit, 49 LineIndex, LineCol, translate_offset_with_edit,
59}; 50};
60pub use ra_db::{ 51pub use ra_db::{
61 Cancelable, Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 52 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId
62}; 53};
63 54
55pub type Cancelable<T> = Result<T, Canceled>;
56
64#[derive(Default)] 57#[derive(Default)]
65pub struct AnalysisChange { 58pub struct AnalysisChange {
66 new_roots: Vec<(SourceRootId, bool)>, 59 new_roots: Vec<(SourceRootId, bool)>,
@@ -393,28 +386,28 @@ impl Analysis {
393 position: FilePosition, 386 position: FilePosition,
394 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { 387 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
395 self.db 388 self.db
396 .catch_canceled(|db| goto_definition::goto_definition(db, position))? 389 .catch_canceled(|db| goto_definition::goto_definition(db, position))
397 } 390 }
398 391
399 /// Finds all usages of the reference at point. 392 /// Finds all usages of the reference at point.
400 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 393 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
401 self.with_db(|db| db.find_all_refs(position))? 394 self.with_db(|db| db.find_all_refs(position))
402 } 395 }
403 396
404 /// Returns a short text descrbing element at position. 397 /// Returns a short text descrbing element at position.
405 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { 398 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> {
406 self.with_db(|db| hover::hover(db, position))? 399 self.with_db(|db| hover::hover(db, position))
407 } 400 }
408 401
409 /// Computes parameter information for the given call expression. 402 /// Computes parameter information for the given call expression.
410 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { 403 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
411 self.db 404 self.db
412 .catch_canceled(|db| call_info::call_info(db, position))? 405 .catch_canceled(|db| call_info::call_info(db, position))
413 } 406 }
414 407
415 /// Returns a `mod name;` declaration which created the current module. 408 /// Returns a `mod name;` declaration which created the current module.
416 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { 409 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
417 self.with_db(|db| parent_module::parent_module(db, position))? 410 self.with_db(|db| parent_module::parent_module(db, position))
418 } 411 }
419 412
420 /// Returns crates this file belongs too. 413 /// Returns crates this file belongs too.
@@ -430,7 +423,7 @@ impl Analysis {
430 /// Returns the set of possible targets to run for the current file. 423 /// Returns the set of possible targets to run for the current file.
431 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { 424 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
432 self.db 425 self.db
433 .catch_canceled(|db| runnables::runnables(db, file_id))? 426 .catch_canceled(|db| runnables::runnables(db, file_id))
434 } 427 }
435 428
436 /// Computes syntax highlighting for the given file. 429 /// Computes syntax highlighting for the given file.
@@ -443,7 +436,7 @@ impl Analysis {
443 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { 436 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
444 let completions = self 437 let completions = self
445 .db 438 .db
446 .catch_canceled(|db| completion::completions(db, position))??; 439 .catch_canceled(|db| completion::completions(db, position))?;
447 Ok(completions.map(|it| it.into())) 440 Ok(completions.map(|it| it.into()))
448 } 441 }
449 442
@@ -460,7 +453,7 @@ impl Analysis {
460 453
461 /// Computes the type of the expression at the given position. 454 /// Computes the type of the expression at the given position.
462 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { 455 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> {
463 self.with_db(|db| hover::type_of(db, frange))? 456 self.with_db(|db| hover::type_of(db, frange))
464 } 457 }
465 458
466 /// Returns the edit required to rename reference at the position to the new 459 /// Returns the edit required to rename reference at the position to the new
@@ -470,7 +463,7 @@ impl Analysis {
470 position: FilePosition, 463 position: FilePosition,
471 new_name: &str, 464 new_name: &str,
472 ) -> Cancelable<Vec<SourceFileEdit>> { 465 ) -> Cancelable<Vec<SourceFileEdit>> {
473 self.with_db(|db| db.rename(position, new_name))? 466 self.with_db(|db| db.rename(position, new_name))
474 } 467 }
475 468
476 fn with_db<F: FnOnce(&db::RootDatabase) -> T + std::panic::UnwindSafe, T>( 469 fn with_db<F: FnOnce(&db::RootDatabase) -> T + std::panic::UnwindSafe, T>(
diff --git a/crates/ra_ide_api/src/parent_module.rs b/crates/ra_ide_api/src/parent_module.rs
index 379b3f3a4..e94297fe3 100644
--- a/crates/ra_ide_api/src/parent_module.rs
+++ b/crates/ra_ide_api/src/parent_module.rs
@@ -1,19 +1,16 @@
1use ra_db::{Cancelable, FilePosition}; 1use ra_db::FilePosition;
2 2
3use crate::{NavigationTarget, db::RootDatabase}; 3use crate::{NavigationTarget, db::RootDatabase};
4 4
5/// This returns `Vec` because a module may be included from several places. We 5/// This returns `Vec` because a module may be included from several places. We
6/// don't handle this case yet though, so the Vec has length at most one. 6/// don't handle this case yet though, so the Vec has length at most one.
7pub(crate) fn parent_module( 7pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
8 db: &RootDatabase,
9 position: FilePosition,
10) -> Cancelable<Vec<NavigationTarget>> {
11 let module = match hir::source_binder::module_from_position(db, position) { 8 let module = match hir::source_binder::module_from_position(db, position) {
12 None => return Ok(Vec::new()), 9 None => return Vec::new(),
13 Some(it) => it, 10 Some(it) => it,
14 }; 11 };
15 let nav = NavigationTarget::from_module_to_decl(db, module); 12 let nav = NavigationTarget::from_module_to_decl(db, module);
16 Ok(vec![nav]) 13 vec![nav]
17} 14}
18 15
19#[cfg(test)] 16#[cfg(test)]
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index a3207fdd2..0f9f8deb3 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 TextRange, SyntaxNode, 3 TextRange, SyntaxNode,
4 ast::{self, AstNode, NameOwner, ModuleItemOwner}, 4 ast::{self, AstNode, NameOwner, ModuleItemOwner},
5}; 5};
6use ra_db::{Cancelable, SyntaxDatabase}; 6use ra_db::SyntaxDatabase;
7 7
8use crate::{db::RootDatabase, FileId}; 8use crate::{db::RootDatabase, FileId};
9 9
@@ -21,14 +21,13 @@ pub enum RunnableKind {
21 Bin, 21 Bin,
22} 22}
23 23
24pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Runnable>> { 24pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
25 let source_file = db.source_file(file_id); 25 let source_file = db.source_file(file_id);
26 let res = source_file 26 source_file
27 .syntax() 27 .syntax()
28 .descendants() 28 .descendants()
29 .filter_map(|i| runnable(db, file_id, i)) 29 .filter_map(|i| runnable(db, file_id, i))
30 .collect(); 30 .collect()
31 Ok(res)
32} 31}
33 32
34fn runnable(db: &RootDatabase, file_id: FileId, item: &SyntaxNode) -> Option<Runnable> { 33fn runnable(db: &RootDatabase, file_id: FileId, item: &SyntaxNode) -> Option<Runnable> {