Repository: rust-analyzer/rust-analyzer
Pull request #8831 (2021-05-14 02:36:34)

Apply async semantic token modifier to async/await keywords
close https://github.com/rust-analyzer/rust-analyzer/issues/8633


Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c9ef4b4205..6233bca83a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -873,6 +873,10 @@ impl Function {
         db.function_data(self.id).is_unsafe()
     }
 
+    pub fn is_async(self, db: &dyn HirDatabase) -> bool {
+        db.function_data(self.id).is_async()
+    }
+
     pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
         let krate = self.module(db).id.krate();
         hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink);
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index b586dcc179..baed8e2170 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -227,8 +227,8 @@ pub(super) fn element(
         k if k.is_keyword() => {
             let h = Highlight::new(HlTag::Keyword);
             match k {
-                T![await]
-                | T![break]
+                T![await] => h | HlMod::Async | HlMod::ControlFlow,
+                T![break]
                 | T![continue]
                 | T![else]
                 | T![if]
@@ -255,6 +255,7 @@ pub(super) fn element(
                     })
                     .map(|modifier| h | modifier)
                     .unwrap_or(h),
+                T![async] => h | HlMod::Async,
                 _ => h,
             }
         }
@@ -310,6 +311,9 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
                 if func.is_unsafe(db) {
                     h |= HlMod::Unsafe;
                 }
+                if func.is_async(db) {
+                    h |= HlMod::Async;
+                }
                 return h;
             }
             hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct),
@@ -409,6 +413,9 @@ fn highlight_method_call(
     if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
         h |= HlMod::Unsafe;
     }
+    if func.is_async(sema.db) {
+        h |= HlMod::Async;
+    }
     if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() {
         h |= HlMod::Trait
     }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index a304b32506..f4a2e7506a 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -65,6 +65,8 @@ pub enum HlMod {
     Static,
     /// Used for items in traits and trait impls.
     Trait,
+    /// Used with keywords like `async` and `await`.
+    Async,
     // Keep this last!
     /// Used for unsafe functions, mutable statics, union accesses and unsafe operations.
     Unsafe,
@@ -186,6 +188,7 @@ impl HlMod {
         HlMod::Mutable,
         HlMod::Static,
         HlMod::Trait,
+        HlMod::Async,
         HlMod::Unsafe,
     ];
 
@@ -203,6 +206,7 @@ impl HlMod {
             HlMod::Mutable => "mutable",
             HlMod::Static => "static",
             HlMod::Trait => "trait",
+            HlMod::Async => "async",
             HlMod::Unsafe => "unsafe",
         }
     }
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index ecab89b2a8..c9d38693e8 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -91,6 +91,7 @@ define_semantic_token_modifiers![
     (INJECTED, "injected"),
     (MUTABLE, "mutable"),
     (CONSUMING, "consuming"),
+    (ASYNC, "async"),
     (UNSAFE, "unsafe"),
     (ATTRIBUTE_MODIFIER, "attribute"),
     (TRAIT_MODIFIER, "trait"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index ecf6fd12fe..8ce4aa2423 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -496,6 +496,7 @@ fn semantic_token_type_and_modifiers(
             HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW,
             HlMod::Mutable => semantic_tokens::MUTABLE,
             HlMod::Consuming => semantic_tokens::CONSUMING,
+            HlMod::Async => semantic_tokens::ASYNC,
             HlMod::Unsafe => semantic_tokens::UNSAFE,
             HlMod::Callable => semantic_tokens::CALLABLE,
             HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,


Test patch:
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index df41921949..33bc6b0f3b 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -234,4 +234,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
             <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span>
         <span class="brace">}</span>
     <span class="brace">}</span>
+<span class="brace">}</span>
+
+<span class="keyword async">async</span> <span class="keyword">fn</span> <span class="function declaration async">learn_and_sing</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword">let</span> <span class="variable declaration">song</span> <span class="operator">=</span> <span class="unresolved_reference">learn_song</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="operator">.</span><span class="keyword control async">await</span><span class="semicolon">;</span>
+    <span class="unresolved_reference">sing_song</span><span class="parenthesis">(</span><span class="variable consuming">song</span><span class="parenthesis">)</span><span class="operator">.</span><span class="keyword control async">await</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+
+<span class="keyword async">async</span> <span class="keyword">fn</span> <span class="function declaration async">async_main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword">let</span> <span class="variable declaration">f1</span> <span class="operator">=</span> <span class="function async">learn_and_sing</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">f2</span> <span class="operator">=</span> <span class="unresolved_reference">dance</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    futures::<span class="macro">join!</span><span class="parenthesis">(</span>f1<span class="comma">,</span> f2<span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index b6e952b088..32f2d9038e 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -208,6 +208,17 @@ impl<T> Option<T> {
         }
     }
 }
+
+async fn learn_and_sing() {
+    let song = learn_song().await;
+    sing_song(song).await;
+}
+
+async fn async_main() {
+    let f1 = learn_and_sing();
+    let f2 = dance();
+    futures::join!(f1, f2);
+}
 "#
         .trim(),
         expect_file!["./test_data/highlighting.html"],