diff options
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 30 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 104 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 11 | ||||
-rw-r--r-- | crates/ra_ide_api/src/name_ref_kind.rs | 95 | ||||
-rw-r--r-- | crates/ra_ide_api/src/snapshots/tests__highlighting.snap | 128 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 49 |
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 | }; |
8 | use hir::{ModuleSource, FieldSource, ImplItem, Either}; | 8 | use hir::{ModuleSource, FieldSource, ImplItem}; |
9 | 9 | ||
10 | use crate::{FileSymbol, db::RootDatabase}; | 10 | use 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 @@ | |||
1 | use ra_db::{FileId, SourceDatabase}; | 1 | use ra_db::{FileId, SourceDatabase}; |
2 | use ra_syntax::{ | 2 | use 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 | }; |
7 | use test_utils::tested_by; | ||
8 | 10 | ||
9 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; | 11 | use crate::{ |
12 | FilePosition, NavigationTarget, | ||
13 | db::RootDatabase, | ||
14 | RangeInfo, | ||
15 | name_ref_kind::{NameRefKind::*, classify_name_ref}, | ||
16 | }; | ||
10 | 17 | ||
11 | pub(crate) fn goto_definition( | 18 | pub(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; | |||
18 | mod status; | 18 | mod status; |
19 | mod completion; | 19 | mod completion; |
20 | mod runnables; | 20 | mod runnables; |
21 | mod name_ref_kind; | ||
21 | mod goto_definition; | 22 | mod goto_definition; |
22 | mod goto_type_definition; | 23 | mod goto_type_definition; |
23 | mod extend_selection; | 24 | mod extend_selection; |
@@ -53,10 +54,7 @@ use ra_db::{ | |||
53 | }; | 54 | }; |
54 | use relative_path::RelativePathBuf; | 55 | use relative_path::RelativePathBuf; |
55 | 56 | ||
56 | use crate::{ | 57 | use crate::{symbol_index::FileSymbol, db::LineIndexDatabase}; |
57 | symbol_index::FileSymbol, | ||
58 | db::LineIndexDatabase, | ||
59 | }; | ||
60 | 58 | ||
61 | pub use crate::{ | 59 | pub 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 | ||
76 | pub use ra_db::{ | 74 | pub use ra_db::{Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, Edition}; |
77 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, | ||
78 | Edition | ||
79 | }; | ||
80 | pub use hir::Documentation; | 75 | pub 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 @@ | |||
1 | use ra_syntax::{AstNode, AstPtr, ast}; | ||
2 | use hir::Either; | ||
3 | use crate::db::RootDatabase; | ||
4 | use test_utils::tested_by; | ||
5 | |||
6 | pub 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 | |||
18 | pub(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 | --- |
2 | created: "2019-03-23T16:20:31.394314144Z" | 2 | created: "2019-05-23T12:10:32.628883358Z" |
3 | creator: insta@0.7.1 | 3 | creator: insta@0.8.1 |
4 | source: crates/ra_ide_api/src/syntax_highlighting.rs | 4 | source: crates/ra_ide_api/src/syntax_highlighting.rs |
5 | expression: result | 5 | expression: result |
6 | --- | 6 | --- |
7 | Ok( | 7 | Ok( |
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)] | ||
124 | struct Foo { | ||
125 | pub x: i32, | ||
126 | pub y: i32, | ||
127 | } | ||
128 | |||
129 | fn foo<T>() -> T { | ||
130 | unimplemented!(); | ||
131 | } | ||
132 | |||
90 | // comment | 133 | // comment |
91 | fn main() {} | 134 | fn 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); |