diff options
author | Aleksey Kladov <[email protected]> | 2020-03-02 18:00:38 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-03-02 18:00:38 +0000 |
commit | 2716a1fa3f8a7410248724a6ce5d4c28837db682 (patch) | |
tree | ad1faf323e4cb1478e1e34e2ed9fe858c5be80e5 /crates | |
parent | 96eca8a1abd79840b9040250db9d1e65ec663b0e (diff) |
More principled approach for gotodef for field shorhand
Callers can now decide for themselves if they should prefer field or
local definition. By default, it's the local.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 27 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/references.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide/src/references/classify.rs | 35 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 30 |
7 files changed, 79 insertions, 36 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index a0853957c..afc7f7ee7 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -107,8 +107,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
107 | self.analyze(field.syntax()).resolve_field(field) | 107 | self.analyze(field.syntax()).resolve_field(field) |
108 | } | 108 | } |
109 | 109 | ||
110 | pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<StructField> { | 110 | pub fn resolve_record_field( |
111 | self.analyze(field.syntax()).resolve_record_field(field) | 111 | &self, |
112 | field: &ast::RecordField, | ||
113 | ) -> Option<(StructField, Option<Local>)> { | ||
114 | self.analyze(field.syntax()).resolve_record_field(self.db, field) | ||
112 | } | 115 | } |
113 | 116 | ||
114 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<VariantDef> { | 117 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<VariantDef> { |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 4c121eb73..015389fb0 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | //! | 5 | //! |
6 | //! So, this modules should not be used during hir construction, it exists | 6 | //! So, this modules should not be used during hir construction, it exists |
7 | //! purely for "IDE needs". | 7 | //! purely for "IDE needs". |
8 | use std::sync::Arc; | 8 | use std::{iter::once, sync::Arc}; |
9 | 9 | ||
10 | use either::Either; | 10 | use either::Either; |
11 | use hir_def::{ | 11 | use hir_def::{ |
@@ -25,8 +25,8 @@ use ra_syntax::{ | |||
25 | }; | 25 | }; |
26 | 26 | ||
27 | use crate::{ | 27 | use crate::{ |
28 | db::HirDatabase, Adt, Const, EnumVariant, Function, Local, MacroDef, ModuleDef, Path, Static, | 28 | db::HirDatabase, Adt, Const, EnumVariant, Function, Local, MacroDef, ModPath, ModuleDef, Path, |
29 | Struct, Trait, Type, TypeAlias, TypeParam, | 29 | PathKind, Static, Struct, Trait, Type, TypeAlias, TypeParam, |
30 | }; | 30 | }; |
31 | 31 | ||
32 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | 32 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of |
@@ -162,16 +162,27 @@ impl SourceAnalyzer { | |||
162 | 162 | ||
163 | pub(crate) fn resolve_record_field( | 163 | pub(crate) fn resolve_record_field( |
164 | &self, | 164 | &self, |
165 | db: &impl HirDatabase, | ||
165 | field: &ast::RecordField, | 166 | field: &ast::RecordField, |
166 | ) -> Option<crate::StructField> { | 167 | ) -> Option<(crate::StructField, Option<Local>)> { |
167 | let expr_id = match field.expr() { | 168 | let (expr_id, local) = match field.expr() { |
168 | Some(it) => self.expr_id(&it)?, | 169 | Some(it) => (self.expr_id(&it)?, None), |
169 | None => { | 170 | None => { |
170 | let src = InFile { file_id: self.file_id, value: field }; | 171 | let src = InFile { file_id: self.file_id, value: field }; |
171 | self.body_source_map.as_ref()?.field_init_shorthand_expr(src)? | 172 | let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?; |
173 | let local_name = field.name_ref()?.as_name(); | ||
174 | let path = ModPath::from_segments(PathKind::Plain, once(local_name)); | ||
175 | let local = match self.resolver.resolve_path_in_value_ns_fully(db, &path) { | ||
176 | Some(ValueNs::LocalBinding(pat_id)) => { | ||
177 | Some(Local { pat_id, parent: self.resolver.body_owner()? }) | ||
178 | } | ||
179 | _ => None, | ||
180 | }; | ||
181 | (expr_id, local) | ||
172 | } | 182 | } |
173 | }; | 183 | }; |
174 | self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into()) | 184 | let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; |
185 | Some((struct_field.into(), local)) | ||
175 | } | 186 | } |
176 | 187 | ||
177 | pub(crate) fn resolve_record_literal( | 188 | pub(crate) fn resolve_record_literal( |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index e67585203..76ee232a3 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -76,6 +76,8 @@ pub(crate) fn reference_definition( | |||
76 | 76 | ||
77 | let name_kind = classify_name_ref(sema, name_ref); | 77 | let name_kind = classify_name_ref(sema, name_ref); |
78 | if let Some(def) = name_kind { | 78 | if let Some(def) = name_kind { |
79 | let def = def.definition(); | ||
80 | |||
79 | return match def.try_to_nav(sema.db) { | 81 | return match def.try_to_nav(sema.db) { |
80 | Some(nav) => ReferenceResult::Exact(nav), | 82 | Some(nav) => ReferenceResult::Exact(nav), |
81 | None => ReferenceResult::Approximate(Vec::new()), | 83 | None => ReferenceResult::Approximate(Vec::new()), |
@@ -795,8 +797,8 @@ mod tests { | |||
795 | Foo { x<|> }; | 797 | Foo { x<|> }; |
796 | } | 798 | } |
797 | ", | 799 | ", |
798 | "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)", | 800 | "x BIND_PAT FileId(1) [42; 43)", |
799 | "x: i32|x", | 801 | "x", |
800 | ) | 802 | ) |
801 | } | 803 | } |
802 | } | 804 | } |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 5073bb1cf..b31956626 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -153,7 +153,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
153 | if let Some((node, name_kind)) = match_ast! { | 153 | if let Some((node, name_kind)) = match_ast! { |
154 | match (token.parent()) { | 154 | match (token.parent()) { |
155 | ast::NameRef(name_ref) => { | 155 | ast::NameRef(name_ref) => { |
156 | classify_name_ref(&sema, &name_ref).map(|d| (name_ref.syntax().clone(), d)) | 156 | classify_name_ref(&sema, &name_ref).map(|d| (name_ref.syntax().clone(), d.definition())) |
157 | }, | 157 | }, |
158 | ast::Name(name) => { | 158 | ast::Name(name) => { |
159 | classify_name(&sema, &name).map(|d| (name.syntax().clone(), d.definition())) | 159 | classify_name(&sema, &name).map(|d| (name.syntax().clone(), d.definition())) |
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index f763013ae..2eb047c96 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -27,7 +27,10 @@ use test_utils::tested_by; | |||
27 | 27 | ||
28 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; | 28 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; |
29 | 29 | ||
30 | pub(crate) use self::{classify::classify_name_ref, rename::rename}; | 30 | pub(crate) use self::{ |
31 | classify::{classify_name_ref, NameRefClass}, | ||
32 | rename::rename, | ||
33 | }; | ||
31 | pub(crate) use ra_ide_db::defs::{classify_name, NameDefinition}; | 34 | pub(crate) use ra_ide_db::defs::{classify_name, NameDefinition}; |
32 | 35 | ||
33 | pub use self::search_scope::SearchScope; | 36 | pub use self::search_scope::SearchScope; |
@@ -160,7 +163,7 @@ fn find_name( | |||
160 | return Some(RangeInfo::new(range, (name.text().to_string(), def))); | 163 | return Some(RangeInfo::new(range, (name.text().to_string(), def))); |
161 | } | 164 | } |
162 | let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; | 165 | let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; |
163 | let def = classify_name_ref(sema, &name_ref)?; | 166 | let def = classify_name_ref(sema, &name_ref)?.definition(); |
164 | let range = name_ref.syntax().text_range(); | 167 | let range = name_ref.syntax().text_range(); |
165 | Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) | 168 | Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) |
166 | } | 169 | } |
@@ -212,6 +215,7 @@ fn process_definition( | |||
212 | // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098 | 215 | // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098 |
213 | 216 | ||
214 | if let Some(d) = classify_name_ref(&sema, &name_ref) { | 217 | if let Some(d) = classify_name_ref(&sema, &name_ref) { |
218 | let d = d.definition(); | ||
215 | if d == def { | 219 | if d == def { |
216 | let kind = | 220 | let kind = |
217 | if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) { | 221 | if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) { |
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs index fdd07d8d1..e837ca8a3 100644 --- a/crates/ra_ide/src/references/classify.rs +++ b/crates/ra_ide/src/references/classify.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Functions that are used to classify an element from its definition or reference. | 1 | //! Functions that are used to classify an element from its definition or reference. |
2 | 2 | ||
3 | use hir::{PathResolution, Semantics}; | 3 | use hir::{Local, PathResolution, Semantics}; |
4 | use ra_ide_db::defs::NameDefinition; | 4 | use ra_ide_db::defs::NameDefinition; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_prof::profile; | 6 | use ra_prof::profile; |
@@ -9,10 +9,24 @@ use test_utils::tested_by; | |||
9 | 9 | ||
10 | pub use ra_ide_db::defs::{from_module_def, from_struct_field}; | 10 | pub use ra_ide_db::defs::{from_module_def, from_struct_field}; |
11 | 11 | ||
12 | pub enum NameRefClass { | ||
13 | NameDefinition(NameDefinition), | ||
14 | FieldShorthand { local: Local, field: NameDefinition }, | ||
15 | } | ||
16 | |||
17 | impl NameRefClass { | ||
18 | pub fn definition(self) -> NameDefinition { | ||
19 | match self { | ||
20 | NameRefClass::NameDefinition(def) => def, | ||
21 | NameRefClass::FieldShorthand { local, field: _ } => NameDefinition::Local(local), | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | |||
12 | pub(crate) fn classify_name_ref( | 26 | pub(crate) fn classify_name_ref( |
13 | sema: &Semantics<RootDatabase>, | 27 | sema: &Semantics<RootDatabase>, |
14 | name_ref: &ast::NameRef, | 28 | name_ref: &ast::NameRef, |
15 | ) -> Option<NameDefinition> { | 29 | ) -> Option<NameRefClass> { |
16 | let _p = profile("classify_name_ref"); | 30 | let _p = profile("classify_name_ref"); |
17 | 31 | ||
18 | let parent = name_ref.syntax().parent()?; | 32 | let parent = name_ref.syntax().parent()?; |
@@ -20,29 +34,34 @@ pub(crate) fn classify_name_ref( | |||
20 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | 34 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { |
21 | tested_by!(goto_def_for_methods); | 35 | tested_by!(goto_def_for_methods); |
22 | if let Some(func) = sema.resolve_method_call(&method_call) { | 36 | if let Some(func) = sema.resolve_method_call(&method_call) { |
23 | return Some(from_module_def(func.into())); | 37 | return Some(NameRefClass::NameDefinition(NameDefinition::ModuleDef(func.into()))); |
24 | } | 38 | } |
25 | } | 39 | } |
26 | 40 | ||
27 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | 41 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { |
28 | tested_by!(goto_def_for_fields); | 42 | tested_by!(goto_def_for_fields); |
29 | if let Some(field) = sema.resolve_field(&field_expr) { | 43 | if let Some(field) = sema.resolve_field(&field_expr) { |
30 | return Some(from_struct_field(field)); | 44 | return Some(NameRefClass::NameDefinition(NameDefinition::StructField(field))); |
31 | } | 45 | } |
32 | } | 46 | } |
33 | 47 | ||
34 | if let Some(record_field) = ast::RecordField::cast(parent.clone()) { | 48 | if let Some(record_field) = ast::RecordField::cast(parent.clone()) { |
35 | tested_by!(goto_def_for_record_fields); | 49 | tested_by!(goto_def_for_record_fields); |
36 | tested_by!(goto_def_for_field_init_shorthand); | 50 | tested_by!(goto_def_for_field_init_shorthand); |
37 | if let Some(field_def) = sema.resolve_record_field(&record_field) { | 51 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { |
38 | return Some(from_struct_field(field_def)); | 52 | let field = NameDefinition::StructField(field); |
53 | let res = match local { | ||
54 | None => NameRefClass::NameDefinition(field), | ||
55 | Some(local) => NameRefClass::FieldShorthand { field, local }, | ||
56 | }; | ||
57 | return Some(res); | ||
39 | } | 58 | } |
40 | } | 59 | } |
41 | 60 | ||
42 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | 61 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { |
43 | tested_by!(goto_def_for_macros); | 62 | tested_by!(goto_def_for_macros); |
44 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | 63 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { |
45 | return Some(NameDefinition::Macro(macro_def)); | 64 | return Some(NameRefClass::NameDefinition(NameDefinition::Macro(macro_def))); |
46 | } | 65 | } |
47 | } | 66 | } |
48 | 67 | ||
@@ -63,5 +82,5 @@ pub(crate) fn classify_name_ref( | |||
63 | PathResolution::Macro(def) => NameDefinition::Macro(def), | 82 | PathResolution::Macro(def) => NameDefinition::Macro(def), |
64 | PathResolution::SelfType(impl_def) => NameDefinition::SelfType(impl_def), | 83 | PathResolution::SelfType(impl_def) => NameDefinition::SelfType(impl_def), |
65 | }; | 84 | }; |
66 | Some(res) | 85 | Some(NameRefClass::NameDefinition(res)) |
67 | } | 86 | } |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 28117b4d8..b89501aff 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -19,7 +19,11 @@ use ra_syntax::{ | |||
19 | }; | 19 | }; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | 21 | ||
22 | use crate::{call_info::call_info_for_token, references::classify_name_ref, Analysis, FileId}; | 22 | use crate::{ |
23 | call_info::call_info_for_token, | ||
24 | references::{classify_name_ref, NameRefClass}, | ||
25 | Analysis, FileId, | ||
26 | }; | ||
23 | 27 | ||
24 | pub(crate) use html::highlight_as_html; | 28 | pub(crate) use html::highlight_as_html; |
25 | pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; | 29 | pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; |
@@ -186,24 +190,24 @@ fn highlight_element( | |||
186 | } | 190 | } |
187 | 191 | ||
188 | // Highlight references like the definitions they resolve to | 192 | // Highlight references like the definitions they resolve to |
189 | |||
190 | // Special-case field init shorthand | ||
191 | NAME_REF if element.parent().and_then(ast::RecordField::cast).is_some() => { | ||
192 | HighlightTag::Field.into() | ||
193 | } | ||
194 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => return None, | 193 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => return None, |
195 | NAME_REF => { | 194 | NAME_REF => { |
196 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | 195 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); |
197 | let name_kind = classify_name_ref(sema, &name_ref)?; | 196 | let name_kind = classify_name_ref(sema, &name_ref)?; |
198 | 197 | ||
199 | if let NameDefinition::Local(local) = &name_kind { | 198 | match name_kind { |
200 | if let Some(name) = local.name(db) { | 199 | NameRefClass::NameDefinition(def) => { |
201 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | 200 | if let NameDefinition::Local(local) = &def { |
202 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | 201 | if let Some(name) = local.name(db) { |
202 | let shadow_count = | ||
203 | bindings_shadow_count.entry(name.clone()).or_default(); | ||
204 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
205 | } | ||
206 | }; | ||
207 | highlight_name(db, def) | ||
203 | } | 208 | } |
204 | }; | 209 | NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), |
205 | 210 | } | |
206 | highlight_name(db, name_kind) | ||
207 | } | 211 | } |
208 | 212 | ||
209 | // Simple token-based highlighting | 213 | // Simple token-based highlighting |