Skip to content

Commit fc350ea

Browse files
bors[bot]Veykril
andauthored
Merge #11631
11631: internal: Refactor syntax_highlighting r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 96c11f5 + 97076c0 commit fc350ea

File tree

7 files changed

+184
-167
lines changed

7 files changed

+184
-167
lines changed

crates/ide/src/syntax_highlighting.rs

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -241,19 +241,26 @@ fn traverse(
241241
current_macro = Some(mac.into());
242242
continue;
243243
}
244-
Some(item) if sema.is_attr_macro_call(&item) => current_attr_call = Some(item),
245-
Some(item) if current_attr_call.is_none() => {
246-
let adt = match item {
247-
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
248-
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
249-
ast::Item::Union(it) => Some(ast::Adt::Union(it)),
250-
_ => None,
251-
};
252-
match adt {
253-
Some(adt) if sema.is_derive_annotated(&adt) => {
254-
current_derive_call = Some(ast::Item::from(adt));
244+
Some(item) => {
245+
if matches!(node.kind(), FN | CONST | STATIC) {
246+
bindings_shadow_count.clear();
247+
}
248+
249+
if sema.is_attr_macro_call(&item) {
250+
current_attr_call = Some(item);
251+
} else if current_attr_call.is_none() {
252+
let adt = match item {
253+
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
254+
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
255+
ast::Item::Union(it) => Some(ast::Adt::Union(it)),
256+
_ => None,
257+
};
258+
match adt {
259+
Some(adt) if sema.is_derive_annotated(&adt) => {
260+
current_derive_call = Some(ast::Item::from(adt));
261+
}
262+
_ => (),
255263
}
256-
_ => (),
257264
}
258265
}
259266
None if ast::Attr::can_cast(node.kind()) => inside_attribute = true,
@@ -291,6 +298,8 @@ fn traverse(
291298
WalkEvent::Enter(it) => it,
292299
WalkEvent::Leave(NodeOrToken::Token(_)) => continue,
293300
WalkEvent::Leave(NodeOrToken::Node(node)) => {
301+
// Doc comment highlighting injection, we do this when leaving the node
302+
// so that we overwrite the highlighting of the doc comment itself.
294303
inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
295304
continue;
296305
}
@@ -302,57 +311,68 @@ fn traverse(
302311
}
303312
}
304313

305-
// only attempt to descend if we are inside a macro call or attribute
306-
// as calling `descend_into_macros_single` gets rather expensive if done for every single token
307-
// additionally, do not descend into comments, descending maps down to doc attributes which get
308-
// tagged as string literals.
309-
let descend_token = (current_macro_call.is_some()
310-
|| current_attr_call.is_some()
311-
|| current_derive_call.is_some())
312-
&& element.kind() != COMMENT;
313-
let element_to_highlight = if descend_token {
314-
let token = match &element {
315-
NodeOrToken::Node(_) => continue,
316-
NodeOrToken::Token(tok) => tok.clone(),
317-
};
318-
let in_mcall_outside_tt = current_attr_call.is_none()
319-
&& token.parent().as_ref().map(SyntaxNode::kind) != Some(TOKEN_TREE);
320-
let token = match in_mcall_outside_tt {
321-
// not in the macros/derives token tree, don't attempt to descend
322-
true => token,
323-
false => sema.descend_into_macros_single(token),
324-
};
325-
match token.parent() {
326-
Some(parent) => {
327-
// Names and NameRefs have special semantics, use them instead of the tokens
328-
// as otherwise we won't ever visit them
329-
match (token.kind(), parent.kind()) {
330-
(T![ident], NAME | NAME_REF) => parent.into(),
331-
(T![self] | T![super] | T![crate] | T![Self], NAME_REF) => parent.into(),
332-
(INT_NUMBER, NAME_REF) => parent.into(),
333-
(LIFETIME_IDENT, LIFETIME) => parent.into(),
334-
_ => token.into(),
314+
let element = match element.clone() {
315+
NodeOrToken::Node(n) => match ast::NameLike::cast(n) {
316+
Some(n) => NodeOrToken::Node(n),
317+
None => continue,
318+
},
319+
NodeOrToken::Token(t) => NodeOrToken::Token(t),
320+
};
321+
let token = element.as_token().cloned();
322+
323+
// Descending tokens into macros is expensive even if no descending occurs, so make sure
324+
// that we actually are in a position where descending is possible.
325+
let in_macro = current_macro_call.is_some()
326+
|| current_derive_call.is_some()
327+
|| current_attr_call.is_some();
328+
let descended_element = if in_macro {
329+
// Attempt to descend tokens into macro-calls.
330+
match element {
331+
NodeOrToken::Token(token) if token.kind() != COMMENT => {
332+
// For function-like macro calls and derive attributes, only attempt to descend if
333+
// we are inside their token-trees.
334+
let in_tt = current_attr_call.is_some()
335+
|| token.parent().as_ref().map(SyntaxNode::kind) == Some(TOKEN_TREE);
336+
337+
if in_tt {
338+
let token = sema.descend_into_macros_single(token);
339+
match token.parent().and_then(ast::NameLike::cast) {
340+
// Remap the token into the wrapping single token nodes
341+
// FIXME: if the node doesn't resolve, we also won't do token based highlighting!
342+
Some(parent) => match (token.kind(), parent.syntax().kind()) {
343+
(T![self] | T![ident], NAME | NAME_REF) => {
344+
NodeOrToken::Node(parent)
345+
}
346+
(T![self] | T![super] | T![crate] | T![Self], NAME_REF) => {
347+
NodeOrToken::Node(parent)
348+
}
349+
(INT_NUMBER, NAME_REF) => NodeOrToken::Node(parent),
350+
(LIFETIME_IDENT, LIFETIME) => NodeOrToken::Node(parent),
351+
_ => NodeOrToken::Token(token),
352+
},
353+
None => NodeOrToken::Token(token),
354+
}
355+
} else {
356+
NodeOrToken::Token(token)
335357
}
336358
}
337-
None => token.into(),
359+
e => e,
338360
}
339361
} else {
340-
element.clone()
362+
element
341363
};
342364

343365
// FIXME: do proper macro def highlighting https://github.com/rust-analyzer/rust-analyzer/issues/6232
344366
// Skip metavariables from being highlighted to prevent keyword highlighting in them
345-
if macro_highlighter.highlight(&element_to_highlight).is_some() {
367+
if descended_element.as_token().and_then(|t| macro_highlighter.highlight(t)).is_some() {
346368
continue;
347369
}
348370

349371
// string highlight injections, note this does not use the descended element as proc-macros
350372
// can rewrite string literals which invalidates our indices
351-
if let (Some(token), Some(token_to_highlight)) =
352-
(element.into_token(), element_to_highlight.as_token())
353-
{
373+
if let (Some(token), Some(descended_token)) = (token, descended_element.as_token()) {
354374
let string = ast::String::cast(token);
355-
let string_to_highlight = ast::String::cast(token_to_highlight.clone());
375+
let string_to_highlight = ast::String::cast(descended_token.clone());
356376
if let Some((string, expanded_string)) = string.zip(string_to_highlight) {
357377
if string.is_raw() {
358378
if inject::ra_fixture(hl, sema, &string, &expanded_string).is_some() {
@@ -377,14 +397,13 @@ fn traverse(
377397
}
378398
}
379399

380-
// do the normal highlighting
381-
let element = match element_to_highlight {
382-
NodeOrToken::Node(node) => highlight::node(
400+
let element = match descended_element {
401+
NodeOrToken::Node(name_like) => highlight::name_like(
383402
sema,
384403
krate,
385404
&mut bindings_shadow_count,
386405
syntactic_name_ref_highlighting,
387-
node,
406+
name_like,
388407
),
389408
NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)),
390409
};

crates/ide/src/syntax_highlighting/highlight.rs

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use hir::{AsAssocItem, HasVisibility, Semantics};
44
use ide_db::{
5-
defs::{Definition, NameClass, NameRefClass},
5+
defs::{Definition, IdentClass, NameClass, NameRefClass},
66
helpers::FamousDefs,
77
RootDatabase, SymbolKind,
88
};
@@ -47,52 +47,36 @@ pub(super) fn token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Optio
4747
Some(highlight)
4848
}
4949

50-
pub(super) fn node(
50+
pub(super) fn name_like(
5151
sema: &Semantics<RootDatabase>,
5252
krate: Option<hir::Crate>,
5353
bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
5454
syntactic_name_ref_highlighting: bool,
55-
node: SyntaxNode,
55+
name_like: ast::NameLike,
5656
) -> Option<(Highlight, Option<u64>)> {
5757
let mut binding_hash = None;
58-
let highlight = match_ast! {
59-
match node {
60-
ast::NameRef(name_ref) => {
61-
highlight_name_ref(
62-
sema,
63-
krate,
64-
bindings_shadow_count,
65-
&mut binding_hash,
66-
syntactic_name_ref_highlighting,
67-
name_ref,
68-
)
69-
},
70-
ast::Name(name) => {
71-
highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name)
72-
},
73-
ast::Lifetime(lifetime) => {
74-
match NameClass::classify_lifetime(sema, &lifetime) {
75-
Some(NameClass::Definition(def)) => {
76-
highlight_def(sema, krate, def) | HlMod::Definition
77-
}
78-
None => match NameRefClass::classify_lifetime(sema, &lifetime) {
79-
Some(NameRefClass::Definition(def)) => highlight_def(sema, krate, def),
80-
_ => SymbolKind::LifetimeParam.into(),
81-
},
82-
_ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition,
83-
}
84-
},
85-
ast::Fn(_) => {
86-
bindings_shadow_count.clear();
87-
return None;
88-
},
89-
_ => {
90-
if [FN, CONST, STATIC].contains(&node.kind()) {
91-
bindings_shadow_count.clear();
92-
}
93-
return None
94-
},
58+
let highlight = match name_like {
59+
ast::NameLike::NameRef(name_ref) => highlight_name_ref(
60+
sema,
61+
krate,
62+
bindings_shadow_count,
63+
&mut binding_hash,
64+
syntactic_name_ref_highlighting,
65+
name_ref,
66+
),
67+
ast::NameLike::Name(name) => {
68+
highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name)
9569
}
70+
ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) {
71+
Some(IdentClass::NameClass(NameClass::Definition(def))) => {
72+
highlight_def(sema, krate, def) | HlMod::Definition
73+
}
74+
Some(IdentClass::NameRefClass(NameRefClass::Definition(def))) => {
75+
highlight_def(sema, krate, def)
76+
}
77+
// FIXME: Fallback for 'static and '_, as we do not resolve these yet
78+
_ => SymbolKind::LifetimeParam.into(),
79+
},
9680
};
9781
Some((highlight, binding_hash))
9882
}

0 commit comments

Comments
 (0)