diff options
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 87 |
1 files changed, 39 insertions, 48 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 9bc3ad448..987476d2c 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -1,8 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{HirFileId, InFile, Name, SourceAnalyzer, SourceBinder}; | 3 | use hir::{Name, Semantics}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_ide_db::{defs::NameDefinition, RootDatabase}; | 5 | use ra_ide_db::{ |
6 | defs::{classify_name, NameDefinition}, | ||
7 | RootDatabase, | ||
8 | }; | ||
6 | use ra_prof::profile; | 9 | use ra_prof::profile; |
7 | use ra_syntax::{ | 10 | use ra_syntax::{ |
8 | ast, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxKind::*, SyntaxToken, | 11 | ast, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxKind::*, SyntaxToken, |
@@ -10,11 +13,7 @@ use ra_syntax::{ | |||
10 | }; | 13 | }; |
11 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{references::classify_name_ref, FileId}; |
14 | expand::descend_into_macros_with_analyzer, | ||
15 | references::{classify_name, classify_name_ref}, | ||
16 | FileId, | ||
17 | }; | ||
18 | 17 | ||
19 | pub mod tags { | 18 | pub mod tags { |
20 | pub const FIELD: &str = "field"; | 19 | pub const FIELD: &str = "field"; |
@@ -73,14 +72,11 @@ pub(crate) fn highlight( | |||
73 | range: Option<TextRange>, | 72 | range: Option<TextRange>, |
74 | ) -> Vec<HighlightedRange> { | 73 | ) -> Vec<HighlightedRange> { |
75 | let _p = profile("highlight"); | 74 | let _p = profile("highlight"); |
75 | let sema = Semantics::new(db); | ||
76 | let root = sema.parse(file_id).syntax().clone(); | ||
76 | 77 | ||
77 | let parse = db.parse(file_id); | ||
78 | let root = parse.tree().syntax().clone(); | ||
79 | |||
80 | let mut sb = SourceBinder::new(db); | ||
81 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); | 78 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
82 | let mut res = Vec::new(); | 79 | let mut res = Vec::new(); |
83 | let analyzer = sb.analyze(InFile::new(file_id.into(), &root), None); | ||
84 | 80 | ||
85 | let mut in_macro_call = None; | 81 | let mut in_macro_call = None; |
86 | 82 | ||
@@ -105,7 +101,7 @@ pub(crate) fn highlight( | |||
105 | match node.kind() { | 101 | match node.kind() { |
106 | MACRO_CALL => { | 102 | MACRO_CALL => { |
107 | in_macro_call = Some(node.clone()); | 103 | in_macro_call = Some(node.clone()); |
108 | if let Some(range) = highlight_macro(InFile::new(file_id.into(), node)) { | 104 | if let Some(range) = highlight_macro(node) { |
109 | res.push(HighlightedRange { | 105 | res.push(HighlightedRange { |
110 | range, | 106 | range, |
111 | tag: tags::MACRO, | 107 | tag: tags::MACRO, |
@@ -116,10 +112,9 @@ pub(crate) fn highlight( | |||
116 | _ if in_macro_call.is_some() => { | 112 | _ if in_macro_call.is_some() => { |
117 | if let Some(token) = node.as_token() { | 113 | if let Some(token) = node.as_token() { |
118 | if let Some((tag, binding_hash)) = highlight_token_tree( | 114 | if let Some((tag, binding_hash)) = highlight_token_tree( |
119 | &mut sb, | 115 | &sema, |
120 | &analyzer, | ||
121 | &mut bindings_shadow_count, | 116 | &mut bindings_shadow_count, |
122 | InFile::new(file_id.into(), token.clone()), | 117 | token.clone(), |
123 | ) { | 118 | ) { |
124 | res.push(HighlightedRange { | 119 | res.push(HighlightedRange { |
125 | range: node.text_range(), | 120 | range: node.text_range(), |
@@ -130,11 +125,9 @@ pub(crate) fn highlight( | |||
130 | } | 125 | } |
131 | } | 126 | } |
132 | _ => { | 127 | _ => { |
133 | if let Some((tag, binding_hash)) = highlight_node( | 128 | if let Some((tag, binding_hash)) = |
134 | &mut sb, | 129 | highlight_node(&sema, &mut bindings_shadow_count, node.clone()) |
135 | &mut bindings_shadow_count, | 130 | { |
136 | InFile::new(file_id.into(), node.clone()), | ||
137 | ) { | ||
138 | res.push(HighlightedRange { | 131 | res.push(HighlightedRange { |
139 | range: node.text_range(), | 132 | range: node.text_range(), |
140 | tag, | 133 | tag, |
@@ -161,8 +154,8 @@ pub(crate) fn highlight( | |||
161 | res | 154 | res |
162 | } | 155 | } |
163 | 156 | ||
164 | fn highlight_macro(node: InFile<SyntaxElement>) -> Option<TextRange> { | 157 | fn highlight_macro(node: SyntaxElement) -> Option<TextRange> { |
165 | let macro_call = ast::MacroCall::cast(node.value.as_node()?.clone())?; | 158 | let macro_call = ast::MacroCall::cast(node.as_node()?.clone())?; |
166 | let path = macro_call.path()?; | 159 | let path = macro_call.path()?; |
167 | let name_ref = path.segment()?.name_ref()?; | 160 | let name_ref = path.segment()?.name_ref()?; |
168 | 161 | ||
@@ -179,35 +172,34 @@ fn highlight_macro(node: InFile<SyntaxElement>) -> Option<TextRange> { | |||
179 | } | 172 | } |
180 | 173 | ||
181 | fn highlight_token_tree( | 174 | fn highlight_token_tree( |
182 | sb: &mut SourceBinder<RootDatabase>, | 175 | sema: &Semantics<RootDatabase>, |
183 | analyzer: &SourceAnalyzer, | ||
184 | bindings_shadow_count: &mut FxHashMap<Name, u32>, | 176 | bindings_shadow_count: &mut FxHashMap<Name, u32>, |
185 | token: InFile<SyntaxToken>, | 177 | token: SyntaxToken, |
186 | ) -> Option<(&'static str, Option<u64>)> { | 178 | ) -> Option<(&'static str, Option<u64>)> { |
187 | if token.value.parent().kind() != TOKEN_TREE { | 179 | if token.parent().kind() != TOKEN_TREE { |
188 | return None; | 180 | return None; |
189 | } | 181 | } |
190 | let token = descend_into_macros_with_analyzer(sb.db, analyzer, token); | 182 | let token = sema.descend_into_macros(token.clone()); |
191 | let expanded = { | 183 | let expanded = { |
192 | let parent = token.value.parent(); | 184 | let parent = token.parent(); |
193 | // We only care Name and Name_ref | 185 | // We only care Name and Name_ref |
194 | match (token.value.kind(), parent.kind()) { | 186 | match (token.kind(), parent.kind()) { |
195 | (IDENT, NAME) | (IDENT, NAME_REF) => token.with_value(parent.into()), | 187 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), |
196 | _ => token.map(|it| it.into()), | 188 | _ => token.into(), |
197 | } | 189 | } |
198 | }; | 190 | }; |
199 | 191 | ||
200 | highlight_node(sb, bindings_shadow_count, expanded) | 192 | highlight_node(sema, bindings_shadow_count, expanded) |
201 | } | 193 | } |
202 | 194 | ||
203 | fn highlight_node( | 195 | fn highlight_node( |
204 | sb: &mut SourceBinder<RootDatabase>, | 196 | sema: &Semantics<RootDatabase>, |
205 | bindings_shadow_count: &mut FxHashMap<Name, u32>, | 197 | bindings_shadow_count: &mut FxHashMap<Name, u32>, |
206 | node: InFile<SyntaxElement>, | 198 | node: SyntaxElement, |
207 | ) -> Option<(&'static str, Option<u64>)> { | 199 | ) -> Option<(&'static str, Option<u64>)> { |
208 | let db = sb.db; | 200 | let db = sema.db; |
209 | let mut binding_hash = None; | 201 | let mut binding_hash = None; |
210 | let tag = match node.value.kind() { | 202 | let tag = match node.kind() { |
211 | FN_DEF => { | 203 | FN_DEF => { |
212 | bindings_shadow_count.clear(); | 204 | bindings_shadow_count.clear(); |
213 | return None; | 205 | return None; |
@@ -216,19 +208,18 @@ fn highlight_node( | |||
216 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING, | 208 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING, |
217 | ATTR => tags::LITERAL_ATTRIBUTE, | 209 | ATTR => tags::LITERAL_ATTRIBUTE, |
218 | // Special-case field init shorthand | 210 | // Special-case field init shorthand |
219 | NAME_REF if node.value.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD, | 211 | NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD, |
220 | NAME_REF if node.value.ancestors().any(|it| it.kind() == ATTR) => return None, | 212 | NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => return None, |
221 | NAME_REF => { | 213 | NAME_REF => { |
222 | let name_ref = node.value.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); | 214 | let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); |
223 | let name_kind = classify_name_ref(sb, node.with_value(&name_ref)); | 215 | let name_kind = classify_name_ref(sema, &name_ref); |
224 | match name_kind { | 216 | match name_kind { |
225 | Some(name_kind) => { | 217 | Some(name_kind) => { |
226 | if let NameDefinition::Local(local) = &name_kind { | 218 | if let NameDefinition::Local(local) = &name_kind { |
227 | if let Some(name) = local.name(db) { | 219 | if let Some(name) = local.name(db) { |
228 | let shadow_count = | 220 | let shadow_count = |
229 | bindings_shadow_count.entry(name.clone()).or_default(); | 221 | bindings_shadow_count.entry(name.clone()).or_default(); |
230 | binding_hash = | 222 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) |
231 | Some(calc_binding_hash(node.file_id, &name, *shadow_count)) | ||
232 | } | 223 | } |
233 | }; | 224 | }; |
234 | 225 | ||
@@ -238,14 +229,14 @@ fn highlight_node( | |||
238 | } | 229 | } |
239 | } | 230 | } |
240 | NAME => { | 231 | NAME => { |
241 | let name = node.value.as_node().cloned().and_then(ast::Name::cast).unwrap(); | 232 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); |
242 | let name_kind = classify_name(sb, node.with_value(&name)); | 233 | let name_kind = classify_name(sema, &name); |
243 | 234 | ||
244 | if let Some(NameDefinition::Local(local)) = &name_kind { | 235 | if let Some(NameDefinition::Local(local)) = &name_kind { |
245 | if let Some(name) = local.name(db) { | 236 | if let Some(name) = local.name(db) { |
246 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | 237 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); |
247 | *shadow_count += 1; | 238 | *shadow_count += 1; |
248 | binding_hash = Some(calc_binding_hash(node.file_id, &name, *shadow_count)) | 239 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) |
249 | } | 240 | } |
250 | }; | 241 | }; |
251 | 242 | ||
@@ -272,7 +263,7 @@ fn highlight_node( | |||
272 | 263 | ||
273 | return Some((tag, binding_hash)); | 264 | return Some((tag, binding_hash)); |
274 | 265 | ||
275 | fn calc_binding_hash(file_id: HirFileId, name: &Name, shadow_count: u32) -> u64 { | 266 | fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 { |
276 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | 267 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { |
277 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | 268 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; |
278 | 269 | ||
@@ -281,7 +272,7 @@ fn highlight_node( | |||
281 | hasher.finish() | 272 | hasher.finish() |
282 | } | 273 | } |
283 | 274 | ||
284 | hash((file_id, name, shadow_count)) | 275 | hash((name, shadow_count)) |
285 | } | 276 | } |
286 | } | 277 | } |
287 | 278 | ||