aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/remove_dbg.rs12
-rw-r--r--crates/completion/src/completions/attribute.rs21
-rw-r--r--crates/completion/src/completions/trait_impl.rs6
-rw-r--r--crates/completion/src/patterns.rs10
-rw-r--r--crates/hir/src/code_model.rs18
-rw-r--r--crates/ide/src/display/navigation_target.rs14
-rw-r--r--crates/ide/src/doc_links.rs30
-rw-r--r--crates/ide/src/goto_definition.rs88
-rw-r--r--crates/ide/src/hover.rs20
-rw-r--r--crates/ide/src/inlay_hints.rs26
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/references.rs14
-rw-r--r--crates/ide/src/runnables.rs75
-rw-r--r--crates/ide/src/syntax_highlighting.rs598
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs82
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs530
-rw-r--r--crates/ide/src/syntax_highlighting/highlights.rs12
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs (renamed from crates/ide/src/syntax_highlighting/injection.rs)132
-rw-r--r--crates/ide/src/syntax_highlighting/injector.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/macro_rules.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs36
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html28
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html52
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html4
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html20
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html106
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html88
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html260
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/injection.html16
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html20
-rw-r--r--crates/ide_db/src/defs.rs36
-rw-r--r--crates/ide_db/src/search.rs2
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs12
-rw-r--r--crates/parser/src/grammar/items.rs26
-rw-r--r--crates/parser/src/grammar/items/traits.rs2
-rw-r--r--crates/parser/src/grammar/patterns.rs2
-rw-r--r--crates/parser/src/grammar/type_args.rs6
-rw-r--r--crates/parser/src/grammar/type_params.rs4
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs3
-rw-r--r--crates/rust-analyzer/src/lib.rs1
-rw-r--r--crates/rust-analyzer/src/main_loop.rs16
-rw-r--r--crates/rust-analyzer/src/op_queue.rs25
-rw-r--r--crates/rust-analyzer/src/reload.rs24
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs8
-rw-r--r--crates/rust-analyzer/src/to_proto.rs18
-rw-r--r--crates/stdx/src/lib.rs4
-rw-r--r--crates/syntax/src/ast/node_ext.rs2
-rw-r--r--crates/syntax/src/validation.rs4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast28
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs2
51 files changed, 1401 insertions, 1151 deletions
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs
index 0320c2f12..6114091f2 100644
--- a/crates/assists/src/handlers/remove_dbg.rs
+++ b/crates/assists/src/handlers/remove_dbg.rs
@@ -1,6 +1,6 @@
1use syntax::{ 1use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 match_ast, SyntaxElement, SyntaxKind, TextRange, TextSize, T, 3 match_ast, SyntaxElement, TextRange, TextSize, T,
4}; 4};
5 5
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -136,14 +136,14 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
136 symbol_kind => { 136 symbol_kind => {
137 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); 137 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty();
138 if symbol_not_in_bracket 138 if symbol_not_in_bracket
139 && symbol_kind != SyntaxKind::COLON // paths 139 && symbol_kind != T![:] // paths
140 && (symbol_kind != SyntaxKind::DOT // field/method access 140 && (symbol_kind != T![.] // field/method access
141 || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations 141 || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations
142 .peek() 142 .peek()
143 .map(|element| element.kind() == SyntaxKind::DOT) 143 .map(|element| element.kind() == T![.])
144 .unwrap_or(false)) 144 .unwrap_or(false))
145 && symbol_kind != SyntaxKind::QUESTION // try operator 145 && symbol_kind != T![?] // try operator
146 && (symbol_kind.is_punct() || symbol_kind == SyntaxKind::AS_KW) 146 && (symbol_kind.is_punct() || symbol_kind == T![as])
147 { 147 {
148 return true; 148 return true;
149 } 149 }
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index 3a29b5203..e5522980d 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -5,7 +5,7 @@
5 5
6use itertools::Itertools; 6use itertools::Itertools;
7use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
8use syntax::{ast, AstNode, SyntaxKind}; 8use syntax::{ast, AstNode, T};
9 9
10use crate::{ 10use crate::{
11 context::CompletionContext, 11 context::CompletionContext,
@@ -21,15 +21,17 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
21 21
22 let attribute = ctx.attribute_under_caret.as_ref()?; 22 let attribute = ctx.attribute_under_caret.as_ref()?;
23 match (attribute.path(), attribute.token_tree()) { 23 match (attribute.path(), attribute.token_tree()) {
24 (Some(path), Some(token_tree)) => match path.to_string().as_str() { 24 (Some(path), Some(token_tree)) => {
25 "derive" => complete_derive(acc, ctx, token_tree), 25 let path = path.syntax().text();
26 "feature" => complete_lint(acc, ctx, token_tree, FEATURES), 26 if path == "derive" {
27 "allow" | "warn" | "deny" | "forbid" => { 27 complete_derive(acc, ctx, token_tree)
28 } else if path == "feature" {
29 complete_lint(acc, ctx, token_tree, FEATURES)
30 } else if path == "allow" || path == "warn" || path == "deny" || path == "forbid" {
28 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS); 31 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
29 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); 32 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
30 } 33 }
31 _ => {} 34 }
32 },
33 (_, Some(_token_tree)) => {} 35 (_, Some(_token_tree)) => {}
34 _ => complete_attribute_start(acc, ctx, attribute), 36 _ => complete_attribute_start(acc, ctx, attribute),
35 } 37 }
@@ -203,8 +205,7 @@ fn complete_lint(
203fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { 205fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> {
204 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { 206 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) {
205 (Some(left_paren), Some(right_paren)) 207 (Some(left_paren), Some(right_paren))
206 if left_paren.kind() == SyntaxKind::L_PAREN 208 if left_paren.kind() == T!['('] && right_paren.kind() == T![')'] =>
207 && right_paren.kind() == SyntaxKind::R_PAREN =>
208 { 209 {
209 let mut input_derives = FxHashSet::default(); 210 let mut input_derives = FxHashSet::default();
210 let mut current_derive = String::new(); 211 let mut current_derive = String::new();
@@ -216,7 +217,7 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin
216 .skip(1) 217 .skip(1)
217 .take_while(|token| token != &right_paren) 218 .take_while(|token| token != &right_paren)
218 { 219 {
219 if SyntaxKind::COMMA == token.kind() { 220 if T![,] == token.kind() {
220 if !current_derive.is_empty() { 221 if !current_derive.is_empty() {
221 input_derives.insert(current_derive); 222 input_derives.insert(current_derive);
222 current_derive = String::new(); 223 current_derive = String::new();
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index aa9c845da..135ae49dc 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -93,11 +93,11 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt
93 // `impl .. { const $0 }` 93 // `impl .. { const $0 }`
94 // ERROR 0 94 // ERROR 0
95 // CONST_KW <- * 95 // CONST_KW <- *
96 SyntaxKind::CONST_KW => 0, 96 T![const] => 0,
97 // `impl .. { fn/type $0 }` 97 // `impl .. { fn/type $0 }`
98 // FN/TYPE_ALIAS 0 98 // FN/TYPE_ALIAS 0
99 // FN_KW <- * 99 // FN_KW <- *
100 SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0, 100 T![fn] | T![type] => 0,
101 // `impl .. { fn/type/const foo$0 }` 101 // `impl .. { fn/type/const foo$0 }`
102 // FN/TYPE_ALIAS/CONST 1 102 // FN/TYPE_ALIAS/CONST 1
103 // NAME 0 103 // NAME 0
@@ -121,7 +121,7 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt
121 let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?; 121 let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?;
122 let kind = match impl_item.kind() { 122 let kind = match impl_item.kind() {
123 // `impl ... { const $0 fn/type/const }` 123 // `impl ... { const $0 fn/type/const }`
124 _ if token.kind() == SyntaxKind::CONST_KW => ImplCompletionKind::Const, 124 _ if token.kind() == T![const] => ImplCompletionKind::Const,
125 SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const, 125 SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const,
126 SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias, 126 SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias,
127 SyntaxKind::FN => ImplCompletionKind::Fn, 127 SyntaxKind::FN => ImplCompletionKind::Fn,
diff --git a/crates/completion/src/patterns.rs b/crates/completion/src/patterns.rs
index f148b9402..f3ce91dd1 100644
--- a/crates/completion/src/patterns.rs
+++ b/crates/completion/src/patterns.rs
@@ -5,7 +5,7 @@ use syntax::{
5 ast::{self, LoopBodyOwner}, 5 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, 6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
7 SyntaxKind::*, 7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, 8 SyntaxNode, SyntaxToken, T,
9}; 9};
10 10
11#[cfg(test)] 11#[cfg(test)]
@@ -119,7 +119,7 @@ pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
119 element 119 element
120 .into_token() 120 .into_token()
121 .and_then(|it| previous_non_trivia_token(it)) 121 .and_then(|it| previous_non_trivia_token(it))
122 .filter(|it| it.kind() == UNSAFE_KW) 122 .filter(|it| it.kind() == T![unsafe])
123 .is_some() 123 .is_some()
124} 124}
125#[test] 125#[test]
@@ -131,7 +131,7 @@ pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
131 element 131 element
132 .into_token() 132 .into_token()
133 .and_then(|it| previous_non_trivia_token(it)) 133 .and_then(|it| previous_non_trivia_token(it))
134 .filter(|it| it.kind() == IF_KW) 134 .filter(|it| it.kind() == T![if])
135 .is_some() 135 .is_some()
136} 136}
137 137
@@ -139,7 +139,7 @@ pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool {
139 element 139 element
140 .into_token() 140 .into_token()
141 .and_then(|it| previous_non_trivia_token(it)) 141 .and_then(|it| previous_non_trivia_token(it))
142 .filter(|it| it.kind() == FN_KW) 142 .filter(|it| it.kind() == T![fn])
143 .is_some() 143 .is_some()
144} 144}
145#[test] 145#[test]
@@ -154,7 +154,7 @@ pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool {
154 .into_token() 154 .into_token()
155 .and_then(|it| previous_non_trivia_token(it)) 155 .and_then(|it| previous_non_trivia_token(it))
156 .and_then(|it| previous_non_trivia_token(it)) 156 .and_then(|it| previous_non_trivia_token(it))
157 .filter(|it| it.kind() == FOR_KW) 157 .filter(|it| it.kind() == T![for])
158 .is_some() 158 .is_some()
159} 159}
160#[test] 160#[test]
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index cc1938333..6cbf5cecf 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -1263,6 +1263,24 @@ pub enum GenericParam {
1263} 1263}
1264impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); 1264impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
1265 1265
1266impl GenericParam {
1267 pub fn module(self, db: &dyn HirDatabase) -> Module {
1268 match self {
1269 GenericParam::TypeParam(it) => it.module(db),
1270 GenericParam::LifetimeParam(it) => it.module(db),
1271 GenericParam::ConstParam(it) => it.module(db),
1272 }
1273 }
1274
1275 pub fn name(self, db: &dyn HirDatabase) -> Name {
1276 match self {
1277 GenericParam::TypeParam(it) => it.name(db),
1278 GenericParam::LifetimeParam(it) => it.name(db),
1279 GenericParam::ConstParam(it) => it.name(db),
1280 }
1281 }
1282}
1283
1266#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1284#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1267pub struct TypeParam { 1285pub struct TypeParam {
1268 pub(crate) id: TypeParamId, 1286 pub(crate) id: TypeParamId,
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index e24c78301..4eecae697 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -215,10 +215,8 @@ impl TryToNav for Definition {
215 Definition::ModuleDef(it) => it.try_to_nav(db), 215 Definition::ModuleDef(it) => it.try_to_nav(db),
216 Definition::SelfType(it) => it.try_to_nav(db), 216 Definition::SelfType(it) => it.try_to_nav(db),
217 Definition::Local(it) => Some(it.to_nav(db)), 217 Definition::Local(it) => Some(it.to_nav(db)),
218 Definition::TypeParam(it) => it.try_to_nav(db), 218 Definition::GenericParam(it) => it.try_to_nav(db),
219 Definition::LifetimeParam(it) => it.try_to_nav(db),
220 Definition::Label(it) => Some(it.to_nav(db)), 219 Definition::Label(it) => Some(it.to_nav(db)),
221 Definition::ConstParam(it) => it.try_to_nav(db),
222 } 220 }
223 } 221 }
224} 222}
@@ -389,6 +387,16 @@ impl TryToNav for hir::AssocItem {
389 } 387 }
390} 388}
391 389
390impl TryToNav for hir::GenericParam {
391 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
392 match self {
393 hir::GenericParam::TypeParam(it) => it.try_to_nav(db),
394 hir::GenericParam::ConstParam(it) => it.try_to_nav(db),
395 hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db),
396 }
397 }
398}
399
392impl ToNav for hir::Local { 400impl ToNav for hir::Local {
393 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 401 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
394 let src = self.source(db); 402 let src = self.source(db);
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 72ddf3690..de10406bc 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -1,6 +1,6 @@
1//! Resolves and rewrites links in markdown documentation. 1//! Resolves and rewrites links in markdown documentation.
2 2
3use std::{convert::TryFrom, iter::once}; 3use std::{convert::TryFrom, iter::once, ops::Range};
4 4
5use itertools::Itertools; 5use itertools::Itertools;
6use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; 6use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
@@ -61,6 +61,30 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi
61 out 61 out
62} 62}
63 63
64pub(crate) fn extract_definitions_from_markdown(
65 markdown: &str,
66) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> {
67 let mut res = vec![];
68 let mut cb = |link: BrokenLink| {
69 Some((
70 /*url*/ link.reference.to_owned().into(),
71 /*title*/ link.reference.to_owned().into(),
72 ))
73 };
74 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
75 for (event, range) in doc.into_offset_iter() {
76 match event {
77 Event::Start(Tag::Link(_link_type, ref target, ref title)) => {
78 let link = if target.is_empty() { title } else { target };
79 let (link, ns) = parse_link(link);
80 res.push((link.to_string(), ns, range));
81 }
82 _ => {}
83 }
84 }
85 res
86}
87
64/// Remove all links in markdown documentation. 88/// Remove all links in markdown documentation.
65pub(crate) fn remove_links(markdown: &str) -> String { 89pub(crate) fn remove_links(markdown: &str) -> String {
66 let mut drop_link = false; 90 let mut drop_link = false;
@@ -192,9 +216,7 @@ fn rewrite_intra_doc_link(
192 Definition::Field(it) => it.resolve_doc_path(db, link, ns), 216 Definition::Field(it) => it.resolve_doc_path(db, link, ns),
193 Definition::SelfType(_) 217 Definition::SelfType(_)
194 | Definition::Local(_) 218 | Definition::Local(_)
195 | Definition::TypeParam(_) 219 | Definition::GenericParam(_)
196 | Definition::ConstParam(_)
197 | Definition::LifetimeParam(_)
198 | Definition::Label(_) => return None, 220 | Definition::Label(_) => return None,
199 }?; 221 }?;
200 let krate = resolved.module(db)?.krate(); 222 let krate = resolved.module(db)?.krate();
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 95b4cb9e3..c20185b16 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,14 +1,20 @@
1use either::Either; 1use either::Either;
2use hir::Semantics; 2use hir::{HasAttrs, ModuleDef, Semantics};
3use ide_db::{ 3use ide_db::{
4 base_db::FileId, 4 base_db::FileId,
5 defs::{NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 symbol_index, RootDatabase, 6 symbol_index, RootDatabase,
7}; 7};
8use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 8use syntax::{
9 ast::{self, NameOwner},
10 match_ast, AstNode, AstToken,
11 SyntaxKind::*,
12 SyntaxToken, TextSize, TokenAtOffset, T,
13};
9 14
10use crate::{ 15use crate::{
11 display::{ToNav, TryToNav}, 16 display::{ToNav, TryToNav},
17 doc_links::extract_definitions_from_markdown,
12 FilePosition, NavigationTarget, RangeInfo, SymbolKind, 18 FilePosition, NavigationTarget, RangeInfo, SymbolKind,
13}; 19};
14 20
@@ -30,6 +36,10 @@ pub(crate) fn goto_definition(
30 let original_token = pick_best(file.token_at_offset(position.offset))?; 36 let original_token = pick_best(file.token_at_offset(position.offset))?;
31 let token = sema.descend_into_macros(original_token.clone()); 37 let token = sema.descend_into_macros(original_token.clone());
32 let parent = token.parent(); 38 let parent = token.parent();
39 if let Some(comment) = ast::Comment::cast(token.clone()) {
40 let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?;
41 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
42 }
33 43
34 let nav_targets = match_ast! { 44 let nav_targets = match_ast! {
35 match parent { 45 match parent {
@@ -68,11 +78,66 @@ pub(crate) fn goto_definition(
68 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 78 Some(RangeInfo::new(original_token.text_range(), nav_targets))
69} 79}
70 80
81fn def_for_doc_comment(
82 sema: &Semantics<RootDatabase>,
83 position: FilePosition,
84 doc_comment: &ast::Comment,
85) -> Option<hir::ModuleDef> {
86 let parent = doc_comment.syntax().parent();
87 let db = sema.db;
88 let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?;
89 let link = &link;
90 let name = match_ast! {
91 match parent {
92 ast::Name(name) => Some(name),
93 ast::Fn(func) => func.name(),
94 _ => None,
95 }
96 }?;
97 let definition = NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db))?;
98 match definition {
99 Definition::ModuleDef(def) => match def {
100 ModuleDef::Module(it) => it.resolve_doc_path(db, link, ns),
101 ModuleDef::Function(it) => it.resolve_doc_path(db, link, ns),
102 ModuleDef::Adt(it) => it.resolve_doc_path(db, link, ns),
103 ModuleDef::Variant(it) => it.resolve_doc_path(db, link, ns),
104 ModuleDef::Const(it) => it.resolve_doc_path(db, link, ns),
105 ModuleDef::Static(it) => it.resolve_doc_path(db, link, ns),
106 ModuleDef::Trait(it) => it.resolve_doc_path(db, link, ns),
107 ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
108 ModuleDef::BuiltinType(_) => return None,
109 },
110 Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
111 Definition::Field(it) => it.resolve_doc_path(db, link, ns),
112 Definition::SelfType(_)
113 | Definition::Local(_)
114 | Definition::GenericParam(_)
115 | Definition::Label(_) => return None,
116 }
117}
118
119fn extract_positioned_link_from_comment(
120 position: FilePosition,
121 comment: &ast::Comment,
122) -> Option<(String, Option<hir::Namespace>)> {
123 let comment_range = comment.syntax().text_range();
124 let doc_comment = comment.doc_comment()?;
125 let def_links = extract_definitions_from_markdown(doc_comment);
126 let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| {
127 let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32);
128 match position.offset.checked_sub(matched_position) {
129 Some(distance) => distance,
130 None => comment_range.end(),
131 }
132 })?;
133 Some((def_link.to_string(), ns.clone()))
134}
135
71fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 136fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
72 return tokens.max_by_key(priority); 137 return tokens.max_by_key(priority);
73 fn priority(n: &SyntaxToken) -> usize { 138 fn priority(n: &SyntaxToken) -> usize {
74 match n.kind() { 139 match n.kind() {
75 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2, 140 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2,
76 kind if kind.is_trivia() => 0, 141 kind if kind.is_trivia() => 0,
77 _ => 1, 142 _ => 1,
78 } 143 }
@@ -1145,4 +1210,19 @@ fn foo<'foo>(_: &'foo ()) {
1145}"#, 1210}"#,
1146 ) 1211 )
1147 } 1212 }
1213
1214 #[test]
1215 fn goto_def_for_intra_rustdoc_link_same_file() {
1216 check(
1217 r#"
1218/// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar)
1219pub fn bar() { }
1220
1221/// You might want to see [`std::fs::read()`] too.
1222pub fn foo() { }
1223 //^^^
1224
1225}"#,
1226 )
1227 }
1148} 1228}
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 165b32ef9..e892d5588 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,6 +1,6 @@
1use hir::{ 1use hir::{
2 Adt, AsAssocItem, AssocItemContainer, FieldSource, HasAttrs, HasSource, HirDisplay, Module, 2 Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
3 ModuleDef, ModuleSource, Semantics, 3 HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
4}; 4};
5use ide_db::base_db::SourceDatabase; 5use ide_db::base_db::SourceDatabase;
6use ide_db::{ 6use ide_db::{
@@ -17,7 +17,7 @@ use crate::{
17 doc_links::{remove_links, rewrite_links}, 17 doc_links::{remove_links, rewrite_links},
18 markdown_remove::remove_markdown, 18 markdown_remove::remove_markdown,
19 markup::Markup, 19 markup::Markup,
20 runnables::{runnable, runnable_fn}, 20 runnables::{runnable_fn, runnable_mod},
21 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 21 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
22}; 22};
23 23
@@ -192,7 +192,7 @@ fn runnable_action(
192 Definition::ModuleDef(it) => match it { 192 Definition::ModuleDef(it) => match it {
193 ModuleDef::Module(it) => match it.definition_source(sema.db).value { 193 ModuleDef::Module(it) => match it.definition_source(sema.db).value {
194 ModuleSource::Module(it) => { 194 ModuleSource::Module(it) => {
195 runnable(&sema, it.syntax().clone()).map(|it| HoverAction::Runnable(it)) 195 runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it))
196 } 196 }
197 _ => None, 197 _ => None,
198 }, 198 },
@@ -220,12 +220,12 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
220 } 220 }
221 }; 221 };
222 222
223 if let Definition::TypeParam(it) = def { 223 if let Definition::GenericParam(GenericParam::TypeParam(it)) = def {
224 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); 224 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
225 } else { 225 } else {
226 let ty = match def { 226 let ty = match def {
227 Definition::Local(it) => it.ty(db), 227 Definition::Local(it) => it.ty(db),
228 Definition::ConstParam(it) => it.ty(db), 228 Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db),
229 _ => return None, 229 _ => return None,
230 }; 230 };
231 231
@@ -357,9 +357,11 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
357 }) 357 })
358 } 358 }
359 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 359 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
360 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), 360 Definition::GenericParam(it) => match it {
361 Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))), 361 GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))),
362 Definition::ConstParam(it) => from_def_source(db, it, None), 362 GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
363 GenericParam::ConstParam(it) => from_def_source(db, it, None),
364 },
363 }; 365 };
364 366
365 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 367 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index a74829cd0..3e9a65d9c 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -353,13 +353,25 @@ fn is_argument_similar_to_param_name(
353 } 353 }
354 match get_string_representation(argument) { 354 match get_string_representation(argument) {
355 None => false, 355 None => false,
356 Some(mut repr) => { 356 Some(argument_string) => {
357 let param_name = param_name.to_ascii_lowercase(); 357 let num_leading_underscores =
358 let argument_string = { 358 argument_string.bytes().take_while(|&c| c == b'_').count();
359 repr.make_ascii_lowercase(); 359
360 repr.trim_start_matches('_') 360 // Does the argument name begin with the parameter name? Ignore leading underscores.
361 }; 361 let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
362 argument_string.starts_with(&param_name) || argument_string.ends_with(&param_name) 362 let starts_with_pattern = param_name.bytes().all(
363 |expected| matches!(arg_bytes.next(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
364 );
365
366 if starts_with_pattern {
367 return true;
368 }
369
370 // Does the argument name end with the parameter name?
371 let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
372 param_name.bytes().rev().all(
373 |expected| matches!(arg_bytes.next_back(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
374 )
363 } 375 }
364 } 376 }
365} 377}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 409507bd0..1f368cbd0 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -76,7 +76,7 @@ pub use crate::{
76 references::{rename::RenameError, Declaration, ReferenceSearchResult}, 76 references::{rename::RenameError, Declaration, ReferenceSearchResult},
77 runnables::{Runnable, RunnableKind, TestId}, 77 runnables::{Runnable, RunnableKind, TestId},
78 syntax_highlighting::{ 78 syntax_highlighting::{
79 tags::{Highlight, HlMod, HlMods, HlTag}, 79 tags::{Highlight, HlMod, HlMods, HlPunct, HlTag},
80 HlRange, 80 HlRange,
81 }, 81 },
82}; 82};
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 37a95e1c5..b774a2be1 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -21,7 +21,7 @@ use ide_db::{
21use syntax::{ 21use syntax::{
22 algo::find_node_at_offset, 22 algo::find_node_at_offset,
23 ast::{self, NameOwner}, 23 ast::{self, NameOwner},
24 match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, 24 match_ast, AstNode, SyntaxNode, TextRange, TokenAtOffset, T,
25}; 25};
26 26
27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; 27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind};
@@ -130,7 +130,10 @@ pub(crate) fn find_all_refs(
130 kind = ReferenceKind::FieldShorthandForLocal; 130 kind = ReferenceKind::FieldShorthandForLocal;
131 } 131 }
132 } 132 }
133 } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { 133 } else if matches!(
134 def,
135 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
136 ) {
134 kind = ReferenceKind::Lifetime; 137 kind = ReferenceKind::Lifetime;
135 }; 138 };
136 139
@@ -200,7 +203,7 @@ fn get_struct_def_name_for_struct_literal_search(
200 position: FilePosition, 203 position: FilePosition,
201) -> Option<ast::Name> { 204) -> Option<ast::Name> {
202 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 205 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
203 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 206 if right.kind() != T!['{'] && right.kind() != T!['('] {
204 return None; 207 return None;
205 } 208 }
206 if let Some(name) = 209 if let Some(name) =
@@ -227,7 +230,7 @@ fn get_enum_def_name_for_struct_literal_search(
227 position: FilePosition, 230 position: FilePosition,
228) -> Option<ast::Name> { 231) -> Option<ast::Name> {
229 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 232 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
230 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 233 if right.kind() != T!['{'] && right.kind() != T!['('] {
231 return None; 234 return None;
232 } 235 }
233 if let Some(name) = 236 if let Some(name) =
@@ -252,8 +255,7 @@ fn try_find_self_references(
252 syntax: &SyntaxNode, 255 syntax: &SyntaxNode,
253 position: FilePosition, 256 position: FilePosition,
254) -> Option<RangeInfo<ReferenceSearchResult>> { 257) -> Option<RangeInfo<ReferenceSearchResult>> {
255 let self_token = 258 let self_token = syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])?;
256 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?;
257 let parent = self_token.parent(); 259 let parent = self_token.parent();
258 match_ast! { 260 match_ast! {
259 match parent { 261 match parent {
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 557563d7e..3a1e204db 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -96,21 +96,23 @@ impl Runnable {
96pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 96pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
97 let sema = Semantics::new(db); 97 let sema = Semantics::new(db);
98 let source_file = sema.parse(file_id); 98 let source_file = sema.parse(file_id);
99 source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() 99 source_file
100} 100 .syntax()
101 101 .descendants()
102pub(crate) fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { 102 .filter_map(|item| {
103 let runnable_item = match_ast! { 103 let runnable = match_ast! {
104 match (item.clone()) { 104 match item {
105 ast::Fn(func) => { 105 ast::Fn(func) => {
106 let def = sema.to_def(&func)?; 106 let def = sema.to_def(&func)?;
107 runnable_fn(sema, def) 107 runnable_fn(&sema, def)
108 }, 108 },
109 ast::Module(it) => runnable_mod(sema, it), 109 ast::Module(it) => runnable_mod(&sema, it),
110 _ => None, 110 _ => None,
111 } 111 }
112 }; 112 };
113 runnable_item.or_else(|| runnable_doctest(sema, item)) 113 runnable.or_else(|| runnable_doctest(&sema, item))
114 })
115 .collect()
114} 116}
115 117
116pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { 118pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
@@ -145,6 +147,29 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) ->
145 Some(Runnable { nav, kind, cfg }) 147 Some(Runnable { nav, kind, cfg })
146} 148}
147 149
150pub(crate) fn runnable_mod(
151 sema: &Semantics<RootDatabase>,
152 module: ast::Module,
153) -> Option<Runnable> {
154 if !has_test_function_or_multiple_test_submodules(&module) {
155 return None;
156 }
157 let module_def = sema.to_def(&module)?;
158
159 let path = module_def
160 .path_to_root(sema.db)
161 .into_iter()
162 .rev()
163 .filter_map(|it| it.name(sema.db))
164 .join("::");
165
166 let def = sema.to_def(&module)?;
167 let attrs = def.attrs(sema.db);
168 let cfg = attrs.cfg();
169 let nav = module_def.to_nav(sema.db);
170 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
171}
172
148fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { 173fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> {
149 match_ast! { 174 match_ast! {
150 match item { 175 match item {
@@ -253,26 +278,6 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
253 }) 278 })
254} 279}
255 280
256fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
257 if !has_test_function_or_multiple_test_submodules(&module) {
258 return None;
259 }
260 let module_def = sema.to_def(&module)?;
261
262 let path = module_def
263 .path_to_root(sema.db)
264 .into_iter()
265 .rev()
266 .filter_map(|it| it.name(sema.db))
267 .join("::");
268
269 let def = sema.to_def(&module)?;
270 let attrs = def.attrs(sema.db);
271 let cfg = attrs.cfg();
272 let nav = module_def.to_nav(sema.db);
273 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
274}
275
276// We could create runnables for modules with number_of_test_submodules > 0, 281// We could create runnables for modules with number_of_test_submodules > 0,
277// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already 282// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already
278fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { 283fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index ad456bc00..f2d4da78d 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -3,30 +3,29 @@ pub(crate) mod tags;
3mod highlights; 3mod highlights;
4mod injector; 4mod injector;
5 5
6mod highlight;
6mod format; 7mod format;
7mod injection;
8mod macro_rules; 8mod macro_rules;
9mod inject;
9 10
10mod html; 11mod html;
11#[cfg(test)] 12#[cfg(test)]
12mod tests; 13mod tests;
13 14
14use hir::{AsAssocItem, Local, Name, Semantics, VariantDef}; 15use hir::{Name, Semantics};
15use ide_db::{ 16use ide_db::RootDatabase;
16 defs::{Definition, NameClass, NameRefClass},
17 RootDatabase,
18};
19use rustc_hash::FxHashMap; 17use rustc_hash::FxHashMap;
20use syntax::{ 18use syntax::{
21 ast::{self, HasFormatSpecifier}, 19 ast::{self, HasFormatSpecifier},
22 AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, 20 AstNode, AstToken, Direction, NodeOrToken,
23 SyntaxKind::{self, *}, 21 SyntaxKind::*,
24 SyntaxNode, SyntaxToken, TextRange, WalkEvent, T, 22 SyntaxNode, TextRange, WalkEvent, T,
25}; 23};
26 24
27use crate::{ 25use crate::{
28 syntax_highlighting::{ 26 syntax_highlighting::{
29 format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter, tags::Highlight, 27 format::highlight_format_string, highlights::Highlights,
28 macro_rules::MacroRulesHighlighter, tags::Highlight,
30 }, 29 },
31 FileId, HlMod, HlTag, SymbolKind, 30 FileId, HlMod, HlTag, SymbolKind,
32}; 31};
@@ -73,12 +72,22 @@ pub(crate) fn highlight(
73 } 72 }
74 }; 73 };
75 74
76 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
77 let mut hl = highlights::Highlights::new(range_to_highlight); 75 let mut hl = highlights::Highlights::new(range_to_highlight);
76 traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting);
77 hl.to_vec()
78}
79
80fn traverse(
81 hl: &mut Highlights,
82 sema: &Semantics<RootDatabase>,
83 root: &SyntaxNode,
84 range_to_highlight: TextRange,
85 syntactic_name_ref_highlighting: bool,
86) {
87 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
78 88
79 let mut current_macro_call: Option<ast::MacroCall> = None; 89 let mut current_macro_call: Option<ast::MacroCall> = None;
80 let mut current_macro_rules: Option<ast::MacroRules> = None; 90 let mut current_macro_rules: Option<ast::MacroRules> = None;
81 let mut format_string_highlighter = FormatStringHighlighter::default();
82 let mut macro_rules_highlighter = MacroRulesHighlighter::default(); 91 let mut macro_rules_highlighter = MacroRulesHighlighter::default();
83 let mut inside_attribute = false; 92 let mut inside_attribute = false;
84 93
@@ -110,7 +119,6 @@ pub(crate) fn highlight(
110 WalkEvent::Leave(Some(mc)) => { 119 WalkEvent::Leave(Some(mc)) => {
111 assert_eq!(current_macro_call, Some(mc)); 120 assert_eq!(current_macro_call, Some(mc));
112 current_macro_call = None; 121 current_macro_call = None;
113 format_string_highlighter = FormatStringHighlighter::default();
114 } 122 }
115 _ => (), 123 _ => (),
116 } 124 }
@@ -128,26 +136,24 @@ pub(crate) fn highlight(
128 } 136 }
129 _ => (), 137 _ => (),
130 } 138 }
131
132 match &event { 139 match &event {
133 // Check for Rust code in documentation
134 WalkEvent::Leave(NodeOrToken::Node(node)) => {
135 if ast::Attr::can_cast(node.kind()) {
136 inside_attribute = false
137 }
138 if let Some((new_comments, inj)) = injection::extract_doc_comments(node) {
139 injection::highlight_doc_comment(new_comments, inj, &mut hl);
140 }
141 }
142 WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { 140 WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
143 inside_attribute = true 141 inside_attribute = true
144 } 142 }
143 WalkEvent::Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
144 inside_attribute = false
145 }
145 _ => (), 146 _ => (),
146 } 147 }
147 148
148 let element = match event { 149 let element = match event {
149 WalkEvent::Enter(it) => it, 150 WalkEvent::Enter(it) => it,
150 WalkEvent::Leave(_) => continue, 151 WalkEvent::Leave(it) => {
152 if let Some(node) = it.as_node() {
153 inject::doc_comment(hl, node);
154 }
155 continue;
156 }
151 }; 157 };
152 158
153 let range = element.text_range(); 159 let range = element.text_range();
@@ -167,8 +173,6 @@ pub(crate) fn highlight(
167 let token = sema.descend_into_macros(token.clone()); 173 let token = sema.descend_into_macros(token.clone());
168 let parent = token.parent(); 174 let parent = token.parent();
169 175
170 format_string_highlighter.check_for_format_string(&parent);
171
172 // We only care Name and Name_ref 176 // We only care Name and Name_ref
173 match (token.kind(), parent.kind()) { 177 match (token.kind(), parent.kind()) {
174 (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), 178 (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(),
@@ -181,13 +185,17 @@ pub(crate) fn highlight(
181 if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) { 185 if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) {
182 if token.is_raw() { 186 if token.is_raw() {
183 let expanded = element_to_highlight.as_token().unwrap().clone(); 187 let expanded = element_to_highlight.as_token().unwrap().clone();
184 if injection::highlight_injection(&mut hl, &sema, token, expanded).is_some() { 188 if inject::ra_fixture(hl, &sema, token, expanded).is_some() {
185 continue; 189 continue;
186 } 190 }
187 } 191 }
188 } 192 }
189 193
190 if let Some((mut highlight, binding_hash)) = highlight_element( 194 if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) {
195 continue;
196 }
197
198 if let Some((mut highlight, binding_hash)) = highlight::element(
191 &sema, 199 &sema,
192 &mut bindings_shadow_count, 200 &mut bindings_shadow_count,
193 syntactic_name_ref_highlighting, 201 syntactic_name_ref_highlighting,
@@ -197,31 +205,25 @@ pub(crate) fn highlight(
197 highlight = highlight | HlMod::Attribute; 205 highlight = highlight | HlMod::Attribute;
198 } 206 }
199 207
200 if macro_rules_highlighter.highlight(element_to_highlight.clone()).is_none() { 208 hl.add(HlRange { range, highlight, binding_hash });
201 hl.add(HlRange { range, highlight, binding_hash }); 209 }
202 }
203 210
204 if let Some(string) = 211 if let Some(string) = element_to_highlight.as_token().cloned().and_then(ast::String::cast) {
205 element_to_highlight.as_token().cloned().and_then(ast::String::cast) 212 highlight_format_string(hl, &string, range);
206 { 213 // Highlight escape sequences
207 format_string_highlighter.highlight_format_string(&mut hl, &string, range); 214 if let Some(char_ranges) = string.char_ranges() {
208 // Highlight escape sequences 215 for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) {
209 if let Some(char_ranges) = string.char_ranges() { 216 if string.text()[piece_range.start().into()..].starts_with('\\') {
210 for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { 217 hl.add(HlRange {
211 if string.text()[piece_range.start().into()..].starts_with('\\') { 218 range: piece_range + range.start(),
212 hl.add(HlRange { 219 highlight: HlTag::EscapeSequence.into(),
213 range: piece_range + range.start(), 220 binding_hash: None,
214 highlight: HlTag::EscapeSequence.into(), 221 });
215 binding_hash: None,
216 });
217 }
218 } 222 }
219 } 223 }
220 } 224 }
221 } 225 }
222 } 226 }
223
224 hl.to_vec()
225} 227}
226 228
227fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { 229fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
@@ -239,505 +241,3 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
239 241
240 Some(TextRange::new(range_start, range_end)) 242 Some(TextRange::new(range_start, range_end))
241} 243}
242
243/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly.
244fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool {
245 while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) {
246 if parent.kind() != *kind {
247 return false;
248 }
249
250 // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value
251 // in the same pattern is unstable: rust-lang/rust#68354.
252 node = node.parent().unwrap().into();
253 kinds = rest;
254 }
255
256 // Only true if we matched all expected kinds
257 kinds.len() == 0
258}
259
260fn is_consumed_lvalue(
261 node: NodeOrToken<SyntaxNode, SyntaxToken>,
262 local: &Local,
263 db: &RootDatabase,
264) -> bool {
265 // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming.
266 parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db)
267}
268
269fn highlight_element(
270 sema: &Semantics<RootDatabase>,
271 bindings_shadow_count: &mut FxHashMap<Name, u32>,
272 syntactic_name_ref_highlighting: bool,
273 element: SyntaxElement,
274) -> Option<(Highlight, Option<u64>)> {
275 let db = sema.db;
276 let mut binding_hash = None;
277 let highlight: Highlight = match element.kind() {
278 FN => {
279 bindings_shadow_count.clear();
280 return None;
281 }
282
283 // Highlight definitions depending on the "type" of the definition.
284 NAME => {
285 let name = element.into_node().and_then(ast::Name::cast).unwrap();
286 let name_kind = NameClass::classify(sema, &name);
287
288 if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
289 if let Some(name) = local.name(db) {
290 let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
291 *shadow_count += 1;
292 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
293 }
294 };
295
296 match name_kind {
297 Some(NameClass::ExternCrate(_)) => HlTag::Symbol(SymbolKind::Module).into(),
298 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
299 Some(NameClass::ConstReference(def)) => highlight_def(db, def),
300 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
301 let mut h = HlTag::Symbol(SymbolKind::Field).into();
302 if let Definition::Field(field) = field_ref {
303 if let VariantDef::Union(_) = field.parent_def(db) {
304 h |= HlMod::Unsafe;
305 }
306 }
307
308 h
309 }
310 None => highlight_name_by_syntax(name) | HlMod::Definition,
311 }
312 }
313
314 // Highlight references like the definitions they resolve to
315 NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => {
316 // even though we track whether we are in an attribute or not we still need this special case
317 // as otherwise we would emit unresolved references for name refs inside attributes
318 Highlight::from(HlTag::Symbol(SymbolKind::Function))
319 }
320 NAME_REF => {
321 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
322 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
323 match NameRefClass::classify(sema, &name_ref) {
324 Some(name_kind) => match name_kind {
325 NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(),
326 NameRefClass::Definition(def) => {
327 if let Definition::Local(local) = &def {
328 if let Some(name) = local.name(db) {
329 let shadow_count =
330 bindings_shadow_count.entry(name.clone()).or_default();
331 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
332 }
333 };
334
335 let mut h = highlight_def(db, def);
336
337 if let Definition::Local(local) = &def {
338 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) {
339 h |= HlMod::Consuming;
340 }
341 }
342
343 if let Some(parent) = name_ref.syntax().parent() {
344 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
345 if let Definition::Field(field) = def {
346 if let VariantDef::Union(_) = field.parent_def(db) {
347 h |= HlMod::Unsafe;
348 }
349 }
350 }
351 }
352
353 h
354 }
355 NameRefClass::FieldShorthand { .. } => {
356 HlTag::Symbol(SymbolKind::Field).into()
357 }
358 },
359 None if syntactic_name_ref_highlighting => {
360 highlight_name_ref_by_syntax(name_ref, sema)
361 }
362 None => HlTag::UnresolvedReference.into(),
363 }
364 })
365 }
366
367 // Simple token-based highlighting
368 COMMENT => {
369 let comment = element.into_token().and_then(ast::Comment::cast)?;
370 let h = HlTag::Comment;
371 match comment.kind().doc {
372 Some(_) => h | HlMod::Documentation,
373 None => h.into(),
374 }
375 }
376 STRING | BYTE_STRING => HlTag::StringLiteral.into(),
377 ATTR => HlTag::Attribute.into(),
378 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
379 BYTE => HlTag::ByteLiteral.into(),
380 CHAR => HlTag::CharLiteral.into(),
381 QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow,
382 LIFETIME => {
383 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
384
385 match NameClass::classify_lifetime(sema, &lifetime) {
386 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
387 None => match NameRefClass::classify_lifetime(sema, &lifetime) {
388 Some(NameRefClass::Definition(def)) => highlight_def(db, def),
389 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)),
390 },
391 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | HlMod::Definition,
392 }
393 }
394 p if p.is_punct() => match p {
395 T![&] => {
396 let h = HlTag::Operator.into();
397 let is_unsafe = element
398 .parent()
399 .and_then(ast::RefExpr::cast)
400 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
401 .unwrap_or(false);
402 if is_unsafe {
403 h | HlMod::Unsafe
404 } else {
405 h
406 }
407 }
408 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(),
409 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
410 HlTag::Symbol(SymbolKind::Macro).into()
411 }
412 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
413 HlTag::BuiltinType.into()
414 }
415 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
416 HlTag::Keyword.into()
417 }
418 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
419 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
420
421 let expr = prefix_expr.expr()?;
422 let ty = sema.type_of_expr(&expr)?;
423 if ty.is_raw_ptr() {
424 HlTag::Operator | HlMod::Unsafe
425 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
426 HlTag::Operator.into()
427 } else {
428 HlTag::Punctuation.into()
429 }
430 }
431 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
432 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
433
434 let expr = prefix_expr.expr()?;
435 match expr {
436 ast::Expr::Literal(_) => HlTag::NumericLiteral,
437 _ => HlTag::Operator,
438 }
439 .into()
440 }
441 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
442 HlTag::Operator.into()
443 }
444 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(),
445 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
446 HlTag::Operator.into()
447 }
448 _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(),
449 _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(),
450 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(),
451 _ => HlTag::Punctuation.into(),
452 },
453
454 k if k.is_keyword() => {
455 let h = Highlight::new(HlTag::Keyword);
456 match k {
457 T![break]
458 | T![continue]
459 | T![else]
460 | T![if]
461 | T![loop]
462 | T![match]
463 | T![return]
464 | T![while]
465 | T![in] => h | HlMod::ControlFlow,
466 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow,
467 T![unsafe] => h | HlMod::Unsafe,
468 T![true] | T![false] => HlTag::BoolLiteral.into(),
469 T![self] => {
470 let self_param_is_mut = element
471 .parent()
472 .and_then(ast::SelfParam::cast)
473 .and_then(|p| p.mut_token())
474 .is_some();
475 let self_path = &element
476 .parent()
477 .as_ref()
478 .and_then(SyntaxNode::parent)
479 .and_then(ast::Path::cast)
480 .and_then(|p| sema.resolve_path(&p));
481 let mut h = HlTag::Symbol(SymbolKind::SelfParam).into();
482 if self_param_is_mut
483 || matches!(self_path,
484 Some(hir::PathResolution::Local(local))
485 if local.is_self(db)
486 && (local.is_mut(db) || local.ty(db).is_mutable_reference())
487 )
488 {
489 h |= HlMod::Mutable
490 }
491
492 if let Some(hir::PathResolution::Local(local)) = self_path {
493 if is_consumed_lvalue(element, &local, db) {
494 h |= HlMod::Consuming;
495 }
496 }
497
498 h
499 }
500 T![ref] => element
501 .parent()
502 .and_then(ast::IdentPat::cast)
503 .and_then(|ident_pat| {
504 if sema.is_unsafe_ident_pat(&ident_pat) {
505 Some(HlMod::Unsafe)
506 } else {
507 None
508 }
509 })
510 .map(|modifier| h | modifier)
511 .unwrap_or(h),
512 _ => h,
513 }
514 }
515
516 _ => return None,
517 };
518
519 return Some((highlight, binding_hash));
520
521 fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 {
522 fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
523 use std::{collections::hash_map::DefaultHasher, hash::Hasher};
524
525 let mut hasher = DefaultHasher::new();
526 x.hash(&mut hasher);
527 hasher.finish()
528 }
529
530 hash((name, shadow_count))
531 }
532}
533
534fn is_child_of_impl(element: &SyntaxElement) -> bool {
535 match element.parent() {
536 Some(e) => e.kind() == IMPL,
537 _ => false,
538 }
539}
540
541fn highlight_func_by_name_ref(
542 sema: &Semantics<RootDatabase>,
543 name_ref: &ast::NameRef,
544) -> Option<Highlight> {
545 let method_call = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
546 highlight_method_call(sema, &method_call)
547}
548
549fn highlight_method_call(
550 sema: &Semantics<RootDatabase>,
551 method_call: &ast::MethodCallExpr,
552) -> Option<Highlight> {
553 let func = sema.resolve_method_call(&method_call)?;
554 let mut h = HlTag::Symbol(SymbolKind::Function).into();
555 h |= HlMod::Associated;
556 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
557 h |= HlMod::Unsafe;
558 }
559 if let Some(self_param) = func.self_param(sema.db) {
560 match self_param.access(sema.db) {
561 hir::Access::Shared => (),
562 hir::Access::Exclusive => h |= HlMod::Mutable,
563 hir::Access::Owned => {
564 if let Some(receiver_ty) =
565 method_call.receiver().and_then(|it| sema.type_of_expr(&it))
566 {
567 if !receiver_ty.is_copy(sema.db) {
568 h |= HlMod::Consuming
569 }
570 }
571 }
572 }
573 }
574 Some(h)
575}
576
577fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
578 match def {
579 Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro),
580 Definition::Field(_) => HlTag::Symbol(SymbolKind::Field),
581 Definition::ModuleDef(def) => match def {
582 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module),
583 hir::ModuleDef::Function(func) => {
584 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
585 if func.as_assoc_item(db).is_some() {
586 h |= HlMod::Associated;
587 if func.self_param(db).is_none() {
588 h |= HlMod::Static
589 }
590 }
591 if func.is_unsafe(db) {
592 h |= HlMod::Unsafe;
593 }
594 return h;
595 }
596 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct),
597 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum),
598 hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union),
599 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant),
600 hir::ModuleDef::Const(konst) => {
601 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
602 if konst.as_assoc_item(db).is_some() {
603 h |= HlMod::Associated
604 }
605 return h;
606 }
607 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
608 hir::ModuleDef::TypeAlias(type_) => {
609 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
610 if type_.as_assoc_item(db).is_some() {
611 h |= HlMod::Associated
612 }
613 return h;
614 }
615 hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType,
616 hir::ModuleDef::Static(s) => {
617 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
618 if s.is_mut(db) {
619 h |= HlMod::Mutable;
620 h |= HlMod::Unsafe;
621 }
622 return h;
623 }
624 },
625 Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl),
626 Definition::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam),
627 Definition::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam),
628 Definition::Local(local) => {
629 let tag = if local.is_param(db) {
630 HlTag::Symbol(SymbolKind::ValueParam)
631 } else {
632 HlTag::Symbol(SymbolKind::Local)
633 };
634 let mut h = Highlight::new(tag);
635 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
636 h |= HlMod::Mutable;
637 }
638 if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) {
639 h |= HlMod::Callable;
640 }
641 return h;
642 }
643 Definition::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam),
644 Definition::Label(_) => HlTag::Symbol(SymbolKind::Label),
645 }
646 .into()
647}
648
649fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
650 let default = HlTag::UnresolvedReference;
651
652 let parent = match name.syntax().parent() {
653 Some(it) => it,
654 _ => return default.into(),
655 };
656
657 let tag = match parent.kind() {
658 STRUCT => HlTag::Symbol(SymbolKind::Struct),
659 ENUM => HlTag::Symbol(SymbolKind::Enum),
660 VARIANT => HlTag::Symbol(SymbolKind::Variant),
661 UNION => HlTag::Symbol(SymbolKind::Union),
662 TRAIT => HlTag::Symbol(SymbolKind::Trait),
663 TYPE_ALIAS => HlTag::Symbol(SymbolKind::TypeAlias),
664 TYPE_PARAM => HlTag::Symbol(SymbolKind::TypeParam),
665 RECORD_FIELD => HlTag::Symbol(SymbolKind::Field),
666 MODULE => HlTag::Symbol(SymbolKind::Module),
667 FN => HlTag::Symbol(SymbolKind::Function),
668 CONST => HlTag::Symbol(SymbolKind::Const),
669 STATIC => HlTag::Symbol(SymbolKind::Static),
670 IDENT_PAT => HlTag::Symbol(SymbolKind::Local),
671 _ => default,
672 };
673
674 tag.into()
675}
676
677fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
678 let default = HlTag::UnresolvedReference;
679
680 let parent = match name.syntax().parent() {
681 Some(it) => it,
682 _ => return default.into(),
683 };
684
685 match parent.kind() {
686 METHOD_CALL_EXPR => {
687 return ast::MethodCallExpr::cast(parent)
688 .and_then(|method_call| highlight_method_call(sema, &method_call))
689 .unwrap_or_else(|| HlTag::Symbol(SymbolKind::Function).into());
690 }
691 FIELD_EXPR => {
692 let h = HlTag::Symbol(SymbolKind::Field);
693 let is_union = ast::FieldExpr::cast(parent)
694 .and_then(|field_expr| {
695 let field = sema.resolve_field(&field_expr)?;
696 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
697 true
698 } else {
699 false
700 })
701 })
702 .unwrap_or(false);
703 if is_union {
704 h | HlMod::Unsafe
705 } else {
706 h.into()
707 }
708 }
709 PATH_SEGMENT => {
710 let path = match parent.parent().and_then(ast::Path::cast) {
711 Some(it) => it,
712 _ => return default.into(),
713 };
714 let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
715 Some(it) => it,
716 _ => {
717 // within path, decide whether it is module or adt by checking for uppercase name
718 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
719 HlTag::Symbol(SymbolKind::Struct)
720 } else {
721 HlTag::Symbol(SymbolKind::Module)
722 }
723 .into();
724 }
725 };
726 let parent = match expr.syntax().parent() {
727 Some(it) => it,
728 None => return default.into(),
729 };
730
731 match parent.kind() {
732 CALL_EXPR => HlTag::Symbol(SymbolKind::Function).into(),
733 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
734 HlTag::Symbol(SymbolKind::Struct)
735 } else {
736 HlTag::Symbol(SymbolKind::Const)
737 }
738 .into(),
739 }
740 }
741 _ => default.into(),
742 }
743}
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index d807ad0ad..a74ca844b 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -1,60 +1,48 @@
1//! Syntax highlighting for format macro strings. 1//! Syntax highlighting for format macro strings.
2use syntax::{ 2use syntax::{
3 ast::{self, FormatSpecifier, HasFormatSpecifier}, 3 ast::{self, FormatSpecifier, HasFormatSpecifier},
4 AstNode, AstToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, 4 AstNode, AstToken, TextRange,
5}; 5};
6 6
7use crate::{HlRange, HlTag, SymbolKind}; 7use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind};
8 8
9use super::highlights::Highlights; 9pub(super) fn highlight_format_string(
10 stack: &mut Highlights,
11 string: &ast::String,
12 range: TextRange,
13) {
14 if is_format_string(string).is_none() {
15 return;
16 }
10 17
11#[derive(Default)] 18 string.lex_format_specifier(|piece_range, kind| {
12pub(super) struct FormatStringHighlighter { 19 if let Some(highlight) = highlight_format_specifier(kind) {
13 format_string: Option<SyntaxElement>, 20 stack.add(HlRange {
21 range: piece_range + range.start(),
22 highlight: highlight.into(),
23 binding_hash: None,
24 });
25 }
26 });
14} 27}
15 28
16impl FormatStringHighlighter { 29fn is_format_string(string: &ast::String) -> Option<()> {
17 pub(super) fn check_for_format_string(&mut self, parent: &SyntaxNode) { 30 let parent = string.syntax().parent();
18 // Check if macro takes a format string and remember it for highlighting later. 31
19 // The macros that accept a format string expand to a compiler builtin macros 32 let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?;
20 // `format_args` and `format_args_nl`. 33 if !matches!(name.text().as_str(), "format_args" | "format_args_nl") {
21 if let Some(name) = parent 34 return None;
22 .parent()
23 .and_then(ast::MacroCall::cast)
24 .and_then(|mc| mc.path())
25 .and_then(|p| p.segment())
26 .and_then(|s| s.name_ref())
27 {
28 match name.text().as_str() {
29 "format_args" | "format_args_nl" => {
30 self.format_string = parent
31 .children_with_tokens()
32 .filter(|t| t.kind() != SyntaxKind::WHITESPACE)
33 .nth(1)
34 .filter(|e| ast::String::can_cast(e.kind()))
35 }
36 _ => {}
37 }
38 }
39 } 35 }
40 pub(super) fn highlight_format_string( 36
41 &self, 37 let first_literal = parent
42 stack: &mut Highlights, 38 .children_with_tokens()
43 string: &impl HasFormatSpecifier, 39 .filter_map(|it| it.as_token().cloned().and_then(ast::String::cast))
44 range: TextRange, 40 .next()?;
45 ) { 41 if &first_literal != string {
46 if self.format_string.as_ref() == Some(&SyntaxElement::from(string.syntax().clone())) { 42 return None;
47 string.lex_format_specifier(|piece_range, kind| {
48 if let Some(highlight) = highlight_format_specifier(kind) {
49 stack.add(HlRange {
50 range: piece_range + range.start(),
51 highlight: highlight.into(),
52 binding_hash: None,
53 });
54 }
55 });
56 }
57 } 43 }
44
45 Some(())
58} 46}
59 47
60fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { 48fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {
@@ -70,7 +58,9 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {
70 | FormatSpecifier::Dot 58 | FormatSpecifier::Dot
71 | FormatSpecifier::Asterisk 59 | FormatSpecifier::Asterisk
72 | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier, 60 | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier,
61
73 FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, 62 FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral,
63
74 FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), 64 FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local),
75 }) 65 })
76} 66}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
new file mode 100644
index 000000000..34bae49a8
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -0,0 +1,530 @@
1//! Computes color for a single element.
2
3use hir::{AsAssocItem, Semantics, VariantDef};
4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase,
7};
8use rustc_hash::FxHashMap;
9use syntax::{
10 ast, AstNode, AstToken, NodeOrToken, SyntaxElement,
11 SyntaxKind::{self, *},
12 SyntaxNode, SyntaxToken, T,
13};
14
15use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag, SymbolKind};
16
17pub(super) fn element(
18 sema: &Semantics<RootDatabase>,
19 bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
20 syntactic_name_ref_highlighting: bool,
21 element: SyntaxElement,
22) -> Option<(Highlight, Option<u64>)> {
23 let db = sema.db;
24 let mut binding_hash = None;
25 let highlight: Highlight = match element.kind() {
26 FN => {
27 bindings_shadow_count.clear();
28 return None;
29 }
30
31 // Highlight definitions depending on the "type" of the definition.
32 NAME => {
33 let name = element.into_node().and_then(ast::Name::cast).unwrap();
34 let name_kind = NameClass::classify(sema, &name);
35
36 if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
37 if let Some(name) = local.name(db) {
38 let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
39 *shadow_count += 1;
40 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
41 }
42 };
43
44 match name_kind {
45 Some(NameClass::ExternCrate(_)) => HlTag::Symbol(SymbolKind::Module).into(),
46 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
47 Some(NameClass::ConstReference(def)) => highlight_def(db, def),
48 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
49 let mut h = HlTag::Symbol(SymbolKind::Field).into();
50 if let Definition::Field(field) = field_ref {
51 if let VariantDef::Union(_) = field.parent_def(db) {
52 h |= HlMod::Unsafe;
53 }
54 }
55
56 h
57 }
58 None => highlight_name_by_syntax(name) | HlMod::Definition,
59 }
60 }
61
62 // Highlight references like the definitions they resolve to
63 NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => {
64 // even though we track whether we are in an attribute or not we still need this special case
65 // as otherwise we would emit unresolved references for name refs inside attributes
66 Highlight::from(HlTag::Symbol(SymbolKind::Function))
67 }
68 NAME_REF => {
69 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
70 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
71 match NameRefClass::classify(sema, &name_ref) {
72 Some(name_kind) => match name_kind {
73 NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(),
74 NameRefClass::Definition(def) => {
75 if let Definition::Local(local) = &def {
76 if let Some(name) = local.name(db) {
77 let shadow_count =
78 bindings_shadow_count.entry(name.clone()).or_default();
79 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
80 }
81 };
82
83 let mut h = highlight_def(db, def);
84
85 if let Definition::Local(local) = &def {
86 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) {
87 h |= HlMod::Consuming;
88 }
89 }
90
91 if let Some(parent) = name_ref.syntax().parent() {
92 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
93 if let Definition::Field(field) = def {
94 if let VariantDef::Union(_) = field.parent_def(db) {
95 h |= HlMod::Unsafe;
96 }
97 }
98 }
99 }
100
101 h
102 }
103 NameRefClass::FieldShorthand { .. } => {
104 HlTag::Symbol(SymbolKind::Field).into()
105 }
106 },
107 None if syntactic_name_ref_highlighting => {
108 highlight_name_ref_by_syntax(name_ref, sema)
109 }
110 None => HlTag::UnresolvedReference.into(),
111 }
112 })
113 }
114
115 // Simple token-based highlighting
116 COMMENT => {
117 let comment = element.into_token().and_then(ast::Comment::cast)?;
118 let h = HlTag::Comment;
119 match comment.kind().doc {
120 Some(_) => h | HlMod::Documentation,
121 None => h.into(),
122 }
123 }
124 STRING | BYTE_STRING => HlTag::StringLiteral.into(),
125 ATTR => HlTag::Attribute.into(),
126 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
127 BYTE => HlTag::ByteLiteral.into(),
128 CHAR => HlTag::CharLiteral.into(),
129 QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow,
130 LIFETIME => {
131 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
132
133 match NameClass::classify_lifetime(sema, &lifetime) {
134 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
135 None => match NameRefClass::classify_lifetime(sema, &lifetime) {
136 Some(NameRefClass::Definition(def)) => highlight_def(db, def),
137 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)),
138 },
139 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | HlMod::Definition,
140 }
141 }
142 p if p.is_punct() => match p {
143 T![&] => {
144 let h = HlTag::Operator.into();
145 let is_unsafe = element
146 .parent()
147 .and_then(ast::RefExpr::cast)
148 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
149 .unwrap_or(false);
150 if is_unsafe {
151 h | HlMod::Unsafe
152 } else {
153 h
154 }
155 }
156 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(),
157 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
158 HlTag::Symbol(SymbolKind::Macro).into()
159 }
160 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
161 HlTag::BuiltinType.into()
162 }
163 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
164 HlTag::Keyword.into()
165 }
166 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
167 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
168
169 let expr = prefix_expr.expr()?;
170 let ty = sema.type_of_expr(&expr)?;
171 if ty.is_raw_ptr() {
172 HlTag::Operator | HlMod::Unsafe
173 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
174 HlTag::Operator.into()
175 } else {
176 HlTag::Punctuation(HlPunct::Other).into()
177 }
178 }
179 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
180 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
181
182 let expr = prefix_expr.expr()?;
183 match expr {
184 ast::Expr::Literal(_) => HlTag::NumericLiteral,
185 _ => HlTag::Operator,
186 }
187 .into()
188 }
189 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
190 HlTag::Operator.into()
191 }
192 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(),
193 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
194 HlTag::Operator.into()
195 }
196 _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(),
197 _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(),
198 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(),
199 kind => HlTag::Punctuation(match kind {
200 T!['['] | T![']'] => HlPunct::Bracket,
201 T!['{'] | T!['}'] => HlPunct::Brace,
202 T!['('] | T![')'] => HlPunct::Parenthesis,
203 T![<] | T![>] => HlPunct::Angle,
204 T![,] => HlPunct::Comma,
205 T![:] => HlPunct::Colon,
206 T![;] => HlPunct::Semi,
207 T![.] => HlPunct::Dot,
208 _ => HlPunct::Other,
209 })
210 .into(),
211 },
212
213 k if k.is_keyword() => {
214 let h = Highlight::new(HlTag::Keyword);
215 match k {
216 T![break]
217 | T![continue]
218 | T![else]
219 | T![if]
220 | T![loop]
221 | T![match]
222 | T![return]
223 | T![while]
224 | T![in] => h | HlMod::ControlFlow,
225 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow,
226 T![unsafe] => h | HlMod::Unsafe,
227 T![true] | T![false] => HlTag::BoolLiteral.into(),
228 T![self] => {
229 let self_param_is_mut = element
230 .parent()
231 .and_then(ast::SelfParam::cast)
232 .and_then(|p| p.mut_token())
233 .is_some();
234 let self_path = &element
235 .parent()
236 .as_ref()
237 .and_then(SyntaxNode::parent)
238 .and_then(ast::Path::cast)
239 .and_then(|p| sema.resolve_path(&p));
240 let mut h = HlTag::Symbol(SymbolKind::SelfParam).into();
241 if self_param_is_mut
242 || matches!(self_path,
243 Some(hir::PathResolution::Local(local))
244 if local.is_self(db)
245 && (local.is_mut(db) || local.ty(db).is_mutable_reference())
246 )
247 {
248 h |= HlMod::Mutable
249 }
250
251 if let Some(hir::PathResolution::Local(local)) = self_path {
252 if is_consumed_lvalue(element, &local, db) {
253 h |= HlMod::Consuming;
254 }
255 }
256
257 h
258 }
259 T![ref] => element
260 .parent()
261 .and_then(ast::IdentPat::cast)
262 .and_then(|ident_pat| {
263 if sema.is_unsafe_ident_pat(&ident_pat) {
264 Some(HlMod::Unsafe)
265 } else {
266 None
267 }
268 })
269 .map(|modifier| h | modifier)
270 .unwrap_or(h),
271 _ => h,
272 }
273 }
274
275 _ => return None,
276 };
277
278 return Some((highlight, binding_hash));
279
280 fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
281 fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
282 use std::{collections::hash_map::DefaultHasher, hash::Hasher};
283
284 let mut hasher = DefaultHasher::new();
285 x.hash(&mut hasher);
286 hasher.finish()
287 }
288
289 hash((name, shadow_count))
290 }
291}
292
293fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
294 match def {
295 Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro),
296 Definition::Field(_) => HlTag::Symbol(SymbolKind::Field),
297 Definition::ModuleDef(def) => match def {
298 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module),
299 hir::ModuleDef::Function(func) => {
300 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
301 if func.as_assoc_item(db).is_some() {
302 h |= HlMod::Associated;
303 if func.self_param(db).is_none() {
304 h |= HlMod::Static
305 }
306 }
307 if func.is_unsafe(db) {
308 h |= HlMod::Unsafe;
309 }
310 return h;
311 }
312 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct),
313 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum),
314 hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union),
315 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant),
316 hir::ModuleDef::Const(konst) => {
317 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
318 if konst.as_assoc_item(db).is_some() {
319 h |= HlMod::Associated
320 }
321 return h;
322 }
323 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
324 hir::ModuleDef::TypeAlias(type_) => {
325 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
326 if type_.as_assoc_item(db).is_some() {
327 h |= HlMod::Associated
328 }
329 return h;
330 }
331 hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType,
332 hir::ModuleDef::Static(s) => {
333 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
334 if s.is_mut(db) {
335 h |= HlMod::Mutable;
336 h |= HlMod::Unsafe;
337 }
338 return h;
339 }
340 },
341 Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl),
342 Definition::GenericParam(it) => match it {
343 hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam),
344 hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam),
345 hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam),
346 },
347 Definition::Local(local) => {
348 let tag = if local.is_param(db) {
349 HlTag::Symbol(SymbolKind::ValueParam)
350 } else {
351 HlTag::Symbol(SymbolKind::Local)
352 };
353 let mut h = Highlight::new(tag);
354 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
355 h |= HlMod::Mutable;
356 }
357 if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) {
358 h |= HlMod::Callable;
359 }
360 return h;
361 }
362 Definition::Label(_) => HlTag::Symbol(SymbolKind::Label),
363 }
364 .into()
365}
366
367fn highlight_func_by_name_ref(
368 sema: &Semantics<RootDatabase>,
369 name_ref: &ast::NameRef,
370) -> Option<Highlight> {
371 let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
372 highlight_method_call(sema, &mc)
373}
374
375fn highlight_method_call(
376 sema: &Semantics<RootDatabase>,
377 method_call: &ast::MethodCallExpr,
378) -> Option<Highlight> {
379 let func = sema.resolve_method_call(&method_call)?;
380 let mut h = HlTag::Symbol(SymbolKind::Function).into();
381 h |= HlMod::Associated;
382 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
383 h |= HlMod::Unsafe;
384 }
385 if let Some(self_param) = func.self_param(sema.db) {
386 match self_param.access(sema.db) {
387 hir::Access::Shared => (),
388 hir::Access::Exclusive => h |= HlMod::Mutable,
389 hir::Access::Owned => {
390 if let Some(receiver_ty) =
391 method_call.receiver().and_then(|it| sema.type_of_expr(&it))
392 {
393 if !receiver_ty.is_copy(sema.db) {
394 h |= HlMod::Consuming
395 }
396 }
397 }
398 }
399 }
400 Some(h)
401}
402
403fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
404 let default = HlTag::UnresolvedReference;
405
406 let parent = match name.syntax().parent() {
407 Some(it) => it,
408 _ => return default.into(),
409 };
410
411 let tag = match parent.kind() {
412 STRUCT => HlTag::Symbol(SymbolKind::Struct),
413 ENUM => HlTag::Symbol(SymbolKind::Enum),
414 VARIANT => HlTag::Symbol(SymbolKind::Variant),
415 UNION => HlTag::Symbol(SymbolKind::Union),
416 TRAIT => HlTag::Symbol(SymbolKind::Trait),
417 TYPE_ALIAS => HlTag::Symbol(SymbolKind::TypeAlias),
418 TYPE_PARAM => HlTag::Symbol(SymbolKind::TypeParam),
419 RECORD_FIELD => HlTag::Symbol(SymbolKind::Field),
420 MODULE => HlTag::Symbol(SymbolKind::Module),
421 FN => HlTag::Symbol(SymbolKind::Function),
422 CONST => HlTag::Symbol(SymbolKind::Const),
423 STATIC => HlTag::Symbol(SymbolKind::Static),
424 IDENT_PAT => HlTag::Symbol(SymbolKind::Local),
425 _ => default,
426 };
427
428 tag.into()
429}
430
431fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
432 let default = HlTag::UnresolvedReference;
433
434 let parent = match name.syntax().parent() {
435 Some(it) => it,
436 _ => return default.into(),
437 };
438
439 match parent.kind() {
440 METHOD_CALL_EXPR => {
441 return ast::MethodCallExpr::cast(parent)
442 .and_then(|it| highlight_method_call(sema, &it))
443 .unwrap_or_else(|| HlTag::Symbol(SymbolKind::Function).into());
444 }
445 FIELD_EXPR => {
446 let h = HlTag::Symbol(SymbolKind::Field);
447 let is_union = ast::FieldExpr::cast(parent)
448 .and_then(|field_expr| {
449 let field = sema.resolve_field(&field_expr)?;
450 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
451 true
452 } else {
453 false
454 })
455 })
456 .unwrap_or(false);
457 if is_union {
458 h | HlMod::Unsafe
459 } else {
460 h.into()
461 }
462 }
463 PATH_SEGMENT => {
464 let path = match parent.parent().and_then(ast::Path::cast) {
465 Some(it) => it,
466 _ => return default.into(),
467 };
468 let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
469 Some(it) => it,
470 _ => {
471 // within path, decide whether it is module or adt by checking for uppercase name
472 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
473 HlTag::Symbol(SymbolKind::Struct)
474 } else {
475 HlTag::Symbol(SymbolKind::Module)
476 }
477 .into();
478 }
479 };
480 let parent = match expr.syntax().parent() {
481 Some(it) => it,
482 None => return default.into(),
483 };
484
485 match parent.kind() {
486 CALL_EXPR => HlTag::Symbol(SymbolKind::Function).into(),
487 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
488 HlTag::Symbol(SymbolKind::Struct)
489 } else {
490 HlTag::Symbol(SymbolKind::Const)
491 }
492 .into(),
493 }
494 }
495 _ => default.into(),
496 }
497}
498
499fn is_consumed_lvalue(
500 node: NodeOrToken<SyntaxNode, SyntaxToken>,
501 local: &hir::Local,
502 db: &RootDatabase,
503) -> bool {
504 // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming.
505 parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db)
506}
507
508/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly.
509fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool {
510 while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) {
511 if parent.kind() != *kind {
512 return false;
513 }
514
515 // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value
516 // in the same pattern is unstable: rust-lang/rust#68354.
517 node = node.parent().unwrap().into();
518 kinds = rest;
519 }
520
521 // Only true if we matched all expected kinds
522 kinds.len() == 0
523}
524
525fn is_child_of_impl(element: &SyntaxElement) -> bool {
526 match element.parent() {
527 Some(e) => e.kind() == IMPL,
528 _ => false,
529 }
530}
diff --git a/crates/ide/src/syntax_highlighting/highlights.rs b/crates/ide/src/syntax_highlighting/highlights.rs
index 11c11ed28..c6f0417ec 100644
--- a/crates/ide/src/syntax_highlighting/highlights.rs
+++ b/crates/ide/src/syntax_highlighting/highlights.rs
@@ -51,18 +51,20 @@ impl Node {
51 } 51 }
52 } 52 }
53 53
54 let (start, len) = 54 let overlapping =
55 equal_range_by(&self.nested, |n| ordering(n.hl_range.range, hl_range.range)); 55 equal_range_by(&self.nested, |n| ordering(n.hl_range.range, hl_range.range));
56 56
57 if len == 1 && self.nested[start].hl_range.range.contains_range(hl_range.range) { 57 if overlapping.len() == 1
58 return self.nested[start].add(hl_range); 58 && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range)
59 {
60 return self.nested[overlapping.start].add(hl_range);
59 } 61 }
60 62
61 let nested = self 63 let nested = self
62 .nested 64 .nested
63 .splice(start..start + len, iter::once(Node::new(hl_range))) 65 .splice(overlapping.clone(), iter::once(Node::new(hl_range)))
64 .collect::<Vec<_>>(); 66 .collect::<Vec<_>>();
65 self.nested[start].nested = nested; 67 self.nested[overlapping.start].nested = nested;
66 } 68 }
67 69
68 fn flatten(&self, acc: &mut Vec<HlRange>) { 70 fn flatten(&self, acc: &mut Vec<HlRange>) {
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 008d5ce24..281461493 100644
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -1,17 +1,14 @@
1//! Syntax highlighting injections such as highlighting of documentation tests. 1//! "Recursive" Syntax highlighting for code in doctests and fixtures.
2
3use std::convert::TryFrom;
4 2
5use hir::Semantics; 3use hir::Semantics;
6use ide_db::call_info::ActiveParameter; 4use ide_db::call_info::ActiveParameter;
7use itertools::Itertools;
8use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; 5use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
9 6
10use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; 7use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase};
11 8
12use super::{highlights::Highlights, injector::Injector}; 9use super::{highlights::Highlights, injector::Injector};
13 10
14pub(super) fn highlight_injection( 11pub(super) fn ra_fixture(
15 hl: &mut Highlights, 12 hl: &mut Highlights,
16 sema: &Semantics<RootDatabase>, 13 sema: &Semantics<RootDatabase>,
17 literal: ast::String, 14 literal: ast::String,
@@ -84,107 +81,78 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
84 "edition2021", 81 "edition2021",
85]; 82];
86 83
87/// Extracts Rust code from documentation comments as well as a mapping from 84/// Injection of syntax highlighting of doctests.
88/// the extracted source code back to the original source ranges. 85pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) {
89/// Lastly, a vector of new comment highlight ranges (spanning only the 86 let doc_comments = node
90/// comment prefix) is returned which is used in the syntax highlighting 87 .children_with_tokens()
91/// injection to replace the previous (line-spanning) comment ranges. 88 .filter_map(|it| it.into_token().and_then(ast::Comment::cast))
92pub(super) fn extract_doc_comments(node: &SyntaxNode) -> Option<(Vec<HlRange>, Injector)> { 89 .filter(|it| it.kind().doc.is_some());
90
91 if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) {
92 return;
93 }
94
93 let mut inj = Injector::default(); 95 let mut inj = Injector::default();
94 // wrap the doctest into function body to get correct syntax highlighting 96 inj.add_unmapped("fn doctest() {\n");
95 let prefix = "fn doctest() {\n";
96 let suffix = "}\n";
97 97
98 let mut line_start = TextSize::of(prefix);
99 let mut is_codeblock = false; 98 let mut is_codeblock = false;
100 let mut is_doctest = false; 99 let mut is_doctest = false;
100
101 // Replace the original, line-spanning comment ranges by new, only comment-prefix 101 // Replace the original, line-spanning comment ranges by new, only comment-prefix
102 // spanning comment ranges. 102 // spanning comment ranges.
103 let mut new_comments = Vec::new(); 103 let mut new_comments = Vec::new();
104 104 for comment in doc_comments {
105 inj.add_unmapped(prefix); 105 match comment.text().find(RUSTDOC_FENCE) {
106 let doctest = node 106 Some(idx) => {
107 .children_with_tokens()
108 .filter_map(|el| el.into_token().and_then(ast::Comment::cast))
109 .filter(|comment| comment.kind().doc.is_some())
110 .filter(|comment| {
111 if let Some(idx) = comment.text().find(RUSTDOC_FENCE) {
112 is_codeblock = !is_codeblock; 107 is_codeblock = !is_codeblock;
113 // Check whether code is rust by inspecting fence guards 108 // Check whether code is rust by inspecting fence guards
114 let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; 109 let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..];
115 let is_rust = 110 let is_rust =
116 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); 111 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
117 is_doctest = is_codeblock && is_rust; 112 is_doctest = is_codeblock && is_rust;
118 false 113 continue;
119 } else {
120 is_doctest
121 } 114 }
122 }) 115 None if !is_doctest => continue,
123 .map(|comment| { 116 None => (),
124 let prefix_len = comment.prefix().len(); 117 }
125 let line: &str = comment.text().as_str();
126 let range = comment.syntax().text_range();
127
128 // whitespace after comment is ignored
129 let pos = if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) {
130 prefix_len + ws.len_utf8()
131 } else {
132 prefix_len
133 };
134
135 // lines marked with `#` should be ignored in output, we skip the `#` char
136 let pos = if let Some(ws) = line.chars().nth(pos).filter(|&c| c == '#') {
137 pos + ws.len_utf8()
138 } else {
139 pos
140 };
141
142 new_comments.push(HlRange {
143 range: TextRange::new(
144 range.start(),
145 range.start() + TextSize::try_from(pos).unwrap(),
146 ),
147 highlight: HlTag::Comment | HlMod::Documentation,
148 binding_hash: None,
149 });
150 line_start += range.len() - TextSize::try_from(pos).unwrap();
151 line_start += TextSize::of("\n");
152
153 inj.add(
154 &line[pos..],
155 TextRange::new(range.start() + TextSize::try_from(pos).unwrap(), range.end()),
156 );
157 inj.add_unmapped("\n");
158 line[pos..].to_owned()
159 })
160 .join("\n");
161 inj.add_unmapped(suffix);
162
163 if doctest.is_empty() {
164 return None;
165 }
166 118
167 Some((new_comments, inj)) 119 let line: &str = comment.text().as_str();
168} 120 let range = comment.syntax().text_range();
169 121
170/// Injection of syntax highlighting of doctests. 122 let mut pos = TextSize::of(comment.prefix());
171pub(super) fn highlight_doc_comment( 123 // whitespace after comment is ignored
172 new_comments: Vec<HlRange>, 124 if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) {
173 inj: Injector, 125 pos += TextSize::of(ws);
174 stack: &mut Highlights, 126 }
175) { 127 // lines marked with `#` should be ignored in output, we skip the `#` char
176 let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); 128 if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') {
177 for comment in new_comments { 129 pos += TextSize::of(ws);
178 stack.add(comment); 130 }
131
132 new_comments.push(TextRange::at(range.start(), pos));
133
134 inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end()));
135 inj.add_unmapped("\n");
179 } 136 }
137 inj.add_unmapped("\n}");
138
139 let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string());
180 140
181 for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { 141 for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() {
182 for r in inj.map_range_up(h.range) { 142 for r in inj.map_range_up(h.range) {
183 stack.add(HlRange { 143 hl.add(HlRange {
184 range: r, 144 range: r,
185 highlight: h.highlight | HlMod::Injected, 145 highlight: h.highlight | HlMod::Injected,
186 binding_hash: h.binding_hash, 146 binding_hash: h.binding_hash,
187 }); 147 });
188 } 148 }
189 } 149 }
150
151 for range in new_comments {
152 hl.add(HlRange {
153 range,
154 highlight: HlTag::Comment | HlMod::Documentation,
155 binding_hash: None,
156 });
157 }
190} 158}
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs
index e8f17eb69..fd4025694 100644
--- a/crates/ide/src/syntax_highlighting/injector.rs
+++ b/crates/ide/src/syntax_highlighting/injector.rs
@@ -33,8 +33,7 @@ impl Injector {
33 &self.buf 33 &self.buf
34 } 34 }
35 pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { 35 pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
36 let (start, len) = equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)); 36 equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)).filter_map(move |i| {
37 (start..start + len).filter_map(move |i| {
38 let (target_range, delta) = self.ranges[i]; 37 let (target_range, delta) = self.ranges[i];
39 let intersection = target_range.intersect(range).unwrap(); 38 let intersection = target_range.intersect(range).unwrap();
40 Some(intersection + delta?) 39 Some(intersection + delta?)
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_rules.rs
index 21d8a9835..44620e912 100644
--- a/crates/ide/src/syntax_highlighting/macro_rules.rs
+++ b/crates/ide/src/syntax_highlighting/macro_rules.rs
@@ -119,7 +119,7 @@ fn is_metavariable(element: SyntaxElement) -> Option<TextRange> {
119 let tok = element.as_token()?; 119 let tok = element.as_token()?;
120 match tok.kind() { 120 match tok.kind() {
121 kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { 121 kind if kind == SyntaxKind::IDENT || kind.is_keyword() => {
122 if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == SyntaxKind::DOLLAR) { 122 if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == T![$]) {
123 return Some(tok.text_range()); 123 return Some(tok.text_range());
124 } 124 }
125 } 125 }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 2f39bcc8e..8dd05ac52 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -29,7 +29,7 @@ pub enum HlTag {
29 EscapeSequence, 29 EscapeSequence,
30 FormatSpecifier, 30 FormatSpecifier,
31 Keyword, 31 Keyword,
32 Punctuation, 32 Punctuation(HlPunct),
33 Operator, 33 Operator,
34 UnresolvedReference, 34 UnresolvedReference,
35 35
@@ -61,6 +61,28 @@ pub enum HlMod {
61 Unsafe, 61 Unsafe,
62} 62}
63 63
64#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
65pub enum HlPunct {
66 /// []
67 Bracket,
68 /// {}
69 Brace,
70 /// ()
71 Parenthesis,
72 /// <>
73 Angle,
74 /// ,
75 Comma,
76 /// .
77 Dot,
78 /// :
79 Colon,
80 /// ;
81 Semi,
82 ///
83 Other,
84}
85
64impl HlTag { 86impl HlTag {
65 fn as_str(self) -> &'static str { 87 fn as_str(self) -> &'static str {
66 match self { 88 match self {
@@ -95,7 +117,17 @@ impl HlTag {
95 HlTag::EscapeSequence => "escape_sequence", 117 HlTag::EscapeSequence => "escape_sequence",
96 HlTag::FormatSpecifier => "format_specifier", 118 HlTag::FormatSpecifier => "format_specifier",
97 HlTag::Keyword => "keyword", 119 HlTag::Keyword => "keyword",
98 HlTag::Punctuation => "punctuation", 120 HlTag::Punctuation(punct) => match punct {
121 HlPunct::Bracket => "bracket",
122 HlPunct::Brace => "brace",
123 HlPunct::Parenthesis => "parenthesis",
124 HlPunct::Angle => "angle",
125 HlPunct::Comma => "comma",
126 HlPunct::Dot => "dot",
127 HlPunct::Colon => "colon",
128 HlPunct::Semi => "semicolon",
129 HlPunct::Other => "punctuation",
130 },
99 HlTag::NumericLiteral => "numeric_literal", 131 HlTag::NumericLiteral => "numeric_literal",
100 HlTag::Operator => "operator", 132 HlTag::Operator => "operator",
101 HlTag::StringLiteral => "string_literal", 133 HlTag::StringLiteral => "string_literal",
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 506ebe60e..e36e6fc3f 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -36,22 +36,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40 40
41<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span> 41<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="brace">{</span><span class="brace">}</span>
42 42
43<span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span> 43<span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span>
44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
46<span class="punctuation">}</span> 46<span class="brace">}</span>
47 47
48<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span> 48<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
49 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 49 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
50 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 50 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51<span class="punctuation">}</span> 51<span class="brace">}</span>
52 52
53<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="punctuation">{</span> 53<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56<span class="punctuation">}</span> 56<span class="brace">}</span>
57 </code></pre> \ No newline at end of file 57 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 7d1d2a839..6dadda1c1 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -37,72 +37,72 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="comment documentation">/// ```</span> 39<pre><code><span class="comment documentation">/// ```</span>
40<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="punctuation injected">;</span> 40<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="semicolon injected">;</span>
41<span class="comment documentation">/// ```</span> 41<span class="comment documentation">/// ```</span>
42<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> 42<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span>
43 <span class="field declaration">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span><span class="punctuation">,</span> 43 <span class="field declaration">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span><span class="comma">,</span>
44<span class="punctuation">}</span> 44<span class="brace">}</span>
45 45
46<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 46<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
47 <span class="comment documentation">/// ```</span> 47 <span class="comment documentation">/// ```</span>
48 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Call me</span> 48 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Call me</span>
49 <span class="comment">// KILLER WHALE</span> 49 <span class="comment">// KILLER WHALE</span>
50 <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="punctuation injected">;</span> 50 <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="semicolon injected">;</span>
51 <span class="comment documentation">/// ```</span> 51 <span class="comment documentation">/// ```</span>
52 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="punctuation">;</span> 52 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span>
53 53
54 <span class="comment documentation">/// Constructs a new `Foo`.</span> 54 <span class="comment documentation">/// Constructs a new `Foo`.</span>
55 <span class="comment documentation">///</span> 55 <span class="comment documentation">///</span>
56 <span class="comment documentation">/// # Examples</span> 56 <span class="comment documentation">/// # Examples</span>
57 <span class="comment documentation">///</span> 57 <span class="comment documentation">///</span>
58 <span class="comment documentation">/// ```</span> 58 <span class="comment documentation">/// ```</span>
59 <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="punctuation attribute injected">)</span><span class="attribute attribute injected">]</span> 59 <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute attribute injected">]</span>
60 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 60 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
61 <span class="comment documentation">/// ```</span> 61 <span class="comment documentation">/// ```</span>
62 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 62 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
63 <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span> 63 <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span>
64 <span class="punctuation">}</span> 64 <span class="brace">}</span>
65 65
66 <span class="comment documentation">/// `bar` method on `Foo`.</span> 66 <span class="comment documentation">/// `bar` method on `Foo`.</span>
67 <span class="comment documentation">///</span> 67 <span class="comment documentation">///</span>
68 <span class="comment documentation">/// # Examples</span> 68 <span class="comment documentation">/// # Examples</span>
69 <span class="comment documentation">///</span> 69 <span class="comment documentation">///</span>
70 <span class="comment documentation">/// ```</span> 70 <span class="comment documentation">/// ```</span>
71 <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="none injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="punctuation injected">;</span> 71 <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="none injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="semicolon injected">;</span>
72 <span class="comment documentation">///</span> 72 <span class="comment documentation">///</span>
73 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 73 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
74 <span class="comment documentation">///</span> 74 <span class="comment documentation">///</span>
75 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> 75 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span>
76 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="punctuation injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 76 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
77 <span class="comment documentation">///</span> 77 <span class="comment documentation">///</span>
78 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="punctuation injected">;</span> 78 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span>
79 <span class="comment documentation">///</span> 79 <span class="comment documentation">///</span>
80 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> 80 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span>
81 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> 81 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span>
82 <span class="comment documentation">///</span> 82 <span class="comment documentation">///</span>
83 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span> 83 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span>
84 <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span> 84 <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span>
85 <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="punctuation injected">;</span> 85 <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="semicolon injected">;</span>
86 <span class="comment documentation">///</span> 86 <span class="comment documentation">///</span>
87 <span class="comment documentation">/// ```</span> 87 <span class="comment documentation">/// ```</span>
88 <span class="comment documentation">///</span> 88 <span class="comment documentation">///</span>
89 <span class="comment documentation">/// ```rust,no_run</span> 89 <span class="comment documentation">/// ```rust,no_run</span>
90 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 90 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
91 <span class="comment documentation">/// ```</span> 91 <span class="comment documentation">/// ```</span>
92 <span class="comment documentation">///</span> 92 <span class="comment documentation">///</span>
93 <span class="comment documentation">/// ```sh</span> 93 <span class="comment documentation">/// ```sh</span>
94 <span class="comment documentation">/// echo 1</span> 94 <span class="comment documentation">/// echo 1</span>
95 <span class="comment documentation">/// ```</span> 95 <span class="comment documentation">/// ```</span>
96 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="punctuation">{</span> 96 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
97 <span class="bool_literal">true</span> 97 <span class="bool_literal">true</span>
98 <span class="punctuation">}</span> 98 <span class="brace">}</span>
99<span class="punctuation">}</span> 99<span class="brace">}</span>
100 100
101<span class="comment documentation">/// ```</span> 101<span class="comment documentation">/// ```</span>
102<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 102<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
103<span class="comment documentation">/// ```</span> 103<span class="comment documentation">/// ```</span>
104<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> 104<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
105 <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 105 <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
106 <span class="punctuation">$</span>expr 106 <span class="punctuation">$</span>expr
107 <span class="punctuation">}</span> 107 <span class="brace">}</span>
108<span class="punctuation">}</span></code></pre> \ No newline at end of file 108<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index ed452586a..6f7a7ffff 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -36,6 +36,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span> 39<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="semicolon">;</span>
40<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span> 40<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="semicolon">;</span>
41</code></pre> \ No newline at end of file 41</code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 92e7dc3e4..753b535b5 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -36,14 +36,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40 40
41<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 41<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
42 <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> 42 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
43 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> 43 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span>
44 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 44 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
45 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> 45 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span>
46 <span class="punctuation">}</span> 46 <span class="brace">}</span>
47 <span class="punctuation">}</span><span class="string_literal">"#</span> 47 <span class="brace">}</span><span class="string_literal">"#</span>
48 <span class="punctuation">)</span><span class="punctuation">;</span> 48 <span class="parenthesis">)</span><span class="semicolon">;</span>
49<span class="punctuation">}</span></code></pre> \ No newline at end of file 49<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 31dad5d42..66d80c4b6 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -36,64 +36,64 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span> 39<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
40 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span> 40 <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="brace">{</span>
41 <span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> 41 <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
42 <span class="punctuation">}</span><span class="punctuation">)</span> 42 <span class="brace">}</span><span class="parenthesis">)</span>
43<span class="punctuation">}</span> 43<span class="brace">}</span>
44<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> 44<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
45<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span> 45<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span>
46 <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> 46 <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span>
47 <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> 47 <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>args<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span>
48<span class="punctuation">}</span> 48<span class="brace">}</span>
49 49
50<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 50<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
51 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> 51 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
52 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "Hello"</span> 52 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "Hello"</span>
53 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "Hello, world!"</span> 53 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "Hello, world!"</span>
54 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "The number is 1"</span> 54 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "The number is 1"</span>
55 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="numeric_literal">3</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "(3, 4)"</span> 55 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="parenthesis">(</span><span class="numeric_literal">3</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "(3, 4)"</span>
56 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "4"</span> 56 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "4"</span>
57 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "1 2"</span> 57 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "1 2"</span>
58 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">42</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "0042" with leading zerosV</span> 58 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">42</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "0042" with leading zerosV</span>
59 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "2 1 1 2"</span> 59 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1 1 2"</span>
60 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "test"</span> 60 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "test"</span>
61 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "2 1"</span> 61 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1"</span>
62 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="punctuation">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="punctuation">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "a 3 b"</span> 62 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="comma">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="comma">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "a 3 b"</span>
63 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "{2}"</span> 63 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "{2}"</span>
64 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 64 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
65 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 65 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 66 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
67 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 67 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
68 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 68 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
69 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 69 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
70 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 70 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
71 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 71 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
72 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 72 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
73 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> 73 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span>
74 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 74 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
75 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 75 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
76 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> 76 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span>
77 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 77 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
78 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 78 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
79 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 79 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
80 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 80 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
81 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 81 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
82 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 82 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="comma">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
83 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="punctuation">)</span><span class="punctuation">;</span> 83 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="parenthesis">)</span><span class="semicolon">;</span>
84 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> 84 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
85 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> 85 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
86 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello {{}}"</span><span class="punctuation">)</span><span class="punctuation">;</span> 86 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello {{}}"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
87 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{ Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> 87 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{ Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
88 88
89 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> 89 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
90 90
91 <span class="comment">// escape sequences</span> 91 <span class="comment">// escape sequences</span>
92 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="punctuation">)</span><span class="punctuation">;</span> 92 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
93 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="punctuation">)</span><span class="punctuation">;</span> 93 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
94 94
95 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 95 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
96 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 96 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
97 97
98 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="punctuation">,</span> thingy<span class="punctuation">,</span> n2<span class="punctuation">)</span><span class="punctuation">;</span> 98 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="comma">,</span> thingy<span class="comma">,</span> n2<span class="parenthesis">)</span><span class="semicolon">;</span>
99<span class="punctuation">}</span></code></pre> \ No newline at end of file 99<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index e3a0aa317..9d4d6d4a0 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -36,65 +36,65 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40 40
41<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span> 41<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="brace">{</span>
42 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> 42 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
43 <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span> 43 <span class="field declaration">b</span><span class="colon">:</span> <span class="builtin_type">f32</span><span class="comma">,</span>
44<span class="punctuation">}</span> 44<span class="brace">}</span>
45 45
46<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> 46<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span>
47 47
48<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> 48<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span>
49 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 49 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
50<span class="punctuation">}</span> 50<span class="brace">}</span>
51 51
52<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span> 52<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span>
53 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u8</span> 53 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u8</span>
54<span class="punctuation">}</span> 54<span class="brace">}</span>
55 55
56<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> 56<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="colon">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
57 57
58<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="punctuation attribute">(</span><span class="attribute attribute">packed</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> 58<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
59<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="punctuation">{</span> 59<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
60 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u16</span><span class="punctuation">,</span> 60 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
61<span class="punctuation">}</span> 61<span class="brace">}</span>
62 62
63<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span> 63<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
64 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span><span class="punctuation">;</span> 64 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
65<span class="punctuation">}</span> 65<span class="brace">}</span>
66 66
67<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="punctuation">{</span> 67<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
68 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 68 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
69<span class="punctuation">}</span> 69<span class="brace">}</span>
70 70
71<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 71<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
72 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> 72 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
73 <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> 73 <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
74 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 74 <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
75 <span class="comment">// unsafe fn and method calls</span> 75 <span class="comment">// unsafe fn and method calls</span>
76 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 76 <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
77 <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="punctuation">;</span> 77 <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
78 <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span> 78 <span class="keyword control">match</span> <span class="variable">u</span> <span class="brace">{</span>
79 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> 79 <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
80 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> 80 <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
81 <span class="punctuation">}</span> 81 <span class="brace">}</span>
82 <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 82 <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
83 83
84 <span class="comment">// unsafe deref</span> 84 <span class="comment">// unsafe deref</span>
85 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="punctuation">;</span> 85 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
86 86
87 <span class="comment">// unsafe access to a static mut</span> 87 <span class="comment">// unsafe access to a static mut</span>
88 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> 88 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
89 89
90 <span class="comment">// unsafe ref of packed fields</span> 90 <span class="comment">// unsafe ref of packed fields</span>
91 <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> 91 <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
92 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> 92 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
93 <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> 93 <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
94 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> 94 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
95 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> 95 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
96 96
97 <span class="comment">// unsafe auto ref of packed field</span> 97 <span class="comment">// unsafe auto ref of packed field</span>
98 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 98 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
99 <span class="punctuation">}</span> 99 <span class="brace">}</span>
100<span class="punctuation">}</span></code></pre> \ No newline at end of file 100<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 02270b077..6b7447c46 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -36,187 +36,187 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="punctuation">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="punctuation">}</span><span class="punctuation">;</span> 39<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
40<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="punctuation">{</span><span class="punctuation">}</span> 40<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
41 41
42<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> 42<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
43<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> 43<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
44 44
45<span class="comment">// Needed for function consuming vs normal</span> 45<span class="comment">// Needed for function consuming vs normal</span>
46<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="punctuation">{</span> 46<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span>
47 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span> 47 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span>
48 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> 48 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
49<span class="punctuation">}</span> 49<span class="brace">}</span>
50 50
51<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="punctuation">{</span> 51<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="brace">{</span>
52 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span> 52 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span>
53 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="punctuation">&lt;</span><span class="type_param declaration">Args</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">}</span> 53 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
54 54
55 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span> 55 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span>
56 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="punctuation">&lt;</span><span class="type_param declaration">Args</span><span class="punctuation">&gt;</span><span class="punctuation">:</span> <span class="trait">FnOnce</span><span class="punctuation">&lt;</span><span class="type_param">Args</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">}</span> 56 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait">FnOnce</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
57 57
58 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span> 58 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span>
59 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="punctuation">&lt;</span><span class="type_param declaration">Args</span><span class="punctuation">&gt;</span><span class="punctuation">:</span> <span class="trait">FnMut</span><span class="punctuation">&lt;</span><span class="type_param">Args</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">}</span> 59 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait">FnMut</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
60<span class="punctuation">}</span> 60<span class="brace">}</span>
61 61
62 62
63<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> 63<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span>
64 <span class="keyword">pub</span> <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> 64 <span class="keyword">pub</span> <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span>
65 <span class="keyword">pub</span> <span class="field declaration">y</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> 65 <span class="keyword">pub</span> <span class="field declaration">y</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span>
66<span class="punctuation">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span> 68<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="punctuation">;</span> 69 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
70<span class="punctuation">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 72<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
73 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 73 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
74 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 74 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
75 <span class="punctuation">}</span> 75 <span class="brace">}</span>
76<span class="punctuation">}</span> 76<span class="brace">}</span>
77 77
78<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 78<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
79 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 79 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
80 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span> 80 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span>
81 <span class="punctuation">}</span> 81 <span class="brace">}</span>
82 82
83 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> 83 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
84 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 84 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
85 <span class="punctuation">}</span> 85 <span class="brace">}</span>
86 86
87 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 87 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
88 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 88 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
89 <span class="punctuation">}</span> 89 <span class="brace">}</span>
90<span class="punctuation">}</span> 90<span class="brace">}</span>
91 91
92<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="punctuation attribute">(</span><span class="attribute attribute">Copy</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> 92<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="parenthesis attribute">(</span><span class="attribute attribute">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
93<span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="punctuation">{</span> 93<span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="brace">{</span>
94 <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> 94 <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
95<span class="punctuation">}</span> 95<span class="brace">}</span>
96 96
97<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> 97<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span>
98 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">FooCopy</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> 98 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
99 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> 99 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span>
100 <span class="punctuation">}</span> 100 <span class="brace">}</span>
101 101
102 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> 102 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
103 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 103 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
104 <span class="punctuation">}</span> 104 <span class="brace">}</span>
105 105
106 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> 106 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
107 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 107 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
108 <span class="punctuation">}</span> 108 <span class="brace">}</span>
109<span class="punctuation">}</span> 109<span class="brace">}</span>
110 110
111<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 111<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
112 112
113<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">&lt;</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="punctuation">{</span> 113<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="angle">&lt;</span><span class="lifetime declaration">'a</span><span class="comma">,</span> <span class="type_param declaration">T</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="brace">{</span>
114 <span class="function">foo</span><span class="operator">::</span><span class="punctuation">&lt;</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> 114 <span class="function">foo</span><span class="operator">::</span><span class="angle">&lt;</span><span class="lifetime">'a</span><span class="comma">,</span> <span class="builtin_type">i32</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
115<span class="punctuation">}</span> 115<span class="brace">}</span>
116 116
117<span class="keyword">fn</span> <span class="function declaration">never</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="punctuation">{</span> 117<span class="keyword">fn</span> <span class="function declaration">never</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="brace">{</span>
118 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> 118 <span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span>
119<span class="punctuation">}</span> 119<span class="brace">}</span>
120 120
121<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="punctuation">{</span> 121<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
122 <span class="const_param">FOO</span> 122 <span class="const_param">FOO</span>
123<span class="punctuation">}</span> 123<span class="brace">}</span>
124 124
125<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> 125<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="semicolon">;</span>
126<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> 126<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param declaration callable">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span>
127 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> 127 <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
128<span class="punctuation">}</span> 128<span class="brace">}</span>
129 129
130<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> 130<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="brace">{</span><span class="brace">}</span>
131 131
132<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 132<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
133 <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 133 <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
134<span class="punctuation">}</span> 134<span class="brace">}</span>
135 135
136<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span> 136<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span>
137 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span> 137 <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span>
138<span class="punctuation">}</span> 138<span class="brace">}</span>
139 139
140<span class="macro">def_fn!</span> <span class="punctuation">{</span> 140<span class="macro">def_fn!</span> <span class="brace">{</span>
141 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-</span><span class="operator">&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> 141 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-</span><span class="operator">&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
142 <span class="numeric_literal">100</span> 142 <span class="numeric_literal">100</span>
143 <span class="punctuation">}</span> 143 <span class="brace">}</span>
144<span class="punctuation">}</span> 144<span class="brace">}</span>
145 145
146<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> 146<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
147 <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 147 <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
148 <span class="punctuation">$</span>expr 148 <span class="punctuation">$</span>expr
149 <span class="punctuation">}</span> 149 <span class="brace">}</span>
150<span class="punctuation">}</span> 150<span class="brace">}</span>
151 151
152<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span> 152<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span>
153 <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span> 153 <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span>
154<span class="punctuation">}</span> 154<span class="brace">}</span>
155 155
156<span class="comment">// comment</span> 156<span class="comment">// comment</span>
157<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 157<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
158 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 158 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
159 159
160 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 160 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
161 <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="punctuation">{</span> 161 <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="brace">{</span>
162 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">;</span> 162 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="semicolon">;</span>
163 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="punctuation">(</span><span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="numeric_literal">1</span> <span class="punctuation">}</span><span class="punctuation">)</span><span class="punctuation">;</span> 163 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="parenthesis">(</span><span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="numeric_literal">1</span> <span class="brace">}</span><span class="parenthesis">)</span><span class="semicolon">;</span>
164 <span class="punctuation">}</span> 164 <span class="brace">}</span>
165 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 165 <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
166 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> 166 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="parenthesis">(</span><span class="numeric_literal">0</span><span class="parenthesis">)</span><span class="semicolon">;</span>
167 <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> 167 <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
168 <span class="punctuation">}</span> 168 <span class="brace">}</span>
169 169
170 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> 170 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="brace">{</span>
171 <span class="comment">// Do nothing</span> 171 <span class="comment">// Do nothing</span>
172 <span class="punctuation">}</span> 172 <span class="brace">}</span>
173 173
174 <span class="macro">noop!</span><span class="punctuation">(</span><span class="macro">noop</span><span class="macro">!</span><span class="punctuation">(</span><span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> 174 <span class="macro">noop!</span><span class="parenthesis">(</span><span class="macro">noop</span><span class="macro">!</span><span class="parenthesis">(</span><span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
175 175
176 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="punctuation">;</span> 176 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="semicolon">;</span>
177 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span> 177 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="semicolon">;</span>
178 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="punctuation">;</span> 178 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="semicolon">;</span>
179 179
180 <span class="keyword">let</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable declaration">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span><span class="punctuation">;</span> 180 <span class="keyword">let</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable declaration">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span><span class="semicolon">;</span>
181 181
182 <span class="variable">y</span><span class="punctuation">;</span> 182 <span class="variable">y</span><span class="semicolon">;</span>
183 183
184 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> 184 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
185 <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> 185 <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
186 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 186 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
187 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 187 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
188 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span> 188 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span>
189 189
190 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> <span class="field">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> 190 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span>
191 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 191 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
192 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 192 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
193 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span> 193 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span>
194 194
195 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="punctuation">;</span> 195 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span>
196 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="punctuation">;</span> 196 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span>
197 197
198 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="punctuation">;</span> 198 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span>
199 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span> 199 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span>
200 200
201 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span> 201 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
202 202
203 <span class="label declaration">'foo</span><span class="punctuation">:</span> <span class="keyword control">loop</span> <span class="punctuation">{</span> 203 <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span>
204 <span class="keyword control">break</span> <span class="label">'foo</span><span class="punctuation">;</span> 204 <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span>
205 <span class="keyword control">continue</span> <span class="label">'foo</span><span class="punctuation">;</span> 205 <span class="keyword control">continue</span> <span class="label">'foo</span><span class="semicolon">;</span>
206 <span class="punctuation">}</span> 206 <span class="brace">}</span>
207<span class="punctuation">}</span> 207<span class="brace">}</span>
208 208
209<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 209<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
210 <span class="enum_variant declaration">Some</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">)</span><span class="punctuation">,</span> 210 <span class="enum_variant declaration">Some</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="comma">,</span>
211 <span class="enum_variant declaration">None</span><span class="punctuation">,</span> 211 <span class="enum_variant declaration">None</span><span class="comma">,</span>
212<span class="punctuation">}</span> 212<span class="brace">}</span>
213<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span> 213<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
214 214
215<span class="keyword">impl</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="type_param">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 215<span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
216 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="punctuation">&lt;</span><span class="type_param declaration">U</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">other</span><span class="punctuation">:</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="type_param">U</span><span class="punctuation">&gt;</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">,</span> <span class="type_param">U</span><span class="punctuation">)</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 216 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span>
217 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span> 217 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span>
218 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> 218 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
219 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="punctuation">,</span> 219 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span>
220 <span class="punctuation">}</span> 220 <span class="brace">}</span>
221 <span class="punctuation">}</span> 221 <span class="brace">}</span>
222<span class="punctuation">}</span></code></pre> \ No newline at end of file 222<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html
index 6703a84e5..78dfec951 100644
--- a/crates/ide/src/syntax_highlighting/test_data/injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/injection.html
@@ -36,13 +36,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 40<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
41 <span class="function">f</span><span class="punctuation">(</span><span class="string_literal">r"</span> 41 <span class="function">f</span><span class="parenthesis">(</span><span class="string_literal">r"</span>
42<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 42<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
43 <span class="function">foo</span><span class="punctuation">(</span><span class="keyword">$0</span><span class="punctuation">{</span> 43 <span class="function">foo</span><span class="parenthesis">(</span><span class="keyword">$0</span><span class="brace">{</span>
44 <span class="numeric_literal">92</span> 44 <span class="numeric_literal">92</span>
45 <span class="punctuation">}</span><span class="keyword">$0</span><span class="punctuation">)</span> 45 <span class="brace">}</span><span class="keyword">$0</span><span class="parenthesis">)</span>
46<span class="punctuation">}</span><span class="string_literal">"</span><span class="punctuation">)</span><span class="punctuation">;</span> 46<span class="brace">}</span><span class="string_literal">"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
47<span class="punctuation">}</span> 47<span class="brace">}</span>
48 </code></pre> \ No newline at end of file 48 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
index 8b3dfa69f..e64f2e5e9 100644
--- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
@@ -36,15 +36,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
40 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> 40 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
41 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 41 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
42 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 42 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
43 43
44 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="punctuation">;</span> 44 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span>
45 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 45 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
46<span class="punctuation">}</span> 46<span class="brace">}</span>
47 47
48<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 48<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
49 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> 49 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
50<span class="punctuation">}</span></code></pre> \ No newline at end of file 50<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index be1c64b03..d68fe42b0 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -6,8 +6,8 @@
6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). 6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
7 7
8use hir::{ 8use hir::{
9 db::HirDatabase, ConstParam, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, 9 db::HirDatabase, Crate, Field, GenericParam, HasVisibility, Impl, Label, Local, MacroDef,
10 MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, 10 Module, ModuleDef, Name, PathResolution, Semantics, Visibility,
11}; 11};
12use syntax::{ 12use syntax::{
13 ast::{self, AstNode}, 13 ast::{self, AstNode},
@@ -24,9 +24,7 @@ pub enum Definition {
24 ModuleDef(ModuleDef), 24 ModuleDef(ModuleDef),
25 SelfType(Impl), 25 SelfType(Impl),
26 Local(Local), 26 Local(Local),
27 TypeParam(TypeParam), 27 GenericParam(GenericParam),
28 LifetimeParam(LifetimeParam),
29 ConstParam(ConstParam),
30 Label(Label), 28 Label(Label),
31} 29}
32 30
@@ -38,9 +36,7 @@ impl Definition {
38 Definition::ModuleDef(it) => it.module(db), 36 Definition::ModuleDef(it) => it.module(db),
39 Definition::SelfType(it) => Some(it.module(db)), 37 Definition::SelfType(it) => Some(it.module(db)),
40 Definition::Local(it) => Some(it.module(db)), 38 Definition::Local(it) => Some(it.module(db)),
41 Definition::TypeParam(it) => Some(it.module(db)), 39 Definition::GenericParam(it) => Some(it.module(db)),
42 Definition::LifetimeParam(it) => Some(it.module(db)),
43 Definition::ConstParam(it) => Some(it.module(db)),
44 Definition::Label(it) => Some(it.module(db)), 40 Definition::Label(it) => Some(it.module(db)),
45 } 41 }
46 } 42 }
@@ -52,9 +48,7 @@ impl Definition {
52 Definition::ModuleDef(def) => def.definition_visibility(db), 48 Definition::ModuleDef(def) => def.definition_visibility(db),
53 Definition::SelfType(_) => None, 49 Definition::SelfType(_) => None,
54 Definition::Local(_) => None, 50 Definition::Local(_) => None,
55 Definition::TypeParam(_) => None, 51 Definition::GenericParam(_) => None,
56 Definition::LifetimeParam(_) => None,
57 Definition::ConstParam(_) => None,
58 Definition::Label(_) => None, 52 Definition::Label(_) => None,
59 } 53 }
60 } 54 }
@@ -80,9 +74,7 @@ impl Definition {
80 }, 74 },
81 Definition::SelfType(_) => return None, 75 Definition::SelfType(_) => return None,
82 Definition::Local(it) => it.name(db)?, 76 Definition::Local(it) => it.name(db)?,
83 Definition::TypeParam(it) => it.name(db), 77 Definition::GenericParam(it) => it.name(db),
84 Definition::LifetimeParam(it) => it.name(db),
85 Definition::ConstParam(it) => it.name(db),
86 Definition::Label(it) => it.name(db), 78 Definition::Label(it) => it.name(db),
87 }; 79 };
88 Some(name) 80 Some(name)
@@ -235,11 +227,11 @@ impl NameClass {
235 }, 227 },
236 ast::TypeParam(it) => { 228 ast::TypeParam(it) => {
237 let def = sema.to_def(&it)?; 229 let def = sema.to_def(&it)?;
238 Some(NameClass::Definition(Definition::TypeParam(def))) 230 Some(NameClass::Definition(Definition::GenericParam(def.into())))
239 }, 231 },
240 ast::ConstParam(it) => { 232 ast::ConstParam(it) => {
241 let def = sema.to_def(&it)?; 233 let def = sema.to_def(&it)?;
242 Some(NameClass::Definition(Definition::ConstParam(def))) 234 Some(NameClass::Definition(Definition::GenericParam(def.into())))
243 }, 235 },
244 _ => None, 236 _ => None,
245 } 237 }
@@ -257,7 +249,7 @@ impl NameClass {
257 match parent { 249 match parent {
258 ast::LifetimeParam(it) => { 250 ast::LifetimeParam(it) => {
259 let def = sema.to_def(&it)?; 251 let def = sema.to_def(&it)?;
260 Some(NameClass::Definition(Definition::LifetimeParam(def))) 252 Some(NameClass::Definition(Definition::GenericParam(def.into())))
261 }, 253 },
262 ast::Label(it) => { 254 ast::Label(it) => {
263 let def = sema.to_def(&it)?; 255 let def = sema.to_def(&it)?;
@@ -393,7 +385,8 @@ impl NameRefClass {
393 | SyntaxKind::WHERE_PRED 385 | SyntaxKind::WHERE_PRED
394 | SyntaxKind::REF_TYPE => sema 386 | SyntaxKind::REF_TYPE => sema
395 .resolve_lifetime_param(lifetime) 387 .resolve_lifetime_param(lifetime)
396 .map(Definition::LifetimeParam) 388 .map(GenericParam::LifetimeParam)
389 .map(Definition::GenericParam)
397 .map(NameRefClass::Definition), 390 .map(NameRefClass::Definition),
398 // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check 391 // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
399 // if our lifetime is in a LifetimeParam without being the constrained lifetime 392 // if our lifetime is in a LifetimeParam without being the constrained lifetime
@@ -401,7 +394,8 @@ impl NameRefClass {
401 != Some(lifetime) => 394 != Some(lifetime) =>
402 { 395 {
403 sema.resolve_lifetime_param(lifetime) 396 sema.resolve_lifetime_param(lifetime)
404 .map(Definition::LifetimeParam) 397 .map(GenericParam::LifetimeParam)
398 .map(Definition::GenericParam)
405 .map(NameRefClass::Definition) 399 .map(NameRefClass::Definition)
406 } 400 }
407 _ => None, 401 _ => None,
@@ -422,10 +416,10 @@ impl From<PathResolution> for Definition {
422 Definition::ModuleDef(def) 416 Definition::ModuleDef(def)
423 } 417 }
424 PathResolution::Local(local) => Definition::Local(local), 418 PathResolution::Local(local) => Definition::Local(local),
425 PathResolution::TypeParam(par) => Definition::TypeParam(par), 419 PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
426 PathResolution::Macro(def) => Definition::Macro(def), 420 PathResolution::Macro(def) => Definition::Macro(def),
427 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), 421 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
428 PathResolution::ConstParam(par) => Definition::ConstParam(par), 422 PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
429 } 423 }
430 } 424 }
431} 425}
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 37b06027c..773bfbc2c 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -136,7 +136,7 @@ impl Definition {
136 return SearchScope::new(res); 136 return SearchScope::new(res);
137 } 137 }
138 138
139 if let Definition::LifetimeParam(param) = self { 139 if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
140 let range = match param.parent(db) { 140 let range = match param.parent(db) {
141 hir::GenericDef::Function(it) => { 141 hir::GenericDef::Function(it) => {
142 it.source(db).and_then(|src| Some(src.value.syntax().text_range())) 142 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index c7a3556a7..d61950b96 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -15,8 +15,16 @@ use super::*;
15// let _ = b"e"; 15// let _ = b"e";
16// let _ = br"f"; 16// let _ = br"f";
17// } 17// }
18pub(crate) const LITERAL_FIRST: TokenSet = 18pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[
19 TokenSet::new(&[TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR, STRING, BYTE_STRING]); 19 T![true],
20 T![false],
21 INT_NUMBER,
22 FLOAT_NUMBER,
23 BYTE,
24 CHAR,
25 STRING,
26 BYTE_STRING,
27]);
20 28
21pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { 29pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
22 if !p.at_ts(LITERAL_FIRST) { 30 if !p.at_ts(LITERAL_FIRST) {
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index cf4168d32..2070ce163 100644
--- a/crates/parser/src/grammar/items.rs
+++ b/crates/parser/src/grammar/items.rs
@@ -27,19 +27,19 @@ pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
27} 27}
28 28
29pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ 29pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[
30 FN_KW, 30 T![fn],
31 STRUCT_KW, 31 T![struct],
32 ENUM_KW, 32 T![enum],
33 IMPL_KW, 33 T![impl],
34 TRAIT_KW, 34 T![trait],
35 CONST_KW, 35 T![const],
36 STATIC_KW, 36 T![static],
37 LET_KW, 37 T![let],
38 MOD_KW, 38 T![mod],
39 PUB_KW, 39 T![pub],
40 CRATE_KW, 40 T![crate],
41 USE_KW, 41 T![use],
42 MACRO_KW, 42 T![macro],
43 T![;], 43 T![;],
44]); 44]);
45 45
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs
index ab9a12b4d..d076974ed 100644
--- a/crates/parser/src/grammar/items/traits.rs
+++ b/crates/parser/src/grammar/items/traits.rs
@@ -110,7 +110,7 @@ fn choose_type_params_over_qpath(p: &Parser) -> bool {
110 if !p.at(T![<]) { 110 if !p.at(T![<]) {
111 return false; 111 return false;
112 } 112 }
113 if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW { 113 if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == T![const] {
114 return true; 114 return true;
115 } 115 }
116 (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT) 116 (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT)
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs
index b53d5749f..da71498a8 100644
--- a/crates/parser/src/grammar/patterns.rs
+++ b/crates/parser/src/grammar/patterns.rs
@@ -83,7 +83,7 @@ fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
83} 83}
84 84
85const PAT_RECOVERY_SET: TokenSet = 85const PAT_RECOVERY_SET: TokenSet =
86 TokenSet::new(&[LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]); 86 TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,]]);
87 87
88fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { 88fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
89 let m = match p.nth(0) { 89 let m = match p.nth(0) {
diff --git a/crates/parser/src/grammar/type_args.rs b/crates/parser/src/grammar/type_args.rs
index a013c49b9..42cd426bd 100644
--- a/crates/parser/src/grammar/type_args.rs
+++ b/crates/parser/src/grammar/type_args.rs
@@ -26,7 +26,7 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) {
26} 26}
27 27
28// test type_arg 28// test type_arg
29// type A = B<'static, i32, 1, { 2 }, Item=u64>; 29// type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>;
30fn generic_arg(p: &mut Parser) { 30fn generic_arg(p: &mut Parser) {
31 let m = p.start(); 31 let m = p.start();
32 match p.current() { 32 match p.current() {
@@ -55,6 +55,10 @@ fn generic_arg(p: &mut Parser) {
55 expressions::literal(p); 55 expressions::literal(p);
56 m.complete(p, CONST_ARG); 56 m.complete(p, CONST_ARG);
57 } 57 }
58 T![true] | T![false] => {
59 expressions::literal(p);
60 m.complete(p, CONST_ARG);
61 }
58 _ => { 62 _ => {
59 types::type_(p); 63 types::type_(p);
60 m.complete(p, TYPE_ARG); 64 m.complete(p, TYPE_ARG);
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs
index 4aeccd193..3de5248da 100644
--- a/crates/parser/src/grammar/type_params.rs
+++ b/crates/parser/src/grammar/type_params.rs
@@ -25,7 +25,7 @@ fn generic_param_list(p: &mut Parser) {
25 match p.current() { 25 match p.current() {
26 LIFETIME_IDENT => lifetime_param(p, m), 26 LIFETIME_IDENT => lifetime_param(p, m),
27 IDENT => type_param(p, m), 27 IDENT => type_param(p, m),
28 CONST_KW => const_param(p, m), 28 T![const] => const_param(p, m),
29 _ => { 29 _ => {
30 m.abandon(p); 30 m.abandon(p);
31 p.err_and_bump("expected type parameter") 31 p.err_and_bump("expected type parameter")
@@ -66,7 +66,7 @@ fn type_param(p: &mut Parser, m: Marker) {
66// test const_param 66// test const_param
67// struct S<const N: u32>; 67// struct S<const N: u32>;
68fn const_param(p: &mut Parser, m: Marker) { 68fn const_param(p: &mut Parser, m: Marker) {
69 assert!(p.at(CONST_KW)); 69 assert!(p.at(T![const]));
70 p.bump(T![const]); 70 p.bump(T![const]);
71 name(p); 71 name(p);
72 types::ascription(p); 72 types::ascription(p);
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 9445aec07..30811bbbf 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -302,7 +302,7 @@ impl AnalysisStatsCmd {
302 report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); 302 report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
303 } 303 }
304 304
305 if self.memory_usage { 305 if self.memory_usage && verbosity.is_verbose() {
306 print_memory_usage(host, vfs); 306 print_memory_usage(host, vfs);
307 } 307 }
308 308
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 1f6bf1c8c..442fbd14c 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -22,6 +22,7 @@ use crate::{
22 from_proto, 22 from_proto,
23 line_endings::LineEndings, 23 line_endings::LineEndings,
24 main_loop::Task, 24 main_loop::Task,
25 op_queue::OpQueue,
25 reload::SourceRootConfig, 26 reload::SourceRootConfig,
26 request_metrics::{LatestRequests, RequestMetrics}, 27 request_metrics::{LatestRequests, RequestMetrics},
27 thread_pool::TaskPool, 28 thread_pool::TaskPool,
@@ -78,6 +79,7 @@ pub(crate) struct GlobalState {
78 pub(crate) source_root_config: SourceRootConfig, 79 pub(crate) source_root_config: SourceRootConfig,
79 pub(crate) proc_macro_client: Option<ProcMacroClient>, 80 pub(crate) proc_macro_client: Option<ProcMacroClient>,
80 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, 81 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
82 pub(crate) fetch_workspaces_queue: OpQueue,
81 latest_requests: Arc<RwLock<LatestRequests>>, 83 latest_requests: Arc<RwLock<LatestRequests>>,
82} 84}
83 85
@@ -130,6 +132,7 @@ impl GlobalState {
130 source_root_config: SourceRootConfig::default(), 132 source_root_config: SourceRootConfig::default(),
131 proc_macro_client: None, 133 proc_macro_client: None,
132 workspaces: Arc::new(Vec::new()), 134 workspaces: Arc::new(Vec::new()),
135 fetch_workspaces_queue: OpQueue::default(),
133 latest_requests: Default::default(), 136 latest_requests: Default::default(),
134 } 137 }
135 } 138 }
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index c9494e300..2207b9a87 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -35,6 +35,7 @@ mod lsp_utils;
35mod thread_pool; 35mod thread_pool;
36mod document; 36mod document;
37mod diff; 37mod diff;
38mod op_queue;
38pub mod lsp_ext; 39pub mod lsp_ext;
39pub mod config; 40pub mod config;
40 41
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 22ee96775..51fb2eb74 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -11,7 +11,6 @@ use ide::{Canceled, FileId};
11use ide_db::base_db::VfsPath; 11use ide_db::base_db::VfsPath;
12use lsp_server::{Connection, Notification, Request, Response}; 12use lsp_server::{Connection, Notification, Request, Response};
13use lsp_types::notification::Notification as _; 13use lsp_types::notification::Notification as _;
14use project_model::ProjectWorkspace;
15use vfs::ChangeKind; 14use vfs::ChangeKind;
16 15
17use crate::{ 16use crate::{
@@ -62,7 +61,6 @@ enum Event {
62pub(crate) enum Task { 61pub(crate) enum Task {
63 Response(Response), 62 Response(Response),
64 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), 63 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
65 Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
66 PrimeCaches(PrimeCachesProgress), 64 PrimeCaches(PrimeCachesProgress),
67 FetchWorkspace(ProjectWorkspaceProgress), 65 FetchWorkspace(ProjectWorkspaceProgress),
68} 66}
@@ -143,7 +141,8 @@ impl GlobalState {
143 |_, _| (), 141 |_, _| (),
144 ); 142 );
145 143
146 self.fetch_workspaces(); 144 self.fetch_workspaces_request();
145 self.fetch_workspaces_if_needed();
147 146
148 while let Some(event) = self.next_event(&inbox) { 147 while let Some(event) = self.next_event(&inbox) {
149 if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { 148 if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
@@ -204,7 +203,6 @@ impl GlobalState {
204 self.diagnostics.set_native_diagnostics(file_id, diagnostics) 203 self.diagnostics.set_native_diagnostics(file_id, diagnostics)
205 } 204 }
206 } 205 }
207 Task::Workspaces(workspaces) => self.switch_workspaces(workspaces),
208 Task::PrimeCaches(progress) => match progress { 206 Task::PrimeCaches(progress) => match progress {
209 PrimeCachesProgress::Started => prime_caches_progress.push(progress), 207 PrimeCachesProgress::Started => prime_caches_progress.push(progress),
210 PrimeCachesProgress::StartedOnCrate { .. } => { 208 PrimeCachesProgress::StartedOnCrate { .. } => {
@@ -224,7 +222,11 @@ impl GlobalState {
224 ProjectWorkspaceProgress::Report(msg) => { 222 ProjectWorkspaceProgress::Report(msg) => {
225 (Progress::Report, Some(msg)) 223 (Progress::Report, Some(msg))
226 } 224 }
227 ProjectWorkspaceProgress::End => (Progress::End, None), 225 ProjectWorkspaceProgress::End(workspaces) => {
226 self.fetch_workspaces_completed();
227 self.switch_workspaces(workspaces);
228 (Progress::End, None)
229 }
228 }; 230 };
229 self.report_progress("fetching", state, msg, None); 231 self.report_progress("fetching", state, msg, None);
230 } 232 }
@@ -403,6 +405,8 @@ impl GlobalState {
403 } 405 }
404 } 406 }
405 407
408 self.fetch_workspaces_if_needed();
409
406 let loop_duration = loop_start.elapsed(); 410 let loop_duration = loop_start.elapsed();
407 if loop_duration > Duration::from_millis(100) { 411 if loop_duration > Duration::from_millis(100) {
408 log::warn!("overly long loop turn: {:?}", loop_duration); 412 log::warn!("overly long loop turn: {:?}", loop_duration);
@@ -440,7 +444,7 @@ impl GlobalState {
440 } 444 }
441 445
442 RequestDispatcher { req: Some(req), global_state: self } 446 RequestDispatcher { req: Some(req), global_state: self }
443 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? 447 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))?
444 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 448 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
445 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 449 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
446 .on_sync::<lsp_types::request::Shutdown>(|s, ()| { 450 .on_sync::<lsp_types::request::Shutdown>(|s, ()| {
diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs
new file mode 100644
index 000000000..51d66f4b3
--- /dev/null
+++ b/crates/rust-analyzer/src/op_queue.rs
@@ -0,0 +1,25 @@
1//! Bookkeeping to make sure only one long-running operation is executed.
2
3#[derive(Default)]
4pub(crate) struct OpQueue {
5 op_scheduled: bool,
6 op_in_progress: bool,
7}
8
9impl OpQueue {
10 pub(crate) fn request_op(&mut self) {
11 self.op_scheduled = true;
12 }
13 pub(crate) fn should_start_op(&mut self) -> bool {
14 if !self.op_in_progress && self.op_scheduled {
15 self.op_in_progress = true;
16 self.op_scheduled = false;
17 return true;
18 }
19 false
20 }
21 pub(crate) fn op_completed(&mut self) {
22 assert!(self.op_in_progress);
23 self.op_in_progress = false;
24 }
25}
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index f4e084741..accf2ef8c 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -19,7 +19,7 @@ use lsp_ext::StatusParams;
19pub(crate) enum ProjectWorkspaceProgress { 19pub(crate) enum ProjectWorkspaceProgress {
20 Begin, 20 Begin,
21 Report(String), 21 Report(String),
22 End, 22 End(Vec<anyhow::Result<ProjectWorkspace>>),
23} 23}
24 24
25impl GlobalState { 25impl GlobalState {
@@ -30,7 +30,7 @@ impl GlobalState {
30 self.analysis_host.update_lru_capacity(self.config.lru_capacity()); 30 self.analysis_host.update_lru_capacity(self.config.lru_capacity());
31 } 31 }
32 if self.config.linked_projects() != old_config.linked_projects() { 32 if self.config.linked_projects() != old_config.linked_projects() {
33 self.fetch_workspaces() 33 self.fetch_workspaces_request()
34 } else if self.config.flycheck() != old_config.flycheck() { 34 } else if self.config.flycheck() != old_config.flycheck() {
35 self.reload_flycheck(); 35 self.reload_flycheck();
36 } 36 }
@@ -44,7 +44,7 @@ impl GlobalState {
44 Status::Ready | Status::Invalid => (), 44 Status::Ready | Status::Invalid => (),
45 } 45 }
46 if self.config.cargo_autoreload() { 46 if self.config.cargo_autoreload() {
47 self.fetch_workspaces(); 47 self.fetch_workspaces_request();
48 } else { 48 } else {
49 self.transition(Status::NeedsReload); 49 self.transition(Status::NeedsReload);
50 } 50 }
@@ -98,8 +98,15 @@ impl GlobalState {
98 }); 98 });
99 } 99 }
100 } 100 }
101 pub(crate) fn fetch_workspaces(&mut self) { 101
102 pub(crate) fn fetch_workspaces_request(&mut self) {
103 self.fetch_workspaces_queue.request_op()
104 }
105 pub(crate) fn fetch_workspaces_if_needed(&mut self) {
102 log::info!("will fetch workspaces"); 106 log::info!("will fetch workspaces");
107 if !self.fetch_workspaces_queue.should_start_op() {
108 return;
109 }
103 110
104 self.task_pool.handle.spawn_with_sender({ 111 self.task_pool.handle.spawn_with_sender({
105 let linked_projects = self.config.linked_projects(); 112 let linked_projects = self.config.linked_projects();
@@ -133,12 +140,17 @@ impl GlobalState {
133 }) 140 })
134 .collect::<Vec<_>>(); 141 .collect::<Vec<_>>();
135 142
136 sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::End)).unwrap();
137 log::info!("did fetch workspaces {:?}", workspaces); 143 log::info!("did fetch workspaces {:?}", workspaces);
138 sender.send(Task::Workspaces(workspaces)).unwrap() 144 sender
145 .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces)))
146 .unwrap();
139 } 147 }
140 }); 148 });
141 } 149 }
150 pub(crate) fn fetch_workspaces_completed(&mut self) {
151 self.fetch_workspaces_queue.op_completed()
152 }
153
142 pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) { 154 pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
143 let _p = profile::span("GlobalState::switch_workspaces"); 155 let _p = profile::span("GlobalState::switch_workspaces");
144 log::info!("will switch workspaces: {:?}", workspaces); 156 log::info!("will switch workspaces: {:?}", workspaces);
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 5c4366f16..7ce9a4ab6 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -38,17 +38,25 @@ macro_rules! define_semantic_token_types {
38} 38}
39 39
40define_semantic_token_types![ 40define_semantic_token_types![
41 (ANGLE, "angle"),
41 (ATTRIBUTE, "attribute"), 42 (ATTRIBUTE, "attribute"),
42 (BOOLEAN, "boolean"), 43 (BOOLEAN, "boolean"),
44 (BRACE, "brace"),
45 (BRACKET, "bracket"),
43 (BUILTIN_TYPE, "builtinType"), 46 (BUILTIN_TYPE, "builtinType"),
47 (COMMA, "comma"),
48 (COLON, "colon"),
49 (DOT, "dot"),
44 (ESCAPE_SEQUENCE, "escapeSequence"), 50 (ESCAPE_SEQUENCE, "escapeSequence"),
45 (FORMAT_SPECIFIER, "formatSpecifier"), 51 (FORMAT_SPECIFIER, "formatSpecifier"),
46 (GENERIC, "generic"), 52 (GENERIC, "generic"),
47 (CONST_PARAMETER, "constParameter"), 53 (CONST_PARAMETER, "constParameter"),
48 (LIFETIME, "lifetime"), 54 (LIFETIME, "lifetime"),
49 (LABEL, "label"), 55 (LABEL, "label"),
56 (PARENTHESIS, "parenthesis"),
50 (PUNCTUATION, "punctuation"), 57 (PUNCTUATION, "punctuation"),
51 (SELF_KEYWORD, "selfKeyword"), 58 (SELF_KEYWORD, "selfKeyword"),
59 (SEMICOLON, "semicolon"),
52 (TYPE_ALIAS, "typeAlias"), 60 (TYPE_ALIAS, "typeAlias"),
53 (UNION, "union"), 61 (UNION, "union"),
54 (UNRESOLVED_REFERENCE, "unresolvedReference"), 62 (UNRESOLVED_REFERENCE, "unresolvedReference"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index d6bf60cde..bdddca9da 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -6,9 +6,9 @@ use std::{
6 6
7use ide::{ 7use ide::{
8 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, 8 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId,
9 FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlRange, HlTag, Indel, InlayHint, 9 FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, HlRange, HlTag, Indel,
10 InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, ReferenceAccess, Runnable, 10 InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, ReferenceAccess,
11 Severity, SourceChange, SourceFileEdit, SymbolKind, TextEdit, TextRange, TextSize, 11 Runnable, Severity, SourceChange, SourceFileEdit, SymbolKind, TextEdit, TextRange, TextSize,
12}; 12};
13use itertools::Itertools; 13use itertools::Itertools;
14 14
@@ -423,7 +423,17 @@ fn semantic_token_type_and_modifiers(
423 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, 423 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
424 HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, 424 HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
425 HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, 425 HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
426 HlTag::Punctuation => semantic_tokens::PUNCTUATION, 426 HlTag::Punctuation(punct) => match punct {
427 HlPunct::Bracket => semantic_tokens::BRACKET,
428 HlPunct::Brace => semantic_tokens::BRACE,
429 HlPunct::Parenthesis => semantic_tokens::PARENTHESIS,
430 HlPunct::Angle => semantic_tokens::ANGLE,
431 HlPunct::Comma => semantic_tokens::COMMA,
432 HlPunct::Dot => semantic_tokens::DOT,
433 HlPunct::Colon => semantic_tokens::COLON,
434 HlPunct::Semi => semantic_tokens::SEMICOLON,
435 HlPunct::Other => semantic_tokens::PUNCTUATION,
436 },
427 }; 437 };
428 438
429 for modifier in highlight.mods.iter() { 439 for modifier in highlight.mods.iter() {
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 5aacdb16e..13aab1451 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -152,13 +152,13 @@ where
152 left 152 left
153} 153}
154 154
155pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> (usize, usize) 155pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize>
156where 156where
157 F: FnMut(&T) -> Ordering, 157 F: FnMut(&T) -> Ordering,
158{ 158{
159 let start = partition_point(slice, |it| key(it) == Ordering::Less); 159 let start = partition_point(slice, |it| key(it) == Ordering::Less);
160 let len = partition_point(&slice[start..], |it| key(it) == Ordering::Equal); 160 let len = partition_point(&slice[start..], |it| key(it) == Ordering::Equal);
161 (start, len) 161 start..start + len
162} 162}
163 163
164pub struct JodChild(pub process::Child); 164pub struct JodChild(pub process::Child);
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 2aa472fb4..27381ba80 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -133,7 +133,7 @@ impl ast::Attr {
133 first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); 133 first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind);
134 134
135 match (first_token_kind, second_token_kind) { 135 match (first_token_kind, second_token_kind) {
136 (Some(SyntaxKind::POUND), Some(T![!])) => AttrKind::Inner, 136 (Some(T![#]), Some(T![!])) => AttrKind::Inner,
137 _ => AttrKind::Outer, 137 _ => AttrKind::Outer,
138 } 138 }
139 } 139 }
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index b3a02f4ae..bfa2dc4ba 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -344,9 +344,9 @@ fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
344 344
345 if tbl.bounds().count() > 1 { 345 if tbl.bounds().count() > 1 {
346 let dyn_token = ty.dyn_token()?; 346 let dyn_token = ty.dyn_token()?;
347 let potential_parentheses = 347 let potential_parenthesis =
348 algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; 348 algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
349 let kind = potential_parentheses.kind(); 349 let kind = potential_parenthesis.kind();
350 if !matches!(kind, T!['('] | T![<] | T![=]) { 350 if !matches!(kind, T!['('] | T![<] | T![=]) {
351 return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); 351 return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
352 } 352 }
diff --git a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast
index 51e881a8e..68c0f1c66 100644
--- a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast
@@ -1,5 +1,5 @@
1SOURCE_FILE@0..46 1SOURCE_FILE@0..59
2 TYPE_ALIAS@0..45 2 [email protected]8
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -7,12 +7,12 @@ [email protected]
7 [email protected] " " 7 [email protected] " "
8 [email protected] "=" 8 [email protected] "="
9 [email protected] " " 9 [email protected] " "
10 PATH_TYPE@9..44 10 PATH_TYPE@9..57
11 PATH@9..44 11 PATH@9..57
12 PATH_SEGMENT@9..44 12 PATH_SEGMENT@9..57
13 [email protected] 13 [email protected]
14 [email protected] "B" 14 [email protected] "B"
15 GENERIC_ARG_LIST@10..44 15 GENERIC_ARG_LIST@10..57
16 [email protected] "<" 16 [email protected] "<"
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
@@ -51,6 +51,16 @@ [email protected]
51 [email protected] 51 [email protected]
52 [email protected] 52 [email protected]
53 [email protected] "u64" 53 [email protected] "u64"
54 [email protected] ">" 54 [email protected] ","
55 [email protected] ";" 55 [email protected] " "
56 [email protected] "\n" 56 [email protected]
57 [email protected]
58 [email protected] "true"
59 [email protected] ","
60 [email protected] " "
61 [email protected]
62 [email protected]
63 [email protected] "false"
64 [email protected] ">"
65 [email protected] ";"
66 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs
index 0d07d7651..6a8721a73 100644
--- a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs
+++ b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs
@@ -1 +1 @@
type A = B<'static, i32, 1, { 2 }, Item=u64>; type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>;