diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-11-11 11:48:02 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-11-11 11:48:02 +0000 |
commit | a599147b4232c0d4f6b071a3a96e86f903f4cf52 (patch) | |
tree | fc8ddd1428c4be2babbdd713c852b31276a315f2 /crates/ra_ide_api/src/syntax_highlighting.rs | |
parent | ef2a9aedb6ac7f0b79e636cff7947935fecb909d (diff) | |
parent | 8b7f853cc19d0940ec542e10bc23aa78455bbb3b (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/ra_ide_api/src/syntax_highlighting.rs')
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 79 |
1 files changed, 22 insertions, 57 deletions
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 | ||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
4 | 4 | ||
5 | use hir::{Mutability, Ty}; | 5 | use hir::{Mutability, Name}; |
6 | use ra_db::SourceDatabase; | 6 | use ra_db::SourceDatabase; |
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use ra_syntax::{ | 8 | use 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 | ||
15 | use crate::{ | 10 | use crate::{ |
16 | db::RootDatabase, | 11 | db::RootDatabase, |
@@ -43,32 +38,12 @@ fn is_control_keyword(kind: SyntaxKind) -> bool { | |||
43 | } | 38 | } |
44 | } | 39 | } |
45 | 40 | ||
46 | fn 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 | |||
66 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { | 41 | pub(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 | ||
240 | fn highlight_name( | 210 | fn 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 | } |