diff options
Diffstat (limited to 'crates/ra_ide_api')
27 files changed, 528 insertions, 468 deletions
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml index d42a664b6..022cbd5a3 100644 --- a/crates/ra_ide_api/Cargo.toml +++ b/crates/ra_ide_api/Cargo.toml | |||
@@ -10,7 +10,7 @@ log = "0.4.5" | |||
10 | relative-path = "0.4.0" | 10 | relative-path = "0.4.0" |
11 | rayon = "1.0.2" | 11 | rayon = "1.0.2" |
12 | fst = "0.3.1" | 12 | fst = "0.3.1" |
13 | salsa = "0.9.1" | 13 | salsa = "0.9.2" |
14 | rustc-hash = "1.0" | 14 | rustc-hash = "1.0" |
15 | parking_lot = "0.7.0" | 15 | parking_lot = "0.7.0" |
16 | unicase = "2.2.0" | 16 | unicase = "2.2.0" |
@@ -21,3 +21,6 @@ ra_text_edit = { path = "../ra_text_edit" } | |||
21 | ra_db = { path = "../ra_db" } | 21 | ra_db = { path = "../ra_db" } |
22 | hir = { path = "../ra_hir", package = "ra_hir" } | 22 | hir = { path = "../ra_hir", package = "ra_hir" } |
23 | test_utils = { path = "../test_utils" } | 23 | test_utils = { path = "../test_utils" } |
24 | |||
25 | [dev-dependencies] | ||
26 | insta = "0.1.4" | ||
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 27b760780..18b9508ef 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::cmp::{max, min}; | 1 | use std::cmp::{max, min}; |
2 | 2 | ||
3 | use ra_db::{SyntaxDatabase, Cancelable}; | 3 | use ra_db::SyntaxDatabase; |
4 | use ra_syntax::{ | 4 | use 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::{ | |||
11 | use crate::{FilePosition, CallInfo, db::RootDatabase}; | 11 | use 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. |
14 | pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable<Option<CallInfo>> { | 14 | pub(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 | ||
67 | enum FnCallNode<'a> { | 69 | enum 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 | ||
13 | use crate::{ | 13 | use 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). |
46 | pub(crate) fn completions( | 46 | pub(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 37985b398..473edc50e 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -1,41 +1,39 @@ | |||
1 | use hir::{Ty, Def}; | 1 | use hir::{Ty, Def}; |
2 | 2 | ||
3 | use crate::Cancelable; | ||
4 | use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem, CompletionItemKind}; | 3 | use 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). |
7 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { | 6 | pub(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 | ||
26 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) -> Cancelable<()> { | 24 | fn 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, .. } => { |
30 | match def_id.resolve(ctx.db)? { | 28 | match def_id.resolve(ctx.db) { |
31 | Def::Struct(s) => { | 29 | Def::Struct(s) => { |
32 | for field in s.fields(ctx.db)? { | 30 | for field in s.fields(ctx.db) { |
33 | CompletionItem::new( | 31 | CompletionItem::new( |
34 | CompletionKind::Reference, | 32 | CompletionKind::Reference, |
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 | ||
59 | fn complete_methods( | 56 | fn 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 a25ad3f13..1eded7658 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -1,20 +1,19 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | Cancelable, | ||
3 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, | 2 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, |
4 | }; | 3 | }; |
5 | 4 | ||
6 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { | 5 | pub(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) => { |
17 | let module_scope = module.scope(ctx.db)?; | 16 | let module_scope = module.scope(ctx.db); |
18 | for (name, res) in module_scope.entries() { | 17 | for (name, res) in module_scope.entries() { |
19 | CompletionItem::new(CompletionKind::Reference, name.to_string()) | 18 | CompletionItem::new(CompletionKind::Reference, name.to_string()) |
20 | .from_resolution(ctx, res) | 19 | .from_resolution(ctx, res) |
@@ -22,7 +21,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C | |||
22 | } | 21 | } |
23 | } | 22 | } |
24 | hir::Def::Enum(e) => { | 23 | hir::Def::Enum(e) => { |
25 | e.variants(ctx.db)? | 24 | e.variants(ctx.db) |
26 | .into_iter() | 25 | .into_iter() |
27 | .for_each(|(variant_name, _variant)| { | 26 | .for_each(|(variant_name, _variant)| { |
28 | CompletionItem::new(CompletionKind::Reference, variant_name.to_string()) | 27 | CompletionItem::new(CompletionKind::Reference, variant_name.to_string()) |
@@ -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 770a0fdf2..699680748 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs | |||
@@ -1,26 +1,23 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | use ra_syntax::TextUnit; | 2 | use ra_syntax::TextUnit; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}; |
5 | Cancelable, | ||
6 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, | ||
7 | }; | ||
8 | 5 | ||
9 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { | 6 | pub(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); |
19 | complete_fn(acc, &scopes, ctx.offset); | 16 | complete_fn(acc, &scopes, ctx.offset); |
20 | } | 17 | } |
21 | 18 | ||
22 | let module_scope = module.scope(ctx.db)?; | 19 | let module_scope = module.scope(ctx.db); |
23 | let (file_id, _) = module.definition_source(ctx.db)?; | 20 | let (file_id, _) = module.definition_source(ctx.db); |
24 | module_scope | 21 | module_scope |
25 | .entries() | 22 | .entries() |
26 | .filter(|(_name, res)| { | 23 | .filter(|(_name, res)| { |
@@ -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 | ||
46 | fn complete_fn(acc: &mut Completions, scopes: &hir::ScopesWithSyntaxMapping, offset: TextUnit) { | 42 | fn 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 113f6c070..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 | }; |
8 | use hir::source_binder; | 8 | use hir::source_binder; |
9 | 9 | ||
10 | use crate::{db, FilePosition, Cancelable}; | 10 | use 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/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index b75d65de3..11d00f78c 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs | |||
@@ -144,7 +144,7 @@ impl Builder { | |||
144 | ctx: &CompletionContext, | 144 | ctx: &CompletionContext, |
145 | resolution: &hir::Resolution, | 145 | resolution: &hir::Resolution, |
146 | ) -> Builder { | 146 | ) -> Builder { |
147 | let resolved = resolution.def_id.and_then(|d| d.resolve(ctx.db).ok()); | 147 | let resolved = resolution.def_id.map(|d| d.resolve(ctx.db)); |
148 | let kind = match resolved { | 148 | let kind = match resolved { |
149 | PerNs { | 149 | PerNs { |
150 | types: Some(hir::Def::Module(..)), | 150 | types: Some(hir::Def::Module(..)), |
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs index c3c809c9f..9f0ab2f1c 100644 --- a/crates/ra_ide_api/src/extend_selection.rs +++ b/crates/ra_ide_api/src/extend_selection.rs | |||
@@ -38,8 +38,9 @@ fn find_macro_call(node: &SyntaxNode, range: TextRange) -> Option<&ast::MacroCal | |||
38 | 38 | ||
39 | #[cfg(test)] | 39 | #[cfg(test)] |
40 | mod tests { | 40 | mod tests { |
41 | use ra_syntax::TextRange; | ||
42 | |||
41 | use crate::mock_analysis::single_file_with_range; | 43 | use crate::mock_analysis::single_file_with_range; |
42 | use test_utils::assert_eq_dbg; | ||
43 | 44 | ||
44 | #[test] | 45 | #[test] |
45 | fn extend_selection_inside_macros() { | 46 | fn extend_selection_inside_macros() { |
@@ -51,6 +52,6 @@ mod tests { | |||
51 | ", | 52 | ", |
52 | ); | 53 | ); |
53 | let r = analysis.extend_selection(frange); | 54 | let r = analysis.extend_selection(frange); |
54 | assert_eq_dbg("[51; 56)", &r); | 55 | assert_eq!(r, TextRange::from_to(51.into(), 56.into())); |
55 | } | 56 | } |
56 | } | 57 | } |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 332a2fb8d..b1becca03 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use ra_db::{FileId, Cancelable, SyntaxDatabase}; | 1 | use ra_db::{FileId, SyntaxDatabase}; |
2 | use ra_syntax::{ | 2 | use 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}; | |||
9 | pub(crate) fn goto_definition( | 9 | pub(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 | ||
29 | pub(crate) enum ReferenceResult { | 26 | pub(crate) enum ReferenceResult { |
@@ -45,16 +42,16 @@ 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()) |
52 | { | 49 | { |
53 | let scope = function.scopes(db)?; | 50 | let scope = function.scopes(db); |
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,22 +60,21 @@ 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 |
70 | .node_expr(expr) | 67 | .node_expr(expr) |
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 | } |
78 | } | 75 | } |
79 | // Then try module name resolution | 76 | // Then try module name resolution |
80 | if let Some(module) = | 77 | if let Some(module) = hir::source_binder::module_from_child_node(db, file_id, name_ref.syntax()) |
81 | hir::source_binder::module_from_child_node(db, file_id, name_ref.syntax())? | ||
82 | { | 78 | { |
83 | if let Some(path) = name_ref | 79 | if let Some(path) = name_ref |
84 | .syntax() | 80 | .syntax() |
@@ -86,39 +82,39 @@ pub(crate) fn reference_definition( | |||
86 | .find_map(ast::Path::cast) | 82 | .find_map(ast::Path::cast) |
87 | .and_then(hir::Path::from_ast) | 83 | .and_then(hir::Path::from_ast) |
88 | { | 84 | { |
89 | let resolved = module.resolve_path(db, &path)?; | 85 | let resolved = module.resolve_path(db, &path); |
90 | 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()) { |
91 | 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)) { |
92 | return Ok(Exact(target)); | 88 | return Exact(target); |
93 | } | 89 | } |
94 | } | 90 | } |
95 | } | 91 | } |
96 | } | 92 | } |
97 | // If that fails try the index based approach. | 93 | // If that fails try the index based approach. |
98 | let navs = db | 94 | let navs = db |
99 | .index_resolve(name_ref)? | 95 | .index_resolve(name_ref) |
100 | .into_iter() | 96 | .into_iter() |
101 | .map(NavigationTarget::from_symbol) | 97 | .map(NavigationTarget::from_symbol) |
102 | .collect(); | 98 | .collect(); |
103 | Ok(Approximate(navs)) | 99 | Approximate(navs) |
104 | } | 100 | } |
105 | 101 | ||
106 | fn name_definition( | 102 | fn name_definition( |
107 | db: &RootDatabase, | 103 | db: &RootDatabase, |
108 | file_id: FileId, | 104 | file_id: FileId, |
109 | name: &ast::Name, | 105 | name: &ast::Name, |
110 | ) -> Cancelable<Option<Vec<NavigationTarget>>> { | 106 | ) -> Option<Vec<NavigationTarget>> { |
111 | 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) { |
112 | if module.has_semi() { | 108 | if module.has_semi() { |
113 | if let Some(child_module) = | 109 | if let Some(child_module) = |
114 | hir::source_binder::module_from_declaration(db, file_id, module)? | 110 | hir::source_binder::module_from_declaration(db, file_id, module) |
115 | { | 111 | { |
116 | let nav = NavigationTarget::from_module(db, child_module)?; | 112 | let nav = NavigationTarget::from_module(db, child_module); |
117 | return Ok(Some(vec![nav])); | 113 | return Some(vec![nav]); |
118 | } | 114 | } |
119 | } | 115 | } |
120 | } | 116 | } |
121 | Ok(None) | 117 | None |
122 | } | 118 | } |
123 | 119 | ||
124 | #[cfg(test)] | 120 | #[cfg(test)] |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index c445d4fa1..d91151c15 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -1,25 +1,22 @@ | |||
1 | use ra_db::{Cancelable, SyntaxDatabase}; | 1 | use ra_db::{SyntaxDatabase}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | AstNode, SyntaxNode, TreeArc, | 3 | AstNode, SyntaxNode, TreeArc, |
4 | ast::{self, NameOwner}, | 4 | ast::self, |
5 | algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}}, | 5 | algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; | 8 | use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; |
9 | 9 | ||
10 | pub(crate) fn hover( | 10 | pub(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 | ||
60 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option<String>> { | 56 | pub(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, | 69 | let syntax_mapping = function.body_syntax_mapping(db); |
74 | parent_fn | ||
75 | )?); | ||
76 | let infer = function.infer(db)?; | ||
77 | 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`. |
89 | fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Cancelable<Option<String>> { | 81 | fn 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 | ||
100 | impl NavigationTarget { | 90 | impl NavigationTarget { |
@@ -137,48 +127,29 @@ impl NavigationTarget { | |||
137 | fn description(&self, db: &RootDatabase) -> Option<String> { | 127 | fn description(&self, db: &RootDatabase) -> Option<String> { |
138 | // TODO: After type inference is done, add type information to improve the output | 128 | // TODO: After type inference is done, add type information to improve the output |
139 | let node = self.node(db)?; | 129 | let node = self.node(db)?; |
140 | // TODO: Refactor to be have less repetition | 130 | |
131 | fn visit_node<T>(node: &T, label: &str) -> Option<String> | ||
132 | where | ||
133 | T: ast::NameOwner + ast::VisibilityOwner, | ||
134 | { | ||
135 | let mut string = node | ||
136 | .visibility() | ||
137 | .map(|v| format!("{} ", v.syntax().text())) | ||
138 | .unwrap_or_default(); | ||
139 | string.push_str(label); | ||
140 | node.name()?.syntax().text().push_to(&mut string); | ||
141 | Some(string) | ||
142 | } | ||
143 | |||
141 | visitor() | 144 | visitor() |
142 | .visit(|node: &ast::FnDef| { | 145 | .visit(|node: &ast::FnDef| visit_node(node, "fn ")) |
143 | let mut string = "fn ".to_string(); | 146 | .visit(|node: &ast::StructDef| visit_node(node, "struct ")) |
144 | node.name()?.syntax().text().push_to(&mut string); | 147 | .visit(|node: &ast::EnumDef| visit_node(node, "enum ")) |
145 | Some(string) | 148 | .visit(|node: &ast::TraitDef| visit_node(node, "trait ")) |
146 | }) | 149 | .visit(|node: &ast::Module| visit_node(node, "mod ")) |
147 | .visit(|node: &ast::StructDef| { | 150 | .visit(|node: &ast::TypeDef| visit_node(node, "type ")) |
148 | let mut string = "struct ".to_string(); | 151 | .visit(|node: &ast::ConstDef| visit_node(node, "const ")) |
149 | node.name()?.syntax().text().push_to(&mut string); | 152 | .visit(|node: &ast::StaticDef| visit_node(node, "static ")) |
150 | Some(string) | ||
151 | }) | ||
152 | .visit(|node: &ast::EnumDef| { | ||
153 | let mut string = "enum ".to_string(); | ||
154 | node.name()?.syntax().text().push_to(&mut string); | ||
155 | Some(string) | ||
156 | }) | ||
157 | .visit(|node: &ast::TraitDef| { | ||
158 | let mut string = "trait ".to_string(); | ||
159 | node.name()?.syntax().text().push_to(&mut string); | ||
160 | Some(string) | ||
161 | }) | ||
162 | .visit(|node: &ast::Module| { | ||
163 | let mut string = "mod ".to_string(); | ||
164 | node.name()?.syntax().text().push_to(&mut string); | ||
165 | Some(string) | ||
166 | }) | ||
167 | .visit(|node: &ast::TypeDef| { | ||
168 | let mut string = "type ".to_string(); | ||
169 | node.name()?.syntax().text().push_to(&mut string); | ||
170 | Some(string) | ||
171 | }) | ||
172 | .visit(|node: &ast::ConstDef| { | ||
173 | let mut string = "const ".to_string(); | ||
174 | node.name()?.syntax().text().push_to(&mut string); | ||
175 | Some(string) | ||
176 | }) | ||
177 | .visit(|node: &ast::StaticDef| { | ||
178 | let mut string = "static ".to_string(); | ||
179 | node.name()?.syntax().text().push_to(&mut string); | ||
180 | Some(string) | ||
181 | }) | ||
182 | .accept(&node)? | 153 | .accept(&node)? |
183 | } | 154 | } |
184 | } | 155 | } |
@@ -249,20 +220,19 @@ mod tests { | |||
249 | assert_eq!("[unknown]", &type_name); | 220 | assert_eq!("[unknown]", &type_name); |
250 | } | 221 | } |
251 | 222 | ||
252 | // FIXME: improve type_of to make this work | ||
253 | #[test] | 223 | #[test] |
254 | fn test_type_of_for_expr_2() { | 224 | fn test_type_of_for_expr_2() { |
255 | let (analysis, range) = single_file_with_range( | 225 | let (analysis, range) = single_file_with_range( |
256 | " | 226 | " |
257 | fn main() { | 227 | fn main() { |
258 | let foo: usize = 1; | 228 | let foo: usize = 1; |
259 | let bar = <|>1 + foo_test<|>; | 229 | let bar = <|>1 + foo<|>; |
260 | } | 230 | } |
261 | ", | 231 | ", |
262 | ); | 232 | ); |
263 | 233 | ||
264 | let type_name = analysis.type_of(range).unwrap().unwrap(); | 234 | let type_name = analysis.type_of(range).unwrap().unwrap(); |
265 | assert_eq!("[unknown]", &type_name); | 235 | assert_eq!("usize", &type_name); |
266 | } | 236 | } |
267 | 237 | ||
268 | } | 238 | } |
diff --git a/crates/ra_ide_api/src/imp.rs b/crates/ra_ide_api/src/imp.rs index ba4aa0fd5..61771ed40 100644 --- a/crates/ra_ide_api/src/imp.rs +++ b/crates/ra_ide_api/src/imp.rs | |||
@@ -15,7 +15,6 @@ use ra_syntax::{ | |||
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | AnalysisChange, | 17 | AnalysisChange, |
18 | Cancelable, | ||
19 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, | 18 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, |
20 | Query, RootChange, SourceChange, SourceFileEdit, | 19 | Query, RootChange, SourceChange, SourceFileEdit, |
21 | symbol_index::{LibrarySymbolsQuery, FileSymbol}, | 20 | symbol_index::{LibrarySymbolsQuery, FileSymbol}, |
@@ -99,25 +98,22 @@ impl db::RootDatabase { | |||
99 | 98 | ||
100 | impl db::RootDatabase { | 99 | impl db::RootDatabase { |
101 | /// Returns `Vec` for the same reason as `parent_module` | 100 | /// Returns `Vec` for the same reason as `parent_module` |
102 | pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 101 | pub(crate) fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { |
103 | let module = match source_binder::module_from_file_id(self, file_id)? { | 102 | let module = match source_binder::module_from_file_id(self, file_id) { |
104 | Some(it) => it, | 103 | Some(it) => it, |
105 | None => return Ok(Vec::new()), | 104 | None => return Vec::new(), |
106 | }; | 105 | }; |
107 | let krate = match module.krate(self)? { | 106 | let krate = match module.krate(self) { |
108 | Some(it) => it, | 107 | Some(it) => it, |
109 | None => return Ok(Vec::new()), | 108 | None => return Vec::new(), |
110 | }; | 109 | }; |
111 | Ok(vec![krate.crate_id()]) | 110 | vec![krate.crate_id()] |
112 | } | 111 | } |
113 | pub(crate) fn find_all_refs( | 112 | 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); | 113 | let file = self.source_file(position.file_id); |
118 | // Find the binding associated with the offset | 114 | // Find the binding associated with the offset |
119 | let (binding, descr) = match find_binding(self, &file, position)? { | 115 | let (binding, descr) = match find_binding(self, &file, position) { |
120 | None => return Ok(Vec::new()), | 116 | None => return Vec::new(), |
121 | Some(it) => it, | 117 | Some(it) => it, |
122 | }; | 118 | }; |
123 | 119 | ||
@@ -128,46 +124,40 @@ impl db::RootDatabase { | |||
128 | .collect::<Vec<_>>(); | 124 | .collect::<Vec<_>>(); |
129 | ret.extend( | 125 | ret.extend( |
130 | descr | 126 | descr |
131 | .scopes(self)? | 127 | .scopes(self) |
132 | .find_all_refs(binding) | 128 | .find_all_refs(binding) |
133 | .into_iter() | 129 | .into_iter() |
134 | .map(|ref_desc| (position.file_id, ref_desc.range)), | 130 | .map(|ref_desc| (position.file_id, ref_desc.range)), |
135 | ); | 131 | ); |
136 | 132 | ||
137 | return Ok(ret); | 133 | return ret; |
138 | 134 | ||
139 | fn find_binding<'a>( | 135 | fn find_binding<'a>( |
140 | db: &db::RootDatabase, | 136 | db: &db::RootDatabase, |
141 | source_file: &'a SourceFile, | 137 | source_file: &'a SourceFile, |
142 | position: FilePosition, | 138 | position: FilePosition, |
143 | ) -> Cancelable<Option<(&'a ast::BindPat, hir::Function)>> { | 139 | ) -> Option<(&'a ast::BindPat, hir::Function)> { |
144 | let syntax = source_file.syntax(); | 140 | let syntax = source_file.syntax(); |
145 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { | 141 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { |
146 | let descr = ctry!(source_binder::function_from_child_node( | 142 | let descr = source_binder::function_from_child_node( |
147 | db, | 143 | db, |
148 | position.file_id, | 144 | position.file_id, |
149 | binding.syntax(), | 145 | binding.syntax(), |
150 | )?); | 146 | )?; |
151 | return Ok(Some((binding, descr))); | 147 | return Some((binding, descr)); |
152 | }; | 148 | }; |
153 | let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset)); | 149 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; |
154 | let descr = ctry!(source_binder::function_from_child_node( | 150 | let descr = |
155 | db, | 151 | source_binder::function_from_child_node(db, position.file_id, name_ref.syntax())?; |
156 | position.file_id, | 152 | let scope = descr.scopes(db); |
157 | name_ref.syntax(), | 153 | let resolved = scope.resolve_local_name(name_ref)?; |
158 | )?); | ||
159 | let scope = descr.scopes(db)?; | ||
160 | let resolved = ctry!(scope.resolve_local_name(name_ref)); | ||
161 | let resolved = resolved.ptr().resolve(source_file); | 154 | let resolved = resolved.ptr().resolve(source_file); |
162 | let binding = ctry!(find_node_at_offset::<ast::BindPat>( | 155 | let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?; |
163 | syntax, | 156 | Some((binding, descr)) |
164 | resolved.range().end() | ||
165 | )); | ||
166 | Ok(Some((binding, descr))) | ||
167 | } | 157 | } |
168 | } | 158 | } |
169 | 159 | ||
170 | pub(crate) fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 160 | pub(crate) fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { |
171 | let syntax = self.source_file(file_id); | 161 | let syntax = self.source_file(file_id); |
172 | 162 | ||
173 | let mut res = ra_ide_api_light::diagnostics(&syntax) | 163 | let mut res = ra_ide_api_light::diagnostics(&syntax) |
@@ -179,8 +169,8 @@ impl db::RootDatabase { | |||
179 | fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)), | 169 | fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)), |
180 | }) | 170 | }) |
181 | .collect::<Vec<_>>(); | 171 | .collect::<Vec<_>>(); |
182 | if let Some(m) = source_binder::module_from_file_id(self, file_id)? { | 172 | if let Some(m) = source_binder::module_from_file_id(self, file_id) { |
183 | for (name_node, problem) in m.problems(self)? { | 173 | for (name_node, problem) in m.problems(self) { |
184 | let source_root = self.file_source_root(file_id); | 174 | let source_root = self.file_source_root(file_id); |
185 | let diag = match problem { | 175 | let diag = match problem { |
186 | Problem::UnresolvedModule { candidate } => { | 176 | Problem::UnresolvedModule { candidate } => { |
@@ -228,7 +218,7 @@ impl db::RootDatabase { | |||
228 | res.push(diag) | 218 | res.push(diag) |
229 | } | 219 | } |
230 | }; | 220 | }; |
231 | Ok(res) | 221 | res |
232 | } | 222 | } |
233 | 223 | ||
234 | pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> { | 224 | pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> { |
@@ -239,13 +229,8 @@ impl db::RootDatabase { | |||
239 | .collect() | 229 | .collect() |
240 | } | 230 | } |
241 | 231 | ||
242 | pub(crate) fn rename( | 232 | pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> { |
243 | &self, | 233 | 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() | 234 | .iter() |
250 | .map(|(file_id, text_range)| SourceFileEdit { | 235 | .map(|(file_id, text_range)| SourceFileEdit { |
251 | file_id: *file_id, | 236 | file_id: *file_id, |
@@ -255,10 +240,9 @@ impl db::RootDatabase { | |||
255 | builder.finish() | 240 | builder.finish() |
256 | }, | 241 | }, |
257 | }) | 242 | }) |
258 | .collect::<Vec<_>>(); | 243 | .collect::<Vec<_>>() |
259 | Ok(res) | ||
260 | } | 244 | } |
261 | pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Cancelable<Vec<FileSymbol>> { | 245 | pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> { |
262 | let name = name_ref.text(); | 246 | let name = name_ref.text(); |
263 | let mut query = Query::new(name.to_string()); | 247 | let mut query = Query::new(name.to_string()); |
264 | query.exact(); | 248 | query.exact(); |
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index abb50ff95..3a0d2dbbe 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. |
12 | macro_rules! ctry { | ||
13 | ($expr:expr) => { | ||
14 | match $expr { | ||
15 | None => return Ok(None), | ||
16 | Some(it) => it, | ||
17 | } | ||
18 | }; | ||
19 | } | ||
20 | |||
21 | mod db; | 12 | mod db; |
22 | mod imp; | 13 | mod imp; |
23 | pub mod mock_analysis; | 14 | pub 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 | }; |
60 | pub use ra_db::{ | 51 | pub use ra_db::{ |
61 | Cancelable, Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId | 52 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId |
62 | }; | 53 | }; |
63 | 54 | ||
55 | pub type Cancelable<T> = Result<T, Canceled>; | ||
56 | |||
64 | #[derive(Default)] | 57 | #[derive(Default)] |
65 | pub struct AnalysisChange { | 58 | pub struct AnalysisChange { |
66 | new_roots: Vec<(SourceRootId, bool)>, | 59 | new_roots: Vec<(SourceRootId, bool)>, |
@@ -381,12 +374,11 @@ impl Analysis { | |||
381 | /// Fuzzy searches for a symbol. | 374 | /// Fuzzy searches for a symbol. |
382 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { | 375 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { |
383 | self.with_db(|db| { | 376 | self.with_db(|db| { |
384 | let res = symbol_index::world_symbols(db, query)? | 377 | symbol_index::world_symbols(db, query) |
385 | .into_iter() | 378 | .into_iter() |
386 | .map(NavigationTarget::from_symbol) | 379 | .map(NavigationTarget::from_symbol) |
387 | .collect::<Vec<_>>(); | 380 | .collect::<Vec<_>>() |
388 | Ok(res) | 381 | }) |
389 | })? | ||
390 | } | 382 | } |
391 | 383 | ||
392 | pub fn goto_definition( | 384 | pub fn goto_definition( |
@@ -394,33 +386,33 @@ impl Analysis { | |||
394 | position: FilePosition, | 386 | position: FilePosition, |
395 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { | 387 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { |
396 | self.db | 388 | self.db |
397 | .catch_canceled(|db| goto_definition::goto_definition(db, position))? | 389 | .catch_canceled(|db| goto_definition::goto_definition(db, position)) |
398 | } | 390 | } |
399 | 391 | ||
400 | /// Finds all usages of the reference at point. | 392 | /// Finds all usages of the reference at point. |
401 | 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)>> { |
402 | self.with_db(|db| db.find_all_refs(position))? | 394 | self.with_db(|db| db.find_all_refs(position)) |
403 | } | 395 | } |
404 | 396 | ||
405 | /// Returns a short text descrbing element at position. | 397 | /// Returns a short text descrbing element at position. |
406 | pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { | 398 | pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { |
407 | self.with_db(|db| hover::hover(db, position))? | 399 | self.with_db(|db| hover::hover(db, position)) |
408 | } | 400 | } |
409 | 401 | ||
410 | /// Computes parameter information for the given call expression. | 402 | /// Computes parameter information for the given call expression. |
411 | pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { | 403 | pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { |
412 | self.db | 404 | self.db |
413 | .catch_canceled(|db| call_info::call_info(db, position))? | 405 | .catch_canceled(|db| call_info::call_info(db, position)) |
414 | } | 406 | } |
415 | 407 | ||
416 | /// Returns a `mod name;` declaration which created the current module. | 408 | /// Returns a `mod name;` declaration which created the current module. |
417 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { | 409 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { |
418 | self.with_db(|db| parent_module::parent_module(db, position))? | 410 | self.with_db(|db| parent_module::parent_module(db, position)) |
419 | } | 411 | } |
420 | 412 | ||
421 | /// Returns crates this file belongs too. | 413 | /// Returns crates this file belongs too. |
422 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 414 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
423 | self.with_db(|db| db.crate_for(file_id))? | 415 | self.with_db(|db| db.crate_for(file_id)) |
424 | } | 416 | } |
425 | 417 | ||
426 | /// Returns the root file of the given crate. | 418 | /// Returns the root file of the given crate. |
@@ -431,20 +423,20 @@ impl Analysis { | |||
431 | /// 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. |
432 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { | 424 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { |
433 | self.db | 425 | self.db |
434 | .catch_canceled(|db| runnables::runnables(db, file_id))? | 426 | .catch_canceled(|db| runnables::runnables(db, file_id)) |
435 | } | 427 | } |
436 | 428 | ||
437 | /// Computes syntax highlighting for the given file. | 429 | /// Computes syntax highlighting for the given file. |
438 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 430 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { |
439 | self.db | 431 | self.db |
440 | .catch_canceled(|db| syntax_highlighting::highlight(db, file_id))? | 432 | .catch_canceled(|db| syntax_highlighting::highlight(db, file_id)) |
441 | } | 433 | } |
442 | 434 | ||
443 | /// Computes completions at the given position. | 435 | /// Computes completions at the given position. |
444 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 436 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { |
445 | let completions = self | 437 | let completions = self |
446 | .db | 438 | .db |
447 | .catch_canceled(|db| completion::completions(db, position))??; | 439 | .catch_canceled(|db| completion::completions(db, position))?; |
448 | Ok(completions.map(|it| it.into())) | 440 | Ok(completions.map(|it| it.into())) |
449 | } | 441 | } |
450 | 442 | ||
@@ -456,12 +448,12 @@ impl Analysis { | |||
456 | 448 | ||
457 | /// Computes the set of diagnostics for the given file. | 449 | /// Computes the set of diagnostics for the given file. |
458 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 450 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
459 | self.with_db(|db| db.diagnostics(file_id))? | 451 | self.with_db(|db| db.diagnostics(file_id)) |
460 | } | 452 | } |
461 | 453 | ||
462 | /// Computes the type of the expression at the given position. | 454 | /// Computes the type of the expression at the given position. |
463 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { | 455 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { |
464 | self.with_db(|db| hover::type_of(db, frange))? | 456 | self.with_db(|db| hover::type_of(db, frange)) |
465 | } | 457 | } |
466 | 458 | ||
467 | /// 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 |
@@ -471,7 +463,7 @@ impl Analysis { | |||
471 | position: FilePosition, | 463 | position: FilePosition, |
472 | new_name: &str, | 464 | new_name: &str, |
473 | ) -> Cancelable<Vec<SourceFileEdit>> { | 465 | ) -> Cancelable<Vec<SourceFileEdit>> { |
474 | self.with_db(|db| db.rename(position, new_name))? | 466 | self.with_db(|db| db.rename(position, new_name)) |
475 | } | 467 | } |
476 | 468 | ||
477 | 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/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index 230d0f67a..21c15c0c0 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use ra_db::{FileId, Cancelable}; | 1 | use ra_db::FileId; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | SyntaxNode, AstNode, SmolStr, TextRange, ast, | 3 | SyntaxNode, AstNode, SmolStr, TextRange, ast, |
4 | SyntaxKind::{self, NAME}, | 4 | SyntaxKind::{self, NAME}, |
@@ -69,84 +69,72 @@ impl NavigationTarget { | |||
69 | } | 69 | } |
70 | } | 70 | } |
71 | 71 | ||
72 | pub(crate) fn from_module( | 72 | pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
73 | db: &RootDatabase, | 73 | let (file_id, source) = module.definition_source(db); |
74 | module: hir::Module, | ||
75 | ) -> Cancelable<NavigationTarget> { | ||
76 | let (file_id, source) = module.definition_source(db)?; | ||
77 | let name = module | 74 | let name = module |
78 | .name(db)? | 75 | .name(db) |
79 | .map(|it| it.to_string().into()) | 76 | .map(|it| it.to_string().into()) |
80 | .unwrap_or_default(); | 77 | .unwrap_or_default(); |
81 | let res = match source { | 78 | match source { |
82 | ModuleSource::SourceFile(node) => { | 79 | ModuleSource::SourceFile(node) => { |
83 | NavigationTarget::from_syntax(file_id, name, None, node.syntax()) | 80 | NavigationTarget::from_syntax(file_id, name, None, node.syntax()) |
84 | } | 81 | } |
85 | ModuleSource::Module(node) => { | 82 | ModuleSource::Module(node) => { |
86 | NavigationTarget::from_syntax(file_id, name, None, node.syntax()) | 83 | NavigationTarget::from_syntax(file_id, name, None, node.syntax()) |
87 | } | 84 | } |
88 | }; | 85 | } |
89 | Ok(res) | ||
90 | } | 86 | } |
91 | 87 | ||
92 | pub(crate) fn from_module_to_decl( | 88 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
93 | db: &RootDatabase, | ||
94 | module: hir::Module, | ||
95 | ) -> Cancelable<NavigationTarget> { | ||
96 | let name = module | 89 | let name = module |
97 | .name(db)? | 90 | .name(db) |
98 | .map(|it| it.to_string().into()) | 91 | .map(|it| it.to_string().into()) |
99 | .unwrap_or_default(); | 92 | .unwrap_or_default(); |
100 | if let Some((file_id, source)) = module.declaration_source(db)? { | 93 | if let Some((file_id, source)) = module.declaration_source(db) { |
101 | return Ok(NavigationTarget::from_syntax( | 94 | return NavigationTarget::from_syntax(file_id, name, None, source.syntax()); |
102 | file_id, | ||
103 | name, | ||
104 | None, | ||
105 | source.syntax(), | ||
106 | )); | ||
107 | } | 95 | } |
108 | NavigationTarget::from_module(db, module) | 96 | NavigationTarget::from_module(db, module) |
109 | } | 97 | } |
110 | 98 | ||
111 | // TODO once Def::Item is gone, this should be able to always return a NavigationTarget | 99 | // TODO once Def::Item is gone, this should be able to always return a NavigationTarget |
112 | pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> { | 100 | pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Option<NavigationTarget> { |
113 | let res = match def { | 101 | let res = match def { |
114 | Def::Struct(s) => { | 102 | Def::Struct(s) => { |
115 | let (file_id, node) = s.source(db)?; | 103 | let (file_id, node) = s.source(db); |
116 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 104 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
117 | } | 105 | } |
118 | Def::Enum(e) => { | 106 | Def::Enum(e) => { |
119 | let (file_id, node) = e.source(db)?; | 107 | let (file_id, node) = e.source(db); |
120 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 108 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
121 | } | 109 | } |
122 | Def::EnumVariant(ev) => { | 110 | Def::EnumVariant(ev) => { |
123 | let (file_id, node) = ev.source(db)?; | 111 | let (file_id, node) = ev.source(db); |
124 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 112 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
125 | } | 113 | } |
126 | Def::Function(f) => { | 114 | Def::Function(f) => { |
127 | let (file_id, node) = f.source(db)?; | 115 | let (file_id, node) = f.source(db); |
128 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 116 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
129 | } | 117 | } |
130 | Def::Trait(f) => { | 118 | Def::Trait(f) => { |
131 | let (file_id, node) = f.source(db)?; | 119 | let (file_id, node) = f.source(db); |
132 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 120 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
133 | } | 121 | } |
134 | Def::Type(f) => { | 122 | Def::Type(f) => { |
135 | let (file_id, node) = f.source(db)?; | 123 | let (file_id, node) = f.source(db); |
136 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 124 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
137 | } | 125 | } |
138 | Def::Static(f) => { | 126 | Def::Static(f) => { |
139 | let (file_id, node) = f.source(db)?; | 127 | let (file_id, node) = f.source(db); |
140 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 128 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
141 | } | 129 | } |
142 | Def::Const(f) => { | 130 | Def::Const(f) => { |
143 | let (file_id, node) = f.source(db)?; | 131 | let (file_id, node) = f.source(db); |
144 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 132 | NavigationTarget::from_named(file_id.original_file(db), &*node) |
145 | } | 133 | } |
146 | Def::Module(m) => NavigationTarget::from_module(db, m)?, | 134 | Def::Module(m) => NavigationTarget::from_module(db, m), |
147 | Def::Item => return Ok(None), | 135 | Def::Item => return None, |
148 | }; | 136 | }; |
149 | Ok(Some(res)) | 137 | Some(res) |
150 | } | 138 | } |
151 | 139 | ||
152 | #[cfg(test)] | 140 | #[cfg(test)] |
diff --git a/crates/ra_ide_api/src/parent_module.rs b/crates/ra_ide_api/src/parent_module.rs index 675042a6c..e94297fe3 100644 --- a/crates/ra_ide_api/src/parent_module.rs +++ b/crates/ra_ide_api/src/parent_module.rs | |||
@@ -1,19 +1,16 @@ | |||
1 | use ra_db::{Cancelable, FilePosition}; | 1 | use ra_db::FilePosition; |
2 | 2 | ||
3 | use crate::{NavigationTarget, db::RootDatabase}; | 3 | use 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. |
7 | pub(crate) fn parent_module( | 7 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { |
8 | db: &RootDatabase, | 8 | let module = match hir::source_binder::module_from_position(db, position) { |
9 | position: FilePosition, | 9 | None => return Vec::new(), |
10 | ) -> Cancelable<Vec<NavigationTarget>> { | ||
11 | let module = match hir::source_binder::module_from_position(db, position)? { | ||
12 | None => return Ok(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 53e49da5b..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 | }; |
6 | use ra_db::{Cancelable, SyntaxDatabase}; | 6 | use ra_db::SyntaxDatabase; |
7 | 7 | ||
8 | use crate::{db::RootDatabase, FileId}; | 8 | use crate::{db::RootDatabase, FileId}; |
9 | 9 | ||
@@ -21,14 +21,13 @@ pub enum RunnableKind { | |||
21 | Bin, | 21 | Bin, |
22 | } | 22 | } |
23 | 23 | ||
24 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Runnable>> { | 24 | pub(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 | ||
34 | fn runnable(db: &RootDatabase, file_id: FileId, item: &SyntaxNode) -> Option<Runnable> { | 33 | fn runnable(db: &RootDatabase, file_id: FileId, item: &SyntaxNode) -> Option<Runnable> { |
@@ -75,20 +74,114 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: &ast::Module) -> Opt | |||
75 | return None; | 74 | return None; |
76 | } | 75 | } |
77 | let range = module.syntax().range(); | 76 | let range = module.syntax().range(); |
78 | let module = | 77 | let module = hir::source_binder::module_from_child_node(db, file_id, module.syntax())?; |
79 | hir::source_binder::module_from_child_node(db, file_id, module.syntax()).ok()??; | ||
80 | 78 | ||
81 | // FIXME: thread cancellation instead of `.ok`ing | 79 | // FIXME: thread cancellation instead of `.ok`ing |
82 | let path = module | 80 | let path = module |
83 | .path_to_root(db) | 81 | .path_to_root(db) |
84 | .ok()? | ||
85 | .into_iter() | 82 | .into_iter() |
86 | .rev() | 83 | .rev() |
87 | .filter_map(|it| it.name(db).ok()) | 84 | .filter_map(|it| it.name(db)) |
88 | .filter_map(|it| it) | ||
89 | .join("::"); | 85 | .join("::"); |
90 | Some(Runnable { | 86 | Some(Runnable { |
91 | range, | 87 | range, |
92 | kind: RunnableKind::TestMod { path }, | 88 | kind: RunnableKind::TestMod { path }, |
93 | }) | 89 | }) |
94 | } | 90 | } |
91 | |||
92 | #[cfg(test)] | ||
93 | mod tests { | ||
94 | use insta::assert_debug_snapshot_matches; | ||
95 | |||
96 | use crate::mock_analysis::analysis_and_position; | ||
97 | |||
98 | #[test] | ||
99 | fn test_runnables() { | ||
100 | let (analysis, pos) = analysis_and_position( | ||
101 | r#" | ||
102 | //- /lib.rs | ||
103 | <|> //empty | ||
104 | fn main() {} | ||
105 | |||
106 | #[test] | ||
107 | fn test_foo() {} | ||
108 | |||
109 | #[test] | ||
110 | #[ignore] | ||
111 | fn test_foo() {} | ||
112 | "#, | ||
113 | ); | ||
114 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
115 | assert_debug_snapshot_matches!("runnables", &runnables) | ||
116 | } | ||
117 | |||
118 | #[test] | ||
119 | fn test_runnables_module() { | ||
120 | let (analysis, pos) = analysis_and_position( | ||
121 | r#" | ||
122 | //- /lib.rs | ||
123 | <|> //empty | ||
124 | mod test_mod { | ||
125 | #[test] | ||
126 | fn test_foo1() {} | ||
127 | } | ||
128 | "#, | ||
129 | ); | ||
130 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
131 | assert_debug_snapshot_matches!("runnables_module", &runnables) | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn test_runnables_one_depth_layer_module() { | ||
136 | let (analysis, pos) = analysis_and_position( | ||
137 | r#" | ||
138 | //- /lib.rs | ||
139 | <|> //empty | ||
140 | mod foo { | ||
141 | mod test_mod { | ||
142 | #[test] | ||
143 | fn test_foo1() {} | ||
144 | } | ||
145 | } | ||
146 | "#, | ||
147 | ); | ||
148 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
149 | assert_debug_snapshot_matches!("runnables_one_depth_layer_module", &runnables) | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn test_runnables_multiple_depth_module() { | ||
154 | let (analysis, pos) = analysis_and_position( | ||
155 | r#" | ||
156 | //- /lib.rs | ||
157 | <|> //empty | ||
158 | mod foo { | ||
159 | mod bar { | ||
160 | mod test_mod { | ||
161 | #[test] | ||
162 | fn test_foo1() {} | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | "#, | ||
167 | ); | ||
168 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
169 | assert_debug_snapshot_matches!("runnables_multiple_depth_module", &runnables) | ||
170 | } | ||
171 | |||
172 | #[test] | ||
173 | fn test_runnables_no_test_function_in_module() { | ||
174 | let (analysis, pos) = analysis_and_position( | ||
175 | r#" | ||
176 | //- /lib.rs | ||
177 | <|> //empty | ||
178 | mod test_mod { | ||
179 | fn foo1() {} | ||
180 | } | ||
181 | "#, | ||
182 | ); | ||
183 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
184 | assert!(runnables.is_empty()) | ||
185 | } | ||
186 | |||
187 | } | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__highlight_query_group_macro.snap b/crates/ra_ide_api/src/snapshots/tests__highlight_query_group_macro.snap new file mode 100644 index 000000000..b84aa9c78 --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__highlight_query_group_macro.snap | |||
@@ -0,0 +1,26 @@ | |||
1 | Created: 2019-01-15T11:15:20.732493641+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/src/syntax_highlighting.rs | ||
4 | |||
5 | [ | ||
6 | HighlightedRange { | ||
7 | range: [20; 32), | ||
8 | tag: "macro" | ||
9 | }, | ||
10 | HighlightedRange { | ||
11 | range: [13; 18), | ||
12 | tag: "text" | ||
13 | }, | ||
14 | HighlightedRange { | ||
15 | range: [51; 54), | ||
16 | tag: "keyword" | ||
17 | }, | ||
18 | HighlightedRange { | ||
19 | range: [55; 60), | ||
20 | tag: "keyword" | ||
21 | }, | ||
22 | HighlightedRange { | ||
23 | range: [61; 72), | ||
24 | tag: "function" | ||
25 | } | ||
26 | ] | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__highlights_code_inside_macros.snap b/crates/ra_ide_api/src/snapshots/tests__highlights_code_inside_macros.snap new file mode 100644 index 000000000..14c6e5a4e --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__highlights_code_inside_macros.snap | |||
@@ -0,0 +1,70 @@ | |||
1 | Created: 2019-01-15T11:15:20.732523231+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/src/syntax_highlighting.rs | ||
4 | |||
5 | [ | ||
6 | HighlightedRange { | ||
7 | range: [13; 15), | ||
8 | tag: "keyword" | ||
9 | }, | ||
10 | HighlightedRange { | ||
11 | range: [16; 20), | ||
12 | tag: "function" | ||
13 | }, | ||
14 | HighlightedRange { | ||
15 | range: [41; 46), | ||
16 | tag: "macro" | ||
17 | }, | ||
18 | HighlightedRange { | ||
19 | range: [49; 52), | ||
20 | tag: "keyword" | ||
21 | }, | ||
22 | HighlightedRange { | ||
23 | range: [57; 59), | ||
24 | tag: "literal" | ||
25 | }, | ||
26 | HighlightedRange { | ||
27 | range: [82; 86), | ||
28 | tag: "macro" | ||
29 | }, | ||
30 | HighlightedRange { | ||
31 | range: [89; 92), | ||
32 | tag: "keyword" | ||
33 | }, | ||
34 | HighlightedRange { | ||
35 | range: [97; 99), | ||
36 | tag: "literal" | ||
37 | }, | ||
38 | HighlightedRange { | ||
39 | range: [49; 52), | ||
40 | tag: "keyword" | ||
41 | }, | ||
42 | HighlightedRange { | ||
43 | range: [53; 54), | ||
44 | tag: "function" | ||
45 | }, | ||
46 | HighlightedRange { | ||
47 | range: [57; 59), | ||
48 | tag: "literal" | ||
49 | }, | ||
50 | HighlightedRange { | ||
51 | range: [61; 62), | ||
52 | tag: "text" | ||
53 | }, | ||
54 | HighlightedRange { | ||
55 | range: [89; 92), | ||
56 | tag: "keyword" | ||
57 | }, | ||
58 | HighlightedRange { | ||
59 | range: [93; 94), | ||
60 | tag: "function" | ||
61 | }, | ||
62 | HighlightedRange { | ||
63 | range: [97; 99), | ||
64 | tag: "literal" | ||
65 | }, | ||
66 | HighlightedRange { | ||
67 | range: [101; 102), | ||
68 | tag: "text" | ||
69 | } | ||
70 | ] | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__runnables.snap b/crates/ra_ide_api/src/snapshots/tests__runnables.snap new file mode 100644 index 000000000..ba6cba0ab --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__runnables.snap | |||
@@ -0,0 +1,22 @@ | |||
1 | Created: 2019-01-15T11:15:20.732460119+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/src/runnables.rs | ||
4 | |||
5 | [ | ||
6 | Runnable { | ||
7 | range: [1; 21), | ||
8 | kind: Bin | ||
9 | }, | ||
10 | Runnable { | ||
11 | range: [22; 46), | ||
12 | kind: Test { | ||
13 | name: "test_foo" | ||
14 | } | ||
15 | }, | ||
16 | Runnable { | ||
17 | range: [47; 81), | ||
18 | kind: Test { | ||
19 | name: "test_foo" | ||
20 | } | ||
21 | } | ||
22 | ] | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__runnables_module.snap b/crates/ra_ide_api/src/snapshots/tests__runnables_module.snap new file mode 100644 index 000000000..b3f2d4d6e --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__runnables_module.snap | |||
@@ -0,0 +1,18 @@ | |||
1 | Created: 2019-01-15T11:15:20.732460109+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/src/runnables.rs | ||
4 | |||
5 | [ | ||
6 | Runnable { | ||
7 | range: [1; 59), | ||
8 | kind: TestMod { | ||
9 | path: "test_mod" | ||
10 | } | ||
11 | }, | ||
12 | Runnable { | ||
13 | range: [28; 57), | ||
14 | kind: Test { | ||
15 | name: "test_foo1" | ||
16 | } | ||
17 | } | ||
18 | ] | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__runnables_multiple_depth_module.snap b/crates/ra_ide_api/src/snapshots/tests__runnables_multiple_depth_module.snap new file mode 100644 index 000000000..6eba482e7 --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__runnables_multiple_depth_module.snap | |||
@@ -0,0 +1,18 @@ | |||
1 | Created: 2019-01-15T11:15:20.732522773+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/src/runnables.rs | ||
4 | |||
5 | [ | ||
6 | Runnable { | ||
7 | range: [41; 115), | ||
8 | kind: TestMod { | ||
9 | path: "foo::bar::test_mod" | ||
10 | } | ||
11 | }, | ||
12 | Runnable { | ||
13 | range: [68; 105), | ||
14 | kind: Test { | ||
15 | name: "test_foo1" | ||
16 | } | ||
17 | } | ||
18 | ] | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__runnables_one_depth_layer_module.snap b/crates/ra_ide_api/src/snapshots/tests__runnables_one_depth_layer_module.snap new file mode 100644 index 000000000..f40c762f3 --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__runnables_one_depth_layer_module.snap | |||
@@ -0,0 +1,18 @@ | |||
1 | Created: 2019-01-15T11:15:20.732480089+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/src/runnables.rs | ||
4 | |||
5 | [ | ||
6 | Runnable { | ||
7 | range: [23; 85), | ||
8 | kind: TestMod { | ||
9 | path: "foo::test_mod" | ||
10 | } | ||
11 | }, | ||
12 | Runnable { | ||
13 | range: [46; 79), | ||
14 | kind: Test { | ||
15 | name: "test_foo1" | ||
16 | } | ||
17 | } | ||
18 | ] | ||
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs index fdda57022..74165d68f 100644 --- a/crates/ra_ide_api/src/symbol_index.rs +++ b/crates/ra_ide_api/src/symbol_index.rs | |||
@@ -37,13 +37,13 @@ use salsa::ParallelDatabase; | |||
37 | use rayon::prelude::*; | 37 | use rayon::prelude::*; |
38 | 38 | ||
39 | use crate::{ | 39 | use crate::{ |
40 | Cancelable, FileId, Query, | 40 | FileId, Query, |
41 | db::RootDatabase, | 41 | db::RootDatabase, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | salsa::query_group! { | 44 | salsa::query_group! { |
45 | pub(crate) trait SymbolsDatabase: hir::db::HirDatabase { | 45 | pub(crate) trait SymbolsDatabase: hir::db::HirDatabase { |
46 | fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | 46 | fn file_symbols(file_id: FileId) -> Arc<SymbolIndex> { |
47 | type FileSymbolsQuery; | 47 | type FileSymbolsQuery; |
48 | } | 48 | } |
49 | fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> { | 49 | fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> { |
@@ -53,8 +53,8 @@ salsa::query_group! { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | 56 | fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { |
57 | db.check_canceled()?; | 57 | db.check_canceled(); |
58 | let source_file = db.source_file(file_id); | 58 | let source_file = db.source_file(file_id); |
59 | let mut symbols = source_file | 59 | let mut symbols = source_file |
60 | .syntax() | 60 | .syntax() |
@@ -63,16 +63,16 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Cancelable<Arc<Sy | |||
63 | .map(move |(name, ptr)| FileSymbol { name, ptr, file_id }) | 63 | .map(move |(name, ptr)| FileSymbol { name, ptr, file_id }) |
64 | .collect::<Vec<_>>(); | 64 | .collect::<Vec<_>>(); |
65 | 65 | ||
66 | for (name, text_range) in hir::source_binder::macro_symbols(db, file_id)? { | 66 | for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) { |
67 | let node = find_covering_node(source_file.syntax(), text_range); | 67 | let node = find_covering_node(source_file.syntax(), text_range); |
68 | let ptr = LocalSyntaxPtr::new(node); | 68 | let ptr = LocalSyntaxPtr::new(node); |
69 | symbols.push(FileSymbol { file_id, name, ptr }) | 69 | symbols.push(FileSymbol { file_id, name, ptr }) |
70 | } | 70 | } |
71 | 71 | ||
72 | Ok(Arc::new(SymbolIndex::new(symbols))) | 72 | Arc::new(SymbolIndex::new(symbols)) |
73 | } | 73 | } |
74 | 74 | ||
75 | pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Cancelable<Vec<FileSymbol>> { | 75 | pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { |
76 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | 76 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` |
77 | struct Snap(salsa::Snapshot<RootDatabase>); | 77 | struct Snap(salsa::Snapshot<RootDatabase>); |
78 | impl Clone for Snap { | 78 | impl Clone for Snap { |
@@ -98,10 +98,9 @@ pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Cancelable<Vec<F | |||
98 | files | 98 | files |
99 | .par_iter() | 99 | .par_iter() |
100 | .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) | 100 | .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) |
101 | .filter_map(|it| it.ok()) | ||
102 | .collect() | 101 | .collect() |
103 | }; | 102 | }; |
104 | Ok(query.search(&buf)) | 103 | query.search(&buf) |
105 | } | 104 | } |
106 | 105 | ||
107 | #[derive(Default, Debug)] | 106 | #[derive(Default, Debug)] |
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index cb19e9515..a4d3ad005 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs | |||
@@ -2,11 +2,11 @@ use ra_syntax::{ast, AstNode,}; | |||
2 | use ra_db::SyntaxDatabase; | 2 | use ra_db::SyntaxDatabase; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | FileId, Cancelable, HighlightedRange, | 5 | FileId, HighlightedRange, |
6 | db::RootDatabase, | 6 | db::RootDatabase, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 9 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { |
10 | let source_file = db.source_file(file_id); | 10 | let source_file = db.source_file(file_id); |
11 | let mut res = ra_ide_api_light::highlight(source_file.syntax()); | 11 | let mut res = ra_ide_api_light::highlight(source_file.syntax()); |
12 | for macro_call in source_file | 12 | for macro_call in source_file |
@@ -28,13 +28,14 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Hi | |||
28 | res.extend(mapped_ranges); | 28 | res.extend(mapped_ranges); |
29 | } | 29 | } |
30 | } | 30 | } |
31 | Ok(res) | 31 | res |
32 | } | 32 | } |
33 | 33 | ||
34 | #[cfg(test)] | 34 | #[cfg(test)] |
35 | mod tests { | 35 | mod tests { |
36 | use crate::mock_analysis::single_file; | 36 | use crate::mock_analysis::single_file; |
37 | use test_utils::assert_eq_dbg; | 37 | |
38 | use insta::assert_debug_snapshot_matches; | ||
38 | 39 | ||
39 | #[test] | 40 | #[test] |
40 | fn highlights_code_inside_macros() { | 41 | fn highlights_code_inside_macros() { |
@@ -47,25 +48,7 @@ mod tests { | |||
47 | ", | 48 | ", |
48 | ); | 49 | ); |
49 | let highlights = analysis.highlight(file_id).unwrap(); | 50 | let highlights = analysis.highlight(file_id).unwrap(); |
50 | assert_eq_dbg( | 51 | assert_debug_snapshot_matches!("highlights_code_inside_macros", &highlights); |
51 | r#"[HighlightedRange { range: [13; 15), tag: "keyword" }, | ||
52 | HighlightedRange { range: [16; 20), tag: "function" }, | ||
53 | HighlightedRange { range: [41; 46), tag: "macro" }, | ||
54 | HighlightedRange { range: [49; 52), tag: "keyword" }, | ||
55 | HighlightedRange { range: [57; 59), tag: "literal" }, | ||
56 | HighlightedRange { range: [82; 86), tag: "macro" }, | ||
57 | HighlightedRange { range: [89; 92), tag: "keyword" }, | ||
58 | HighlightedRange { range: [97; 99), tag: "literal" }, | ||
59 | HighlightedRange { range: [49; 52), tag: "keyword" }, | ||
60 | HighlightedRange { range: [53; 54), tag: "function" }, | ||
61 | HighlightedRange { range: [57; 59), tag: "literal" }, | ||
62 | HighlightedRange { range: [61; 62), tag: "text" }, | ||
63 | HighlightedRange { range: [89; 92), tag: "keyword" }, | ||
64 | HighlightedRange { range: [93; 94), tag: "function" }, | ||
65 | HighlightedRange { range: [97; 99), tag: "literal" }, | ||
66 | HighlightedRange { range: [101; 102), tag: "text" }]"#, | ||
67 | &highlights, | ||
68 | ) | ||
69 | } | 52 | } |
70 | 53 | ||
71 | // FIXME: this test is not really necessary: artifact of the inital hacky | 54 | // FIXME: this test is not really necessary: artifact of the inital hacky |
@@ -80,13 +63,6 @@ mod tests { | |||
80 | ", | 63 | ", |
81 | ); | 64 | ); |
82 | let highlights = analysis.highlight(file_id).unwrap(); | 65 | let highlights = analysis.highlight(file_id).unwrap(); |
83 | assert_eq_dbg( | 66 | assert_debug_snapshot_matches!("highlight_query_group_macro", &highlights); |
84 | r#"[HighlightedRange { range: [20; 32), tag: "macro" }, | ||
85 | HighlightedRange { range: [13; 18), tag: "text" }, | ||
86 | HighlightedRange { range: [51; 54), tag: "keyword" }, | ||
87 | HighlightedRange { range: [55; 60), tag: "keyword" }, | ||
88 | HighlightedRange { range: [61; 72), tag: "function" }]"#, | ||
89 | &highlights, | ||
90 | ) | ||
91 | } | 67 | } |
92 | } | 68 | } |
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs index 7dc1dba73..2b863aedf 100644 --- a/crates/ra_ide_api/tests/test/main.rs +++ b/crates/ra_ide_api/tests/test/main.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | mod runnables; | ||
2 | |||
3 | use ra_syntax::TextRange; | 1 | use ra_syntax::TextRange; |
4 | use test_utils::{assert_eq_dbg, assert_eq_text}; | 2 | use test_utils::assert_eq_text; |
3 | use insta::assert_debug_snapshot_matches; | ||
5 | 4 | ||
6 | use ra_ide_api::{ | 5 | use ra_ide_api::{ |
7 | mock_analysis::{single_file, single_file_with_position, MockAnalysis}, | 6 | mock_analysis::{single_file, single_file_with_position, MockAnalysis}, |
@@ -12,18 +11,7 @@ use ra_ide_api::{ | |||
12 | fn test_unresolved_module_diagnostic() { | 11 | fn test_unresolved_module_diagnostic() { |
13 | let (analysis, file_id) = single_file("mod foo;"); | 12 | let (analysis, file_id) = single_file("mod foo;"); |
14 | let diagnostics = analysis.diagnostics(file_id).unwrap(); | 13 | let diagnostics = analysis.diagnostics(file_id).unwrap(); |
15 | assert_eq_dbg( | 14 | assert_debug_snapshot_matches!("unresolved_module_diagnostic", &diagnostics); |
16 | r#"[Diagnostic { | ||
17 | message: "unresolved module", | ||
18 | range: [4; 7), | ||
19 | fix: Some(SourceChange { | ||
20 | label: "create module", | ||
21 | source_file_edits: [], | ||
22 | file_system_edits: [CreateFile { source_root: SourceRootId(0), path: "foo.rs" }], | ||
23 | cursor_position: None }), | ||
24 | severity: Error }]"#, | ||
25 | &diagnostics, | ||
26 | ); | ||
27 | } | 15 | } |
28 | 16 | ||
29 | // FIXME: move this test to hir | 17 | // FIXME: move this test to hir |
@@ -31,7 +19,7 @@ fn test_unresolved_module_diagnostic() { | |||
31 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | 19 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { |
32 | let (analysis, file_id) = single_file("mod foo {}"); | 20 | let (analysis, file_id) = single_file("mod foo {}"); |
33 | let diagnostics = analysis.diagnostics(file_id).unwrap(); | 21 | let diagnostics = analysis.diagnostics(file_id).unwrap(); |
34 | assert_eq_dbg(r#"[]"#, &diagnostics); | 22 | assert!(diagnostics.is_empty()); |
35 | } | 23 | } |
36 | 24 | ||
37 | #[test] | 25 | #[test] |
diff --git a/crates/ra_ide_api/tests/test/runnables.rs b/crates/ra_ide_api/tests/test/runnables.rs deleted file mode 100644 index da8d5e0d5..000000000 --- a/crates/ra_ide_api/tests/test/runnables.rs +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | use test_utils::assert_eq_dbg; | ||
2 | |||
3 | use ra_ide_api::mock_analysis::analysis_and_position; | ||
4 | |||
5 | #[test] | ||
6 | fn test_runnables() { | ||
7 | let (analysis, pos) = analysis_and_position( | ||
8 | r#" | ||
9 | //- /lib.rs | ||
10 | <|> //empty | ||
11 | fn main() {} | ||
12 | |||
13 | #[test] | ||
14 | fn test_foo() {} | ||
15 | |||
16 | #[test] | ||
17 | #[ignore] | ||
18 | fn test_foo() {} | ||
19 | "#, | ||
20 | ); | ||
21 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
22 | assert_eq_dbg( | ||
23 | r#"[Runnable { range: [1; 21), kind: Bin }, | ||
24 | Runnable { range: [22; 46), kind: Test { name: "test_foo" } }, | ||
25 | Runnable { range: [47; 81), kind: Test { name: "test_foo" } }]"#, | ||
26 | &runnables, | ||
27 | ) | ||
28 | } | ||
29 | |||
30 | #[test] | ||
31 | fn test_runnables_module() { | ||
32 | let (analysis, pos) = analysis_and_position( | ||
33 | r#" | ||
34 | //- /lib.rs | ||
35 | <|> //empty | ||
36 | mod test_mod { | ||
37 | #[test] | ||
38 | fn test_foo1() {} | ||
39 | } | ||
40 | "#, | ||
41 | ); | ||
42 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
43 | assert_eq_dbg( | ||
44 | r#"[Runnable { range: [1; 59), kind: TestMod { path: "test_mod" } }, | ||
45 | Runnable { range: [28; 57), kind: Test { name: "test_foo1" } }]"#, | ||
46 | &runnables, | ||
47 | ) | ||
48 | } | ||
49 | |||
50 | #[test] | ||
51 | fn test_runnables_one_depth_layer_module() { | ||
52 | let (analysis, pos) = analysis_and_position( | ||
53 | r#" | ||
54 | //- /lib.rs | ||
55 | <|> //empty | ||
56 | mod foo { | ||
57 | mod test_mod { | ||
58 | #[test] | ||
59 | fn test_foo1() {} | ||
60 | } | ||
61 | } | ||
62 | "#, | ||
63 | ); | ||
64 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
65 | assert_eq_dbg( | ||
66 | r#"[Runnable { range: [23; 85), kind: TestMod { path: "foo::test_mod" } }, | ||
67 | Runnable { range: [46; 79), kind: Test { name: "test_foo1" } }]"#, | ||
68 | &runnables, | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | #[test] | ||
73 | fn test_runnables_multiple_depth_module() { | ||
74 | let (analysis, pos) = analysis_and_position( | ||
75 | r#" | ||
76 | //- /lib.rs | ||
77 | <|> //empty | ||
78 | mod foo { | ||
79 | mod bar { | ||
80 | mod test_mod { | ||
81 | #[test] | ||
82 | fn test_foo1() {} | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | "#, | ||
87 | ); | ||
88 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
89 | assert_eq_dbg( | ||
90 | r#"[Runnable { range: [41; 115), kind: TestMod { path: "foo::bar::test_mod" } }, | ||
91 | Runnable { range: [68; 105), kind: Test { name: "test_foo1" } }]"#, | ||
92 | &runnables, | ||
93 | ) | ||
94 | } | ||
95 | |||
96 | #[test] | ||
97 | fn test_runnables_no_test_function_in_module() { | ||
98 | let (analysis, pos) = analysis_and_position( | ||
99 | r#" | ||
100 | //- /lib.rs | ||
101 | <|> //empty | ||
102 | mod test_mod { | ||
103 | fn foo1() {} | ||
104 | } | ||
105 | "#, | ||
106 | ); | ||
107 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
108 | assert_eq_dbg(r#"[]"#, &runnables) | ||
109 | } | ||
diff --git a/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap b/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap new file mode 100644 index 000000000..1b41e2b00 --- /dev/null +++ b/crates/ra_ide_api/tests/test/snapshots/test__unresolved_module_diagnostic.snap | |||
@@ -0,0 +1,26 @@ | |||
1 | Created: 2019-01-15T11:15:20.891129945+00:00 | ||
2 | Creator: [email protected] | ||
3 | Source: crates/ra_ide_api/tests/test/main.rs | ||
4 | |||
5 | [ | ||
6 | Diagnostic { | ||
7 | message: "unresolved module", | ||
8 | range: [4; 7), | ||
9 | fix: Some( | ||
10 | SourceChange { | ||
11 | label: "create module", | ||
12 | source_file_edits: [], | ||
13 | file_system_edits: [ | ||
14 | CreateFile { | ||
15 | source_root: SourceRootId( | ||
16 | 0 | ||
17 | ), | ||
18 | path: "foo.rs" | ||
19 | } | ||
20 | ], | ||
21 | cursor_position: None | ||
22 | } | ||
23 | ), | ||
24 | severity: Error | ||
25 | } | ||
26 | ] | ||