aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/syntax_highlighting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs87
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
3use hir::{HirFileId, InFile, Name, SourceAnalyzer, SourceBinder}; 3use hir::{Name, Semantics};
4use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
5use ra_ide_db::{defs::NameDefinition, RootDatabase}; 5use ra_ide_db::{
6 defs::{classify_name, NameDefinition},
7 RootDatabase,
8};
6use ra_prof::profile; 9use ra_prof::profile;
7use ra_syntax::{ 10use 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};
11use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
12 15
13use crate::{ 16use 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
19pub mod tags { 18pub 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
164fn highlight_macro(node: InFile<SyntaxElement>) -> Option<TextRange> { 157fn 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
181fn highlight_token_tree( 174fn 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
203fn highlight_node( 195fn 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