aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/syntax_highlighting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/syntax_highlighting.rs')
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs79
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
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 }