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/display/navigation_target.rs30
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs104
-rw-r--r--crates/ra_ide_api/src/lib.rs11
-rw-r--r--crates/ra_ide_api/src/name_ref_kind.rs95
-rw-r--r--crates/ra_ide_api/src/snapshots/tests__highlighting.snap128
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs49
6 files changed, 311 insertions, 106 deletions
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 7ea336c50..1c694cbc9 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, 5 ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner},
6 algo::visit::{visitor, Visitor}, 6 algo::visit::{visitor, Visitor},
7}; 7};
8use hir::{ModuleSource, FieldSource, ImplItem, Either}; 8use hir::{ModuleSource, FieldSource, ImplItem};
9 9
10use crate::{FileSymbol, db::RootDatabase}; 10use crate::{FileSymbol, db::RootDatabase};
11 11
@@ -77,17 +77,12 @@ impl NavigationTarget {
77 pub(crate) fn from_pat( 77 pub(crate) fn from_pat(
78 db: &RootDatabase, 78 db: &RootDatabase,
79 file_id: FileId, 79 file_id: FileId,
80 pat: Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>, 80 pat: AstPtr<ast::Pat>,
81 ) -> NavigationTarget { 81 ) -> NavigationTarget {
82 let file = db.parse(file_id); 82 let file = db.parse(file_id);
83 let (name, full_range) = match pat { 83 let (name, full_range) = match pat.to_node(file.syntax()).kind() {
84 Either::A(pat) => match pat.to_node(file.syntax()).kind() { 84 ast::PatKind::BindPat(pat) => return NavigationTarget::from_bind_pat(file_id, &pat),
85 ast::PatKind::BindPat(pat) => { 85 _ => ("_".into(), pat.syntax_node_ptr().range()),
86 return NavigationTarget::from_bind_pat(file_id, &pat)
87 }
88 _ => ("_".into(), pat.syntax_node_ptr().range()),
89 },
90 Either::B(slf) => ("self".into(), slf.syntax_node_ptr().range()),
91 }; 86 };
92 NavigationTarget { 87 NavigationTarget {
93 file_id, 88 file_id,
@@ -99,6 +94,21 @@ impl NavigationTarget {
99 } 94 }
100 } 95 }
101 96
97 pub(crate) fn from_self_param(
98 file_id: FileId,
99 par: AstPtr<ast::SelfParam>,
100 ) -> NavigationTarget {
101 let (name, full_range) = ("self".into(), par.syntax_node_ptr().range());
102 NavigationTarget {
103 file_id,
104 name,
105 full_range,
106 focus_range: None,
107 kind: NAME,
108 container_name: None,
109 }
110 }
111
102 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 112 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
103 let (file_id, source) = module.definition_source(db); 113 let (file_id, source) = module.definition_source(db);
104 let file_id = file_id.as_original_file(); 114 let file_id = file_id.as_original_file();
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index adae29e9c..9c56f17f2 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -1,12 +1,19 @@
1use ra_db::{FileId, SourceDatabase}; 1use ra_db::{FileId, SourceDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, ast, 3 AstNode, ast,
4 algo::{find_node_at_offset, visit::{visitor, Visitor}}, 4 algo::{
5 find_node_at_offset,
6 visit::{visitor, Visitor},
7 },
5 SyntaxNode, 8 SyntaxNode,
6}; 9};
7use test_utils::tested_by;
8 10
9use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; 11use crate::{
12 FilePosition, NavigationTarget,
13 db::RootDatabase,
14 RangeInfo,
15 name_ref_kind::{NameRefKind::*, classify_name_ref},
16};
10 17
11pub(crate) fn goto_definition( 18pub(crate) fn goto_definition(
12 db: &RootDatabase, 19 db: &RootDatabase,
@@ -50,85 +57,24 @@ pub(crate) fn reference_definition(
50 57
51 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 58 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
52 59
53 // Special cases: 60 match classify_name_ref(db, &analyzer, name_ref) {
54 61 Some(Method(func)) => return Exact(NavigationTarget::from_function(db, func)),
55 // Check if it is a method 62 Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)),
56 if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { 63 Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)),
57 tested_by!(goto_definition_works_for_methods); 64 Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_impl_item(db, assoc)),
58 if let Some(func) = analyzer.resolve_method_call(method_call) { 65 Some(Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
59 return Exact(NavigationTarget::from_function(db, func)); 66 Some(SelfType(ty)) => {
60 } 67 if let Some((def_id, _)) = ty.as_adt() {
61 } 68 return Exact(NavigationTarget::from_adt_def(db, def_id));
62
63 //it could be a macro call
64 if let Some(macro_call) = name_ref
65 .syntax()
66 .parent()
67 .and_then(|node| node.parent())
68 .and_then(|node| node.parent())
69 .and_then(ast::MacroCall::cast)
70 {
71 tested_by!(goto_definition_works_for_macros);
72 if let Some(macro_call) = analyzer.resolve_macro_call(macro_call) {
73 return Exact(NavigationTarget::from_macro_def(db, macro_call));
74 }
75 }
76
77 // It could also be a field access
78 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) {
79 tested_by!(goto_definition_works_for_fields);
80 if let Some(field) = analyzer.resolve_field(field_expr) {
81 return Exact(NavigationTarget::from_field(db, field));
82 };
83 }
84
85 // It could also be a named field
86 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) {
87 tested_by!(goto_definition_works_for_named_fields);
88
89 let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast);
90
91 if let Some(ty) = struct_lit.and_then(|lit| analyzer.type_of(db, lit.into())) {
92 if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() {
93 let hir_path = hir::Path::from_name_ref(name_ref);
94 let hir_name = hir_path.as_ident().unwrap();
95
96 if let Some(field) = s.field(db, hir_name) {
97 return Exact(NavigationTarget::from_field(db, field));
98 }
99 } 69 }
100 } 70 }
101 } 71 Some(Pat(pat)) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
102 72 Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)),
103 // General case, a path or a local: 73 Some(GenericParam(_)) => {
104 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { 74 // FIXME: go to the generic param def
105 if let Some(resolved) = analyzer.resolve_path(db, path) {
106 match resolved {
107 hir::PathResolution::Def(def) => return Exact(NavigationTarget::from_def(db, def)),
108 hir::PathResolution::LocalBinding(pat) => {
109 let nav = NavigationTarget::from_pat(db, file_id, pat);
110 return Exact(nav);
111 }
112 hir::PathResolution::GenericParam(..) => {
113 // FIXME: go to the generic param def
114 }
115 hir::PathResolution::Macro(def) => {
116 let nav = NavigationTarget::from_macro_def(db, def);
117 return Exact(nav);
118 }
119 hir::PathResolution::SelfType(impl_block) => {
120 let ty = impl_block.target_ty(db);
121
122 if let Some((def_id, _)) = ty.as_adt() {
123 return Exact(NavigationTarget::from_adt_def(db, def_id));
124 }
125 }
126 hir::PathResolution::AssocItem(assoc) => {
127 return Exact(NavigationTarget::from_impl_item(db, assoc));
128 }
129 }
130 } 75 }
131 } 76 None => {}
77 };
132 78
133 // Fallback index based approach: 79 // Fallback index based approach:
134 let navs = crate::symbol_index::index_resolve(db, name_ref) 80 let navs = crate::symbol_index::index_resolve(db, name_ref)
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index d4be8bd6c..f78348f74 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -18,6 +18,7 @@ mod change;
18mod status; 18mod status;
19mod completion; 19mod completion;
20mod runnables; 20mod runnables;
21mod name_ref_kind;
21mod goto_definition; 22mod goto_definition;
22mod goto_type_definition; 23mod goto_type_definition;
23mod extend_selection; 24mod extend_selection;
@@ -53,10 +54,7 @@ use ra_db::{
53}; 54};
54use relative_path::RelativePathBuf; 55use relative_path::RelativePathBuf;
55 56
56use crate::{ 57use crate::{symbol_index::FileSymbol, db::LineIndexDatabase};
57 symbol_index::FileSymbol,
58 db::LineIndexDatabase,
59};
60 58
61pub use crate::{ 59pub use crate::{
62 change::{AnalysisChange, LibraryData}, 60 change::{AnalysisChange, LibraryData},
@@ -73,10 +71,7 @@ pub use crate::{
73 display::{FunctionSignature, NavigationTarget, StructureNode, file_structure}, 71 display::{FunctionSignature, NavigationTarget, StructureNode, file_structure},
74}; 72};
75 73
76pub use ra_db::{ 74pub use ra_db::{Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, Edition};
77 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
78 Edition
79};
80pub use hir::Documentation; 75pub use hir::Documentation;
81 76
82// We use jemalloc mainly to get heap usage statistics, actual performance 77// We use jemalloc mainly to get heap usage statistics, actual performance
diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs
new file mode 100644
index 000000000..b498fe495
--- /dev/null
+++ b/crates/ra_ide_api/src/name_ref_kind.rs
@@ -0,0 +1,95 @@
1use ra_syntax::{AstNode, AstPtr, ast};
2use hir::Either;
3use crate::db::RootDatabase;
4use test_utils::tested_by;
5
6pub enum NameRefKind {
7 Method(hir::Function),
8 Macro(hir::MacroByExampleDef),
9 FieldAccess(hir::StructField),
10 AssocItem(hir::ImplItem),
11 Def(hir::ModuleDef),
12 SelfType(hir::Ty),
13 Pat(AstPtr<ast::Pat>),
14 SelfParam(AstPtr<ast::SelfParam>),
15 GenericParam(u32),
16}
17
18pub(crate) fn classify_name_ref(
19 db: &RootDatabase,
20 analyzer: &hir::SourceAnalyzer,
21 name_ref: &ast::NameRef,
22) -> Option<NameRefKind> {
23 use NameRefKind::*;
24
25 // Check if it is a method
26 if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) {
27 tested_by!(goto_definition_works_for_methods);
28 if let Some(func) = analyzer.resolve_method_call(method_call) {
29 return Some(Method(func));
30 }
31 }
32
33 // It could be a macro call
34 if let Some(macro_call) = name_ref
35 .syntax()
36 .parent()
37 .and_then(|node| node.parent())
38 .and_then(|node| node.parent())
39 .and_then(ast::MacroCall::cast)
40 {
41 tested_by!(goto_definition_works_for_macros);
42 if let Some(mac) = analyzer.resolve_macro_call(macro_call) {
43 return Some(Macro(mac));
44 }
45 }
46
47 // It could also be a field access
48 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) {
49 tested_by!(goto_definition_works_for_fields);
50 if let Some(field) = analyzer.resolve_field(field_expr) {
51 return Some(FieldAccess(field));
52 };
53 }
54
55 // It could also be a named field
56 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) {
57 tested_by!(goto_definition_works_for_named_fields);
58
59 let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast);
60
61 if let Some(ty) = struct_lit.and_then(|lit| analyzer.type_of(db, lit.into())) {
62 if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() {
63 let hir_path = hir::Path::from_name_ref(name_ref);
64 let hir_name = hir_path.as_ident().unwrap();
65
66 if let Some(field) = s.field(db, hir_name) {
67 return Some(FieldAccess(field));
68 }
69 }
70 }
71 }
72
73 // General case, a path or a local:
74 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
75 if let Some(resolved) = analyzer.resolve_path(db, path) {
76 return match resolved {
77 hir::PathResolution::Def(def) => Some(Def(def)),
78 hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)),
79 hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)),
80 hir::PathResolution::GenericParam(par) => {
81 // FIXME: get generic param def
82 Some(GenericParam(par))
83 }
84 hir::PathResolution::Macro(def) => Some(Macro(def)),
85 hir::PathResolution::SelfType(impl_block) => {
86 let ty = impl_block.target_ty(db);
87 Some(SelfType(ty))
88 }
89 hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)),
90 };
91 }
92 }
93
94 None
95}
diff --git a/crates/ra_ide_api/src/snapshots/tests__highlighting.snap b/crates/ra_ide_api/src/snapshots/tests__highlighting.snap
index 72029e0ed..9d4c04db3 100644
--- a/crates/ra_ide_api/src/snapshots/tests__highlighting.snap
+++ b/crates/ra_ide_api/src/snapshots/tests__highlighting.snap
@@ -1,33 +1,145 @@
1--- 1---
2created: "2019-03-23T16:20:31.394314144Z" 2created: "2019-05-23T12:10:32.628883358Z"
3creator: insta@0.7.1 3creator: insta@0.8.1
4source: crates/ra_ide_api/src/syntax_highlighting.rs 4source: crates/ra_ide_api/src/syntax_highlighting.rs
5expression: result 5expression: result
6--- 6---
7Ok( 7Ok(
8 [ 8 [
9 HighlightedRange { 9 HighlightedRange {
10 range: [1; 11), 10 range: [1; 24),
11 tag: "attribute"
12 },
13 HighlightedRange {
14 range: [25; 31),
15 tag: "keyword"
16 },
17 HighlightedRange {
18 range: [32; 35),
19 tag: "function"
20 },
21 HighlightedRange {
22 range: [42; 45),
23 tag: "keyword"
24 },
25 HighlightedRange {
26 range: [46; 47),
27 tag: "function"
28 },
29 HighlightedRange {
30 range: [49; 52),
31 tag: "text"
32 },
33 HighlightedRange {
34 range: [58; 61),
35 tag: "keyword"
36 },
37 HighlightedRange {
38 range: [62; 63),
39 tag: "function"
40 },
41 HighlightedRange {
42 range: [65; 68),
43 tag: "text"
44 },
45 HighlightedRange {
46 range: [73; 75),
47 tag: "keyword"
48 },
49 HighlightedRange {
50 range: [76; 79),
51 tag: "function"
52 },
53 HighlightedRange {
54 range: [80; 81),
55 tag: "type"
56 },
57 HighlightedRange {
58 range: [80; 81),
59 tag: "function"
60 },
61 HighlightedRange {
62 range: [88; 89),
63 tag: "type"
64 },
65 HighlightedRange {
66 range: [96; 110),
67 tag: "macro"
68 },
69 HighlightedRange {
70 range: [117; 127),
11 tag: "comment" 71 tag: "comment"
12 }, 72 },
13 HighlightedRange { 73 HighlightedRange {
14 range: [12; 14), 74 range: [128; 130),
15 tag: "keyword" 75 tag: "keyword"
16 }, 76 },
17 HighlightedRange { 77 HighlightedRange {
18 range: [15; 19), 78 range: [131; 135),
19 tag: "function" 79 tag: "function"
20 }, 80 },
21 HighlightedRange { 81 HighlightedRange {
22 range: [29; 37), 82 range: [145; 153),
23 tag: "macro" 83 tag: "macro"
24 }, 84 },
25 HighlightedRange { 85 HighlightedRange {
26 range: [38; 50), 86 range: [154; 166),
27 tag: "string" 87 tag: "string"
28 }, 88 },
29 HighlightedRange { 89 HighlightedRange {
30 range: [52; 54), 90 range: [168; 170),
91 tag: "literal"
92 },
93 HighlightedRange {
94 range: [178; 181),
95 tag: "keyword"
96 },
97 HighlightedRange {
98 range: [182; 185),
99 tag: "keyword"
100 },
101 HighlightedRange {
102 range: [186; 189),
103 tag: "macro"
104 },
105 HighlightedRange {
106 range: [197; 200),
107 tag: "macro"
108 },
109 HighlightedRange {
110 range: [192; 195),
111 tag: "text"
112 },
113 HighlightedRange {
114 range: [208; 211),
115 tag: "macro"
116 },
117 HighlightedRange {
118 range: [212; 216),
119 tag: "macro"
120 },
121 HighlightedRange {
122 range: [226; 227),
123 tag: "literal"
124 },
125 HighlightedRange {
126 range: [232; 233),
127 tag: "literal"
128 },
129 HighlightedRange {
130 range: [242; 248),
131 tag: "keyword.unsafe"
132 },
133 HighlightedRange {
134 range: [251; 254),
135 tag: "text"
136 },
137 HighlightedRange {
138 range: [255; 262),
139 tag: "text"
140 },
141 HighlightedRange {
142 range: [263; 264),
31 tag: "literal" 143 tag: "literal"
32 } 144 }
33 ] 145 ]
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 2158291dc..89f20260f 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -40,8 +40,41 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
40 COMMENT => "comment", 40 COMMENT => "comment",
41 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 41 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
42 ATTR => "attribute", 42 ATTR => "attribute",
43 NAME_REF => "text", 43 NAME_REF => {
44 if let Some(name_ref) = node.as_node().and_then(|n| ast::NameRef::cast(n)) {
45 use crate::name_ref_kind::{classify_name_ref, NameRefKind::*};
46 use hir::{ModuleDef, ImplItem};
47
48 // FIXME: try to reuse the SourceAnalyzers
49 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
50 match classify_name_ref(db, &analyzer, name_ref) {
51 Some(Method(_)) => "function",
52 Some(Macro(_)) => "macro",
53 Some(FieldAccess(_)) => "field",
54 Some(AssocItem(ImplItem::Method(_))) => "function",
55 Some(AssocItem(ImplItem::Const(_))) => "constant",
56 Some(AssocItem(ImplItem::TypeAlias(_))) => "type",
57 Some(Def(ModuleDef::Module(_))) => "module",
58 Some(Def(ModuleDef::Function(_))) => "function",
59 Some(Def(ModuleDef::Struct(_))) => "type",
60 Some(Def(ModuleDef::Enum(_))) => "type",
61 Some(Def(ModuleDef::EnumVariant(_))) => "constant",
62 Some(Def(ModuleDef::Const(_))) => "constant",
63 Some(Def(ModuleDef::Static(_))) => "constant",
64 Some(Def(ModuleDef::Trait(_))) => "type",
65 Some(Def(ModuleDef::TypeAlias(_))) => "type",
66 Some(SelfType(_)) => "type",
67 Some(Pat(_)) => "text",
68 Some(SelfParam(_)) => "type",
69 Some(GenericParam(_)) => "type",
70 None => "text",
71 }
72 } else {
73 "text"
74 }
75 }
44 NAME => "function", 76 NAME => "function",
77 TYPE_ALIAS_DEF | TYPE_ARG | TYPE_PARAM => "type",
45 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 78 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
46 LIFETIME => "parameter", 79 LIFETIME => "parameter",
47 T![unsafe] => "keyword.unsafe", 80 T![unsafe] => "keyword.unsafe",
@@ -87,9 +120,23 @@ mod tests {
87 fn test_highlighting() { 120 fn test_highlighting() {
88 let (analysis, file_id) = single_file( 121 let (analysis, file_id) = single_file(
89 r#" 122 r#"
123#[derive(Clone, Debug)]
124struct Foo {
125 pub x: i32,
126 pub y: i32,
127}
128
129fn foo<T>() -> T {
130 unimplemented!();
131}
132
90// comment 133// comment
91fn main() {} 134fn main() {}
92 println!("Hello, {}!", 92); 135 println!("Hello, {}!", 92);
136
137 let mut vec = Vec::new();
138 vec.push(Foo { x: 0, y: 1 });
139 unsafe { vec.set_len(0); }
93"#, 140"#,
94 ); 141 );
95 let result = analysis.highlight(file_id); 142 let result = analysis.highlight(file_id);