aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-11-11 11:48:02 +0000
committerGitHub <[email protected]>2019-11-11 11:48:02 +0000
commita599147b4232c0d4f6b071a3a96e86f903f4cf52 (patch)
treefc8ddd1428c4be2babbdd713c852b31276a315f2 /crates
parentef2a9aedb6ac7f0b79e636cff7947935fecb909d (diff)
parent8b7f853cc19d0940ec542e10bc23aa78455bbb3b (diff)
Merge #2200
2200: Add variables to HIR r=matklad a=matklad Introduce a `hir::Variable`, which should cover locals, parameters and `self`. Unlike `PatId`, variable knows it's owner so it is self-contained, and should be more convenient to use from `ra_ide_api`. The goal here is to hide more details about `Body` from hir, which should make it easier to move `Body` into `hir_def`. I don't think that `ra_ide_api` intrracts with bodies directly at the moment anyway, but the glue layer is based basically on `ast::BindPat`, which seems pretty brittle. Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/code_model.rs55
-rw-r--r--crates/ra_hir/src/expr/scope.rs2
-rw-r--r--crates/ra_hir/src/from_source.rs30
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs20
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs70
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs3
-rw-r--r--crates/ra_ide_api/src/hover.rs2
-rw-r--r--crates/ra_ide_api/src/references.rs3
-rw-r--r--crates/ra_ide_api/src/references/classify.rs22
-rw-r--r--crates/ra_ide_api/src/references/name_definition.rs38
-rw-r--r--crates/ra_ide_api/src/references/search_scope.rs6
-rw-r--r--crates/ra_ide_api/src/snapshots/rainbow_highlighting.html12
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs79
14 files changed, 171 insertions, 173 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index e5bfad3ca..09c4e97fa 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -22,7 +22,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
22use crate::{ 22use crate::{
23 adt::VariantDef, 23 adt::VariantDef,
24 db::{AstDatabase, DefDatabase, HirDatabase}, 24 db::{AstDatabase, DefDatabase, HirDatabase},
25 expr::{validation::ExprValidator, Body, BodySourceMap}, 25 expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId},
26 generics::HasGenericParams, 26 generics::HasGenericParams,
27 ids::{ 27 ids::{
28 AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, 28 AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
@@ -32,7 +32,7 @@ use crate::{
32 resolve::{Resolver, Scope, TypeNs}, 32 resolve::{Resolver, Scope, TypeNs},
33 traits::TraitData, 33 traits::TraitData,
34 ty::{InferenceResult, Namespace, TraitRef}, 34 ty::{InferenceResult, Namespace, TraitRef},
35 Either, HasSource, ImportId, Name, ScopeDef, Ty, 35 Either, HasSource, ImportId, Name, ScopeDef, Source, Ty,
36}; 36};
37 37
38/// hir::Crate describes a single crate. It's the main interface with which 38/// hir::Crate describes a single crate. It's the main interface with which
@@ -1070,3 +1070,54 @@ impl AssocItem {
1070 .expect("AssocItem without container") 1070 .expect("AssocItem without container")
1071 } 1071 }
1072} 1072}
1073
1074#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1075pub struct Local {
1076 pub(crate) parent: DefWithBody,
1077 pub(crate) pat_id: PatId,
1078}
1079
1080impl Local {
1081 pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
1082 let body = db.body_hir(self.parent);
1083 match &body[self.pat_id] {
1084 Pat::Bind { name, .. } => Some(name.clone()),
1085 _ => None,
1086 }
1087 }
1088
1089 pub fn is_self(self, db: &impl HirDatabase) -> bool {
1090 self.name(db) == Some(name::SELF_PARAM)
1091 }
1092
1093 pub fn is_mut(self, db: &impl HirDatabase) -> bool {
1094 let body = db.body_hir(self.parent);
1095 match &body[self.pat_id] {
1096 Pat::Bind { mode, .. } => match mode {
1097 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
1098 _ => false,
1099 },
1100 _ => false,
1101 }
1102 }
1103
1104 pub fn parent(self, _db: &impl HirDatabase) -> DefWithBody {
1105 self.parent
1106 }
1107
1108 pub fn module(self, db: &impl HirDatabase) -> Module {
1109 self.parent.module(db)
1110 }
1111
1112 pub fn ty(self, db: &impl HirDatabase) -> Ty {
1113 let infer = db.infer(self.parent);
1114 infer[self.pat_id].clone()
1115 }
1116
1117 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
1118 let (_body, source_map) = db.body_with_source_map(self.parent);
1119 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
1120 let root = src.file_syntax(db);
1121 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root)))
1122 }
1123}
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index 5a1eade2c..daf8d8d07 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -17,7 +17,7 @@ impl_arena_id!(ScopeId);
17 17
18#[derive(Debug, PartialEq, Eq)] 18#[derive(Debug, PartialEq, Eq)]
19pub struct ExprScopes { 19pub struct ExprScopes {
20 body: Arc<Body>, 20 pub(crate) body: Arc<Body>,
21 scopes: Arena<ScopeId, ScopeData>, 21 scopes: Arena<ScopeId, ScopeData>,
22 scope_by_expr: FxHashMap<ExprId, ScopeId>, 22 scope_by_expr: FxHashMap<ExprId, ScopeId>,
23} 23}
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index c95d2cdd0..2c441b0f4 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -2,13 +2,17 @@
2 2
3use hir_def::{StructId, StructOrUnionId, UnionId}; 3use hir_def::{StructId, StructOrUnionId, UnionId};
4use hir_expand::name::AsName; 4use hir_expand::name::AsName;
5use ra_syntax::ast::{self, AstNode, NameOwner}; 5use ra_syntax::{
6 ast::{self, AstNode, NameOwner},
7 match_ast,
8};
6 9
7use crate::{ 10use crate::{
8 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
9 ids::{AstItemDef, LocationCtx}, 12 ids::{AstItemDef, LocationCtx},
10 AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, 13 AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource,
11 ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, 14 ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias,
15 Union, VariantDef,
12}; 16};
13 17
14pub trait FromSource: Sized { 18pub trait FromSource: Sized {
@@ -126,6 +130,26 @@ impl FromSource for StructField {
126 } 130 }
127} 131}
128 132
133impl Local {
134 pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> {
135 let file_id = src.file_id;
136 let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| {
137 let res = match_ast! {
138 match it {
139 ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() },
140 ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() },
141 ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() },
142 _ => return None,
143 }
144 };
145 Some(res)
146 })?;
147 let (_body, source_map) = db.body_with_source_map(parent);
148 let pat_id = source_map.node_pat(&src.ast.into())?;
149 Some(Local { parent, pat_id })
150 }
151}
152
129impl Module { 153impl Module {
130 pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { 154 pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
131 let src_parent = Source { 155 let src_parent = Source {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 9dc8d139b..806f1daed 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -65,7 +65,7 @@ pub use crate::{
65 docs::{DocDef, Docs, Documentation}, 65 docs::{DocDef, Docs, Documentation},
66 src::{HasBodySource, HasSource}, 66 src::{HasBodySource, HasSource},
67 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, 67 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
68 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, 68 EnumVariant, FieldSource, FnData, Function, HasBody, Local, MacroDef, Module, ModuleDef,
69 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, 69 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
70 }, 70 },
71 expr::ExprScopes, 71 expr::ExprScopes,
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 66cb4b357..c5fdf3bab 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -28,7 +28,7 @@ use crate::{
28 ids::LocationCtx, 28 ids::LocationCtx,
29 resolve::{ScopeDef, TypeNs, ValueNs}, 29 resolve::{ScopeDef, TypeNs, ValueNs},
30 ty::method_resolution::{self, implements_trait}, 30 ty::method_resolution::{self, implements_trait},
31 AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, 31 AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, Local,
32 MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, 32 MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
33}; 33};
34 34
@@ -94,6 +94,7 @@ fn def_with_body_from_child_node(
94#[derive(Debug)] 94#[derive(Debug)]
95pub struct SourceAnalyzer { 95pub struct SourceAnalyzer {
96 resolver: Resolver, 96 resolver: Resolver,
97 body_owner: Option<DefWithBody>,
97 body_source_map: Option<Arc<BodySourceMap>>, 98 body_source_map: Option<Arc<BodySourceMap>>,
98 infer: Option<Arc<crate::ty::InferenceResult>>, 99 infer: Option<Arc<crate::ty::InferenceResult>>,
99 scopes: Option<Arc<crate::expr::ExprScopes>>, 100 scopes: Option<Arc<crate::expr::ExprScopes>>,
@@ -104,7 +105,7 @@ pub enum PathResolution {
104 /// An item 105 /// An item
105 Def(crate::ModuleDef), 106 Def(crate::ModuleDef),
106 /// A local binding (only value namespace) 107 /// A local binding (only value namespace)
107 LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>), 108 Local(Local),
108 /// A generic parameter 109 /// A generic parameter
109 GenericParam(u32), 110 GenericParam(u32),
110 SelfType(crate::ImplBlock), 111 SelfType(crate::ImplBlock),
@@ -152,6 +153,7 @@ impl SourceAnalyzer {
152 let resolver = expr::resolver_for_scope(def.body(db), db, scope); 153 let resolver = expr::resolver_for_scope(def.body(db), db, scope);
153 SourceAnalyzer { 154 SourceAnalyzer {
154 resolver, 155 resolver,
156 body_owner: Some(def),
155 body_source_map: Some(source_map), 157 body_source_map: Some(source_map),
156 infer: Some(def.infer(db)), 158 infer: Some(def.infer(db)),
157 scopes: Some(scopes), 159 scopes: Some(scopes),
@@ -162,6 +164,7 @@ impl SourceAnalyzer {
162 .ancestors() 164 .ancestors()
163 .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) 165 .find_map(|node| try_get_resolver_for_node(db, file_id, &node))
164 .unwrap_or_default(), 166 .unwrap_or_default(),
167 body_owner: None,
165 body_source_map: None, 168 body_source_map: None,
166 infer: None, 169 infer: None,
167 scopes: None, 170 scopes: None,
@@ -233,16 +236,9 @@ impl SourceAnalyzer {
233 }); 236 });
234 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { 237 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
235 let res = match val { 238 let res = match val {
236 ValueNs::LocalBinding(it) => { 239 ValueNs::LocalBinding(pat_id) => {
237 // We get a `PatId` from resolver, but it actually can only 240 let var = Local { parent: self.body_owner?, pat_id };
238 // point at `BindPat`, and not at the arbitrary pattern. 241 PathResolution::Local(var)
239 let pat_ptr = self
240 .body_source_map
241 .as_ref()?
242 .pat_syntax(it)?
243 .ast // FIXME: ignoring file_id here is definitelly wrong
244 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
245 PathResolution::LocalBinding(pat_ptr)
246 } 242 }
247 ValueNs::Function(it) => PathResolution::Def(it.into()), 243 ValueNs::Function(it) => PathResolution::Def(it.into()),
248 ValueNs::Const(it) => PathResolution::Def(it.into()), 244 ValueNs::Const(it) => PathResolution::Def(it.into()),
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 41d467564..f7ad08515 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -1,11 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{AssocItem, FieldSource, HasSource, ModuleSource}; 3use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource};
4use ra_db::{FileId, SourceDatabase}; 4use ra_db::{FileId, SourceDatabase};
5use ra_syntax::{ 5use ra_syntax::{
6 ast::{self, DocCommentsOwner}, 6 ast::{self, DocCommentsOwner, NameOwner},
7 match_ast, AstNode, AstPtr, SmolStr, 7 match_ast, AstNode, SmolStr,
8 SyntaxKind::{self, NAME}, 8 SyntaxKind::{self, BIND_PAT},
9 SyntaxNode, TextRange, 9 SyntaxNode, TextRange,
10}; 10};
11 11
@@ -76,42 +76,6 @@ impl NavigationTarget {
76 self.focus_range 76 self.focus_range
77 } 77 }
78 78
79 pub(crate) fn from_bind_pat(
80 db: &RootDatabase,
81 file_id: FileId,
82 pat: &ast::BindPat,
83 ) -> NavigationTarget {
84 NavigationTarget::from_named(db, file_id.into(), pat, None, None)
85 }
86
87 pub(crate) fn from_pat(
88 db: &RootDatabase,
89 file_id: FileId,
90 pat: AstPtr<ast::BindPat>,
91 ) -> NavigationTarget {
92 let parse = db.parse(file_id);
93 let pat = pat.to_node(parse.tree().syntax());
94 NavigationTarget::from_bind_pat(db, file_id, &pat)
95 }
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
103 NavigationTarget {
104 file_id,
105 name,
106 full_range,
107 focus_range: None,
108 kind: NAME,
109 container_name: None,
110 description: None, //< No document node for SelfParam
111 docs: None, //< No document node for SelfParam
112 }
113 }
114
115 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 79 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
116 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 80 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
117 if let Some(src) = module.declaration_source(db) { 81 if let Some(src) = module.declaration_source(db) {
@@ -370,6 +334,32 @@ impl ToNav for hir::AssocItem {
370 } 334 }
371} 335}
372 336
337impl ToNav for hir::Local {
338 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
339 let src = self.source(db);
340 let (full_range, focus_range) = match src.ast {
341 Either::A(it) => {
342 (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range()))
343 }
344 Either::B(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())),
345 };
346 let name = match self.name(db) {
347 Some(it) => it.to_string().into(),
348 None => "".into(),
349 };
350 NavigationTarget {
351 file_id: src.file_id.original_file(db),
352 name,
353 kind: BIND_PAT,
354 full_range,
355 focus_range,
356 container_name: None,
357 description: None,
358 docs: None,
359 }
360 }
361}
362
373fn find_range_from_node( 363fn find_range_from_node(
374 db: &RootDatabase, 364 db: &RootDatabase,
375 src: hir::HirFileId, 365 src: hir::HirFileId,
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 713b61d5e..6c8387f6c 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -68,8 +68,7 @@ pub(crate) fn reference_definition(
68 return Exact(adt.to_nav(db)); 68 return Exact(adt.to_nav(db));
69 } 69 }
70 } 70 }
71 Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), 71 Some(Local(local)) => return Exact(local.to_nav(db)),
72 Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)),
73 Some(GenericParam(_)) => { 72 Some(GenericParam(_)) => {
74 // FIXME: go to the generic param def 73 // FIXME: go to the generic param def
75 } 74 }
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index cc41390b2..086e6dec3 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -143,7 +143,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
143 }) 143 })
144 } 144 }
145 } 145 }
146 Some(Pat(_)) | Some(SelfParam(_)) => { 146 Some(Local(_)) => {
147 // Hover for these shows type names 147 // Hover for these shows type names
148 no_fallback = true; 148 no_fallback = true;
149 } 149 }
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 0a76bf484..9cb9433e7 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -86,8 +86,7 @@ pub(crate) fn find_all_refs(
86 Some((adt, _)) => adt.to_nav(db), 86 Some((adt, _)) => adt.to_nav(db),
87 None => return None, 87 None => return None,
88 }, 88 },
89 NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), 89 NameKind::Local(local) => local.to_nav(db),
90 NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par),
91 NameKind::GenericParam(_) => return None, 90 NameKind::GenericParam(_) => return None,
92 }; 91 };
93 92
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs
index 153082d5b..217f9951e 100644
--- a/crates/ra_ide_api/src/references/classify.rs
+++ b/crates/ra_ide_api/src/references/classify.rs
@@ -1,13 +1,13 @@
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::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; 3use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer};
4use ra_db::FileId; 4use ra_db::FileId;
5use ra_prof::profile; 5use ra_prof::profile;
6use ra_syntax::{ast, match_ast, AstNode, AstPtr}; 6use ra_syntax::{ast, match_ast, AstNode};
7use test_utils::tested_by; 7use test_utils::tested_by;
8 8
9use super::{ 9use super::{
10 name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field}, 10 name_definition::{from_assoc_item, from_module_def, from_struct_field},
11 NameDefinition, NameKind, 11 NameDefinition, NameKind,
12}; 12};
13use crate::db::RootDatabase; 13use crate::db::RootDatabase;
@@ -25,7 +25,13 @@ pub(crate) fn classify_name(
25 match_ast! { 25 match_ast! {
26 match parent { 26 match parent {
27 ast::BindPat(it) => { 27 ast::BindPat(it) => {
28 from_pat(db, file_id, AstPtr::new(&it)) 28 let src = hir::Source { file_id, ast: it };
29 let local = hir::Local::from_source(db, src)?;
30 Some(NameDefinition {
31 visibility: None,
32 container: local.module(db),
33 kind: NameKind::Local(local),
34 })
29 }, 35 },
30 ast::RecordFieldDef(it) => { 36 ast::RecordFieldDef(it) => {
31 let ast = hir::FieldSource::Named(it); 37 let ast = hir::FieldSource::Named(it);
@@ -159,10 +165,10 @@ pub(crate) fn classify_name_ref(
159 match resolved { 165 match resolved {
160 Def(def) => Some(from_module_def(db, def, Some(container))), 166 Def(def) => Some(from_module_def(db, def, Some(container))),
161 AssocItem(item) => Some(from_assoc_item(db, item)), 167 AssocItem(item) => Some(from_assoc_item(db, item)),
162 LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), 168 Local(local) => {
163 LocalBinding(Either::B(par)) => { 169 let container = local.module(db);
164 let kind = NameKind::SelfParam(par); 170 let kind = NameKind::Local(local);
165 Some(NameDefinition { kind, container, visibility }) 171 Some(NameDefinition { kind, container, visibility: None })
166 } 172 }
167 GenericParam(par) => { 173 GenericParam(par) => {
168 // FIXME: get generic param def 174 // FIXME: get generic param def
diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs
index 4580bc789..450f7ea9b 100644
--- a/crates/ra_ide_api/src/references/name_definition.rs
+++ b/crates/ra_ide_api/src/references/name_definition.rs
@@ -4,10 +4,9 @@
4//! Note that the reference search is possible for not all of the classified items. 4//! Note that the reference search is possible for not all of the classified items.
5 5
6use hir::{ 6use hir::{
7 db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, 7 Adt, AssocItem, HasSource, Local, MacroDef, Module, ModuleDef, StructField, Ty, VariantDef,
8 Module, ModuleDef, StructField, Ty, VariantDef,
9}; 8};
10use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; 9use ra_syntax::{ast, ast::VisibilityOwner};
11 10
12use crate::db::RootDatabase; 11use crate::db::RootDatabase;
13 12
@@ -18,8 +17,7 @@ pub enum NameKind {
18 AssocItem(AssocItem), 17 AssocItem(AssocItem),
19 Def(ModuleDef), 18 Def(ModuleDef),
20 SelfType(Ty), 19 SelfType(Ty),
21 Pat((DefWithBody, AstPtr<ast::BindPat>)), 20 Local(Local),
22 SelfParam(AstPtr<ast::SelfParam>),
23 GenericParam(u32), 21 GenericParam(u32),
24} 22}
25 23
@@ -30,36 +28,6 @@ pub(crate) struct NameDefinition {
30 pub kind: NameKind, 28 pub kind: NameKind,
31} 29}
32 30
33pub(super) fn from_pat(
34 db: &RootDatabase,
35 file_id: HirFileId,
36 pat: AstPtr<ast::BindPat>,
37) -> Option<NameDefinition> {
38 let root = db.parse_or_expand(file_id)?;
39 let def = pat.to_node(&root).syntax().ancestors().find_map(|node| {
40 match_ast! {
41 match node {
42 ast::FnDef(it) => {
43 let src = hir::Source { file_id, ast: it };
44 Some(hir::Function::from_source(db, src)?.into())
45 },
46 ast::ConstDef(it) => {
47 let src = hir::Source { file_id, ast: it };
48 Some(hir::Const::from_source(db, src)?.into())
49 },
50 ast::StaticDef(it) => {
51 let src = hir::Source { file_id, ast: it };
52 Some(hir::Static::from_source(db, src)?.into())
53 },
54 _ => None,
55 }
56 }
57 })?;
58 let kind = NameKind::Pat((def, pat));
59 let container = def.module(db);
60 Some(NameDefinition { kind, container, visibility: None })
61}
62
63pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { 31pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
64 let container = item.module(db); 32 let container = item.module(db);
65 let visibility = match item { 33 let visibility = match item {
diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs
index f2789e0b2..2907787c2 100644
--- a/crates/ra_ide_api/src/references/search_scope.rs
+++ b/crates/ra_ide_api/src/references/search_scope.rs
@@ -71,13 +71,13 @@ impl NameDefinition {
71 let module_src = self.container.definition_source(db); 71 let module_src = self.container.definition_source(db);
72 let file_id = module_src.file_id.original_file(db); 72 let file_id = module_src.file_id.original_file(db);
73 73
74 if let NameKind::Pat((def, _)) = self.kind { 74 if let NameKind::Local(var) = self.kind {
75 let mut res = FxHashMap::default(); 75 let range = match var.parent(db) {
76 let range = match def {
77 DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), 76 DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(),
78 DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), 77 DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(),
79 DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), 78 DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(),
80 }; 79 };
80 let mut res = FxHashMap::default();
81 res.insert(file_id, Some(range)); 81 res.insert(file_id, Some(range));
82 return SearchScope::new(res); 82 return SearchScope::new(res);
83 } 83 }
diff --git a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html
index ed664817e..79f11ea80 100644
--- a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html
@@ -20,14 +20,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
20.keyword\.control { color: #F0DFAF; font-weight: bold; } 20.keyword\.control { color: #F0DFAF; font-weight: bold; }
21</style> 21</style>
22<pre><code><span class="keyword">fn</span> <span class="function">main</span>() { 22<pre><code><span class="keyword">fn</span> <span class="function">main</span>() {
23 <span class="keyword">let</span> <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>; 23 <span class="keyword">let</span> <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>;
24 <span class="keyword">let</span> <span class="variable" data-binding-hash="5695551762718493399" style="color: hsl(272,48%,45%);">x</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>(); 24 <span class="keyword">let</span> <span class="variable" data-binding-hash="14702933417323009544" style="color: hsl(108,90%,49%);">x</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>();
25 <span class="keyword">let</span> <span class="variable" data-binding-hash="5435401749617022797" style="color: hsl(353,77%,74%);">y</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>(); 25 <span class="keyword">let</span> <span class="variable" data-binding-hash="5443150872754369068" style="color: hsl(215,43%,43%);">y</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>();
26 26
27 <span class="keyword">let</span> <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span> = <span class="string">"other color please!"</span>; 27 <span class="keyword">let</span> <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span> = <span class="string">"other color please!"</span>;
28 <span class="keyword">let</span> <span class="variable" data-binding-hash="14878783531007968800" style="color: hsl(265,73%,83%);">y</span> = <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span>.<span class="text">to_string</span>(); 28 <span class="keyword">let</span> <span class="variable" data-binding-hash="2073121142529774969" style="color: hsl(320,43%,74%);">y</span> = <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span>.<span class="text">to_string</span>();
29} 29}
30 30
31<span class="keyword">fn</span> <span class="function">bar</span>() { 31<span class="keyword">fn</span> <span class="function">bar</span>() {
32 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>; 32 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>;
33}</code></pre> \ No newline at end of file 33}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 1ee68abe2..d53a759ee 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -2,15 +2,10 @@
2 2
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4 4
5use hir::{Mutability, Ty}; 5use hir::{Mutability, Name};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ 8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
9 ast::{self, NameOwner},
10 AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind,
11 SyntaxKind::*,
12 SyntaxNode, TextRange, T,
13};
14 9
15use crate::{ 10use crate::{
16 db::RootDatabase, 11 db::RootDatabase,
@@ -43,32 +38,12 @@ fn is_control_keyword(kind: SyntaxKind) -> bool {
43 } 38 }
44} 39}
45 40
46fn is_variable_mutable(
47 db: &RootDatabase,
48 analyzer: &hir::SourceAnalyzer,
49 pat: ast::BindPat,
50) -> bool {
51 if pat.is_mutable() {
52 return true;
53 }
54
55 let ty = analyzer.type_of_pat(db, &pat.into()).unwrap_or(Ty::Unknown);
56 if let Some((_, mutability)) = ty.as_reference() {
57 match mutability {
58 Mutability::Shared => false,
59 Mutability::Mut => true,
60 }
61 } else {
62 false
63 }
64}
65
66pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { 41pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
67 let _p = profile("highlight"); 42 let _p = profile("highlight");
68 let parse = db.parse(file_id); 43 let parse = db.parse(file_id);
69 let root = parse.tree().syntax().clone(); 44 let root = parse.tree().syntax().clone();
70 45
71 fn calc_binding_hash(file_id: FileId, text: &SmolStr, shadow_count: u32) -> u64 { 46 fn calc_binding_hash(file_id: FileId, name: &Name, shadow_count: u32) -> u64 {
72 fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { 47 fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
73 use std::{collections::hash_map::DefaultHasher, hash::Hasher}; 48 use std::{collections::hash_map::DefaultHasher, hash::Hasher};
74 49
@@ -77,13 +52,13 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
77 hasher.finish() 52 hasher.finish()
78 } 53 }
79 54
80 hash((file_id, text, shadow_count)) 55 hash((file_id, name, shadow_count))
81 } 56 }
82 57
83 // Visited nodes to handle highlighting priorities 58 // Visited nodes to handle highlighting priorities
84 // FIXME: retain only ranges here 59 // FIXME: retain only ranges here
85 let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); 60 let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
86 let mut bindings_shadow_count: FxHashMap<SmolStr, u32> = FxHashMap::default(); 61 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
87 62
88 let mut res = Vec::new(); 63 let mut res = Vec::new();
89 for node in root.descendants_with_tokens() { 64 for node in root.descendants_with_tokens() {
@@ -107,34 +82,29 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
107 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 82 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
108 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); 83 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
109 84
110 if let Some(Pat((_, ptr))) = &name_kind { 85 if let Some(Local(local)) = &name_kind {
111 let pat = ptr.to_node(&root); 86 if let Some(name) = local.name(db) {
112 if let Some(name) = pat.name() { 87 let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
113 let text = name.text(); 88 binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
114 let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
115 binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
116 } 89 }
117 }; 90 };
118 91
119 name_kind 92 name_kind.map_or("text", |it| highlight_name(db, it))
120 .map_or("text", |it| highlight_name(db, file_id, name_ref.syntax(), &root, it))
121 } 93 }
122 NAME => { 94 NAME => {
123 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); 95 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
124 let name_kind = classify_name(db, file_id, &name).map(|d| d.kind); 96 let name_kind = classify_name(db, file_id, &name).map(|d| d.kind);
125 97
126 if let Some(Pat((_, ptr))) = &name_kind { 98 if let Some(Local(local)) = &name_kind {
127 let pat = ptr.to_node(&root); 99 if let Some(name) = local.name(db) {
128 if let Some(name) = pat.name() { 100 let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
129 let text = name.text();
130 let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
131 *shadow_count += 1; 101 *shadow_count += 1;
132 binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) 102 binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
133 } 103 }
134 }; 104 };
135 105
136 match name_kind { 106 match name_kind {
137 Some(name_kind) => highlight_name(db, file_id, name.syntax(), &root, name_kind), 107 Some(name_kind) => highlight_name(db, name_kind),
138 None => name.syntax().parent().map_or("function", |x| match x.kind() { 108 None => name.syntax().parent().map_or("function", |x| match x.kind() {
139 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", 109 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
140 RECORD_FIELD_DEF => "field", 110 RECORD_FIELD_DEF => "field",
@@ -237,13 +207,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
237 buf 207 buf
238} 208}
239 209
240fn highlight_name( 210fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
241 db: &RootDatabase,
242 file_id: FileId,
243 node: &SyntaxNode,
244 root: &SyntaxNode,
245 name_kind: NameKind,
246) -> &'static str {
247 match name_kind { 211 match name_kind {
248 Macro(_) => "macro", 212 Macro(_) => "macro",
249 Field(_) => "field", 213 Field(_) => "field",
@@ -260,14 +224,15 @@ fn highlight_name(
260 Def(hir::ModuleDef::TypeAlias(_)) => "type", 224 Def(hir::ModuleDef::TypeAlias(_)) => "type",
261 Def(hir::ModuleDef::BuiltinType(_)) => "type", 225 Def(hir::ModuleDef::BuiltinType(_)) => "type",
262 SelfType(_) => "type", 226 SelfType(_) => "type",
263 SelfParam(_) => "type",
264 GenericParam(_) => "type", 227 GenericParam(_) => "type",
265 Pat((_, ptr)) => { 228 Local(local) => {
266 let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None); 229 if local.is_mut(db) {
267 if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
268 "variable.mut" 230 "variable.mut"
269 } else { 231 } else {
270 "variable" 232 match local.ty(db).as_reference() {
233 Some((_, Mutability::Mut)) => "variable.mut",
234 _ => "variable",
235 }
271 } 236 }
272 } 237 }
273 } 238 }