Fix LSP semantic coloration bailing out sometimes

Step to reproduce:

```
xx := Window {
   TouchArea {
      clicked => {
         if (true) {}
         // note: because there is no else, the semantic colouring is bailing out now
      }
   }
   TouchArea { clicked => {} }
}
```

This is caused by a bug in rowan::SyntaxToken::next_token that doesn't visit
the next token if it has an empty node

Unfortunately, the LSP has no tests, so I couldn't add one easily
This commit is contained in:
Olivier Goffart 2022-02-04 13:21:26 +01:00
parent 458c88cfa4
commit c5ef368a3f
2 changed files with 36 additions and 6 deletions

View file

@ -693,6 +693,31 @@ impl SyntaxToken {
pub fn parent(&self) -> SyntaxNode {
SyntaxNode { node: self.token.parent().unwrap(), source_file: self.source_file.clone() }
}
pub fn next_token(&self) -> Option<SyntaxToken> {
// Due to a bug (as of rowan 0.15.3), rowan::SyntaxToken::next_token doesn't work if a
// sibling don't have tokens.
// For example, if we have an expression like `if (true) {}` the
// ConditionalExpression has an empty Expression/CodeBlock for the else part,
// and next_token doesn't go into that.
// So re-implement
let token = self
.token
.next_sibling_or_token()
.and_then(|e| match e {
rowan::NodeOrToken::Node(n) => n.first_token(),
rowan::NodeOrToken::Token(t) => Some(t),
})
.or_else(|| {
self.token.ancestors().find_map(|it| it.next_sibling_or_token()).and_then(|e| {
match e {
rowan::NodeOrToken::Node(n) => n.first_token(),
rowan::NodeOrToken::Token(t) => Some(t),
}
})
})?;
Some(SyntaxToken { token, source_file: self.source_file.clone() })
}
}
impl std::fmt::Display for SyntaxToken {
@ -745,6 +770,11 @@ impl SyntaxNode {
pub fn parent(&self) -> Option<SyntaxNode> {
self.node.parent().map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
}
pub fn first_token(&self) -> Option<SyntaxToken> {
self.node
.first_token()
.map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
}
}
#[derive(Debug, Clone, derive_more::From)]