aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-02 18:01:50 +0000
committerGitHub <[email protected]>2020-03-02 18:01:50 +0000
commit7928ac4bbd8c75ac779d6da7e9cbe6aa314fb5bd (patch)
tree4a0f3b337f334d5355a79c60279bebefa0c68616
parent71b53b2cae74d6f84c79d21b24754792a8435149 (diff)
parent2716a1fa3f8a7410248724a6ce5d4c28837db682 (diff)
Merge #3405
3405: More principled approach for gotodef for field shorhand r=matklad a=matklad Callers can now decide for themselves if they should prefer field or local definition. By default, it's the local. bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_hir/src/semantics.rs7
-rw-r--r--crates/ra_hir/src/source_analyzer.rs27
-rw-r--r--crates/ra_ide/src/goto_definition.rs6
-rw-r--r--crates/ra_ide/src/hover.rs2
-rw-r--r--crates/ra_ide/src/references.rs8
-rw-r--r--crates/ra_ide/src/references/classify.rs35
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs30
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".
8use std::sync::Arc; 8use std::{iter::once, sync::Arc};
9 9
10use either::Either; 10use either::Either;
11use hir_def::{ 11use hir_def::{
@@ -25,8 +25,8 @@ use ra_syntax::{
25}; 25};
26 26
27use crate::{ 27use 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
28use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; 28use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
29 29
30pub(crate) use self::{classify::classify_name_ref, rename::rename}; 30pub(crate) use self::{
31 classify::{classify_name_ref, NameRefClass},
32 rename::rename,
33};
31pub(crate) use ra_ide_db::defs::{classify_name, NameDefinition}; 34pub(crate) use ra_ide_db::defs::{classify_name, NameDefinition};
32 35
33pub use self::search_scope::SearchScope; 36pub 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
3use hir::{PathResolution, Semantics}; 3use hir::{Local, PathResolution, Semantics};
4use ra_ide_db::defs::NameDefinition; 4use ra_ide_db::defs::NameDefinition;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_prof::profile; 6use ra_prof::profile;
@@ -9,10 +9,24 @@ use test_utils::tested_by;
9 9
10pub use ra_ide_db::defs::{from_module_def, from_struct_field}; 10pub use ra_ide_db::defs::{from_module_def, from_struct_field};
11 11
12pub enum NameRefClass {
13 NameDefinition(NameDefinition),
14 FieldShorthand { local: Local, field: NameDefinition },
15}
16
17impl 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
12pub(crate) fn classify_name_ref( 26pub(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(&macro_call) { 63 if let Some(macro_def) = sema.resolve_macro_call(&macro_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};
20use rustc_hash::FxHashMap; 20use rustc_hash::FxHashMap;
21 21
22use crate::{call_info::call_info_for_token, references::classify_name_ref, Analysis, FileId}; 22use crate::{
23 call_info::call_info_for_token,
24 references::{classify_name_ref, NameRefClass},
25 Analysis, FileId,
26};
23 27
24pub(crate) use html::highlight_as_html; 28pub(crate) use html::highlight_as_html;
25pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; 29pub 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