Skip to content

Commit 7e30ca1

Browse files
committed
Auto merge of rust-lang#12844 - Veykril:highlight-attr, r=Veykril
fix: Improve syntax highlighting in attributes Fixes rust-lang/rust-analyzer#12842
2 parents cb8a3be + 1ab862a commit 7e30ca1

File tree

2 files changed

+64
-7
lines changed

2 files changed

+64
-7
lines changed

crates/hir/src/semantics.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use smallvec::{smallvec, SmallVec};
2222
use syntax::{
2323
algo::skip_trivia_token,
2424
ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody},
25-
match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
25+
match_ast, AstNode, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
2626
};
2727

2828
use crate::{
@@ -217,6 +217,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
217217
self.imp.descend_into_macros_with_same_text(token)
218218
}
219219

220+
pub fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken {
221+
self.imp.descend_into_macros_with_kind_preference(token)
222+
}
223+
220224
/// Maps a node down by mapping its first and last token down.
221225
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
222226
self.imp.descend_node_into_attributes(node)
@@ -680,6 +684,32 @@ impl<'db> SemanticsImpl<'db> {
680684
res
681685
}
682686

687+
fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken {
688+
let fetch_kind = |token: &SyntaxToken| match token.parent() {
689+
Some(node) => match node.kind() {
690+
kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => {
691+
node.parent().map_or(kind, |it| it.kind())
692+
}
693+
_ => token.kind(),
694+
},
695+
None => token.kind(),
696+
};
697+
let preferred_kind = fetch_kind(&token);
698+
let mut res = None;
699+
self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
700+
if fetch_kind(&value) == preferred_kind {
701+
res = Some(value);
702+
true
703+
} else {
704+
if let None = res {
705+
res = Some(value)
706+
}
707+
false
708+
}
709+
});
710+
res.unwrap_or(token)
711+
}
712+
683713
fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
684714
let mut res = token.clone();
685715
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {

crates/ide/src/syntax_highlighting.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,19 @@ fn traverse(
206206
let is_unlinked = sema.to_module_def(file_id).is_none();
207207
let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
208208

209+
enum AttrOrDerive {
210+
Attr(ast::Item),
211+
Derive(ast::Item),
212+
}
213+
214+
impl AttrOrDerive {
215+
fn item(&self) -> &ast::Item {
216+
match self {
217+
AttrOrDerive::Attr(item) | AttrOrDerive::Derive(item) => item,
218+
}
219+
}
220+
}
221+
209222
let mut tt_level = 0;
210223
let mut attr_or_derive_item = None;
211224
let mut current_macro: Option<ast::Macro> = None;
@@ -260,7 +273,7 @@ fn traverse(
260273

261274
if attr_or_derive_item.is_none() {
262275
if sema.is_attr_macro_call(&item) {
263-
attr_or_derive_item = Some(item);
276+
attr_or_derive_item = Some(AttrOrDerive::Attr(item));
264277
} else {
265278
let adt = match item {
266279
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
@@ -270,7 +283,8 @@ fn traverse(
270283
};
271284
match adt {
272285
Some(adt) if sema.is_derive_annotated(&adt) => {
273-
attr_or_derive_item = Some(ast::Item::from(adt));
286+
attr_or_derive_item =
287+
Some(AttrOrDerive::Derive(ast::Item::from(adt)));
274288
}
275289
_ => (),
276290
}
@@ -292,7 +306,9 @@ fn traverse(
292306
current_macro = None;
293307
macro_highlighter = MacroHighlighter::default();
294308
}
295-
Some(item) if attr_or_derive_item.as_ref().map_or(false, |it| *it == item) => {
309+
Some(item)
310+
if attr_or_derive_item.as_ref().map_or(false, |it| *it.item() == item) =>
311+
{
296312
attr_or_derive_item = None;
297313
}
298314
_ => (),
@@ -330,15 +346,26 @@ fn traverse(
330346

331347
// Descending tokens into macros is expensive even if no descending occurs, so make sure
332348
// that we actually are in a position where descending is possible.
333-
let in_macro = tt_level > 0 || attr_or_derive_item.is_some();
349+
let in_macro = tt_level > 0
350+
|| match attr_or_derive_item {
351+
Some(AttrOrDerive::Attr(_)) => true,
352+
Some(AttrOrDerive::Derive(_)) => inside_attribute,
353+
None => false,
354+
};
334355
let descended_element = if in_macro {
335356
// Attempt to descend tokens into macro-calls.
336357
match element {
337358
NodeOrToken::Token(token) if token.kind() != COMMENT => {
338-
let token = sema.descend_into_macros_single(token);
359+
let token = match attr_or_derive_item {
360+
Some(AttrOrDerive::Attr(_)) => {
361+
sema.descend_into_macros_with_kind_preference(token)
362+
}
363+
Some(AttrOrDerive::Derive(_)) | None => {
364+
sema.descend_into_macros_single(token)
365+
}
366+
};
339367
match token.parent().and_then(ast::NameLike::cast) {
340368
// 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!
342369
Some(parent) => match (token.kind(), parent.syntax().kind()) {
343370
(T![self] | T![ident], NAME | NAME_REF) => NodeOrToken::Node(parent),
344371
(T![self] | T![super] | T![crate] | T![Self], NAME_REF) => {

0 commit comments

Comments
 (0)