aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/diagnostics/fixes.rs2
-rw-r--r--crates/ide/src/doc_links.rs9
-rw-r--r--crates/ide/src/file_structure.rs2
-rw-r--r--crates/ide/src/inlay_hints.rs129
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/lib.rs14
-rw-r--r--crates/ide/src/markdown_remove.rs3
-rw-r--r--crates/ide/src/matching_brace.rs2
-rw-r--r--crates/ide/src/references.rs8
-rw-r--r--crates/ide/src/runnables.rs70
-rw-r--r--crates/ide/src/syntax_highlighting.rs12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html12
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs12
13 files changed, 245 insertions, 32 deletions
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 0c950003e..02e17ba43 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -25,7 +25,7 @@ use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePos
25/// A [Diagnostic] that potentially has a fix available. 25/// A [Diagnostic] that potentially has a fix available.
26/// 26///
27/// [Diagnostic]: hir::diagnostics::Diagnostic 27/// [Diagnostic]: hir::diagnostics::Diagnostic
28pub trait DiagnosticWithFix: Diagnostic { 28pub(crate) trait DiagnosticWithFix: Diagnostic {
29 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>; 29 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>;
30} 30}
31 31
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 250f10f9f..10263537a 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -1,7 +1,6 @@
1//! Resolves and rewrites links in markdown documentation. 1//! Resolves and rewrites links in markdown documentation.
2 2
3use std::convert::TryFrom; 3use std::{convert::TryFrom, iter::once};
4use std::iter::once;
5 4
6use itertools::Itertools; 5use itertools::Itertools;
7use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; 6use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
@@ -21,10 +20,10 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset,
21 20
22use crate::{FilePosition, Semantics}; 21use crate::{FilePosition, Semantics};
23 22
24pub type DocumentationLink = String; 23pub(crate) type DocumentationLink = String;
25 24
26/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) 25/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
27pub fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String { 26pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
28 let mut cb = |link: BrokenLink| { 27 let mut cb = |link: BrokenLink| {
29 Some(( 28 Some((
30 /*url*/ link.reference.to_owned().into(), 29 /*url*/ link.reference.to_owned().into(),
@@ -63,7 +62,7 @@ pub fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition)
63} 62}
64 63
65/// Remove all links in markdown documentation. 64/// Remove all links in markdown documentation.
66pub fn remove_links(markdown: &str) -> String { 65pub(crate) fn remove_links(markdown: &str) -> String {
67 let mut drop_link = false; 66 let mut drop_link = false;
68 67
69 let mut opts = Options::empty(); 68 let mut opts = Options::empty();
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 6168fb837..415795e8c 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -27,7 +27,7 @@ pub struct StructureNode {
27// 27//
28// | VS Code | kbd:[Ctrl+Shift+O] 28// | VS Code | kbd:[Ctrl+Shift+O]
29// |=== 29// |===
30pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> { 30pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
31 let mut res = Vec::new(); 31 let mut res = Vec::new();
32 let mut stack = Vec::new(); 32 let mut stack = Vec::new();
33 33
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 49d8e4ae1..ac704ae21 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,6 +1,6 @@
1use assists::utils::FamousDefs; 1use assists::utils::FamousDefs;
2use either::Either; 2use either::Either;
3use hir::{known, HirDisplay, Semantics}; 3use hir::{known, Callable, HirDisplay, Semantics};
4use ide_db::RootDatabase; 4use ide_db::RootDatabase;
5use stdx::to_lower_snake_case; 5use stdx::to_lower_snake_case;
6use syntax::{ 6use syntax::{
@@ -170,7 +170,7 @@ fn get_param_name_hints(
170 }; 170 };
171 Some((param_name, arg)) 171 Some((param_name, arg))
172 }) 172 })
173 .filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, &param_name, &arg)) 173 .filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, param_name, &arg))
174 .map(|(param_name, arg)| InlayHint { 174 .map(|(param_name, arg)| InlayHint {
175 range: arg.syntax().text_range(), 175 range: arg.syntax().text_range(),
176 kind: InlayKind::ParameterHint, 176 kind: InlayKind::ParameterHint,
@@ -334,9 +334,11 @@ fn should_show_param_name_hint(
334 | hir::CallableKind::TupleEnumVariant(_) 334 | hir::CallableKind::TupleEnumVariant(_)
335 | hir::CallableKind::Closure => None, 335 | hir::CallableKind::Closure => None,
336 }; 336 };
337
337 if param_name.is_empty() 338 if param_name.is_empty()
338 || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_')) 339 || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_'))
339 || is_argument_similar_to_param_name(sema, argument, param_name) 340 || is_argument_similar_to_param_name(sema, argument, param_name)
341 || is_param_name_similar_to_fn_name(param_name, callable, fn_name.as_ref())
340 || param_name.starts_with("ra_fixture") 342 || param_name.starts_with("ra_fixture")
341 { 343 {
342 return false; 344 return false;
@@ -364,6 +366,26 @@ fn is_argument_similar_to_param_name(
364 } 366 }
365} 367}
366 368
369fn is_param_name_similar_to_fn_name(
370 param_name: &str,
371 callable: &Callable,
372 fn_name: Option<&String>,
373) -> bool {
374 // if it's the only parameter, don't show it if:
375 // - is the same as the function name, or
376 // - the function ends with '_' + param_name
377
378 match (callable.n_params(), fn_name) {
379 (1, Some(function)) => {
380 function == param_name
381 || (function.len() > param_name.len()
382 && function.ends_with(param_name)
383 && function[..function.len() - param_name.len()].ends_with('_'))
384 }
385 _ => false,
386 }
387}
388
367fn is_enum_name_similar_to_param_name( 389fn is_enum_name_similar_to_param_name(
368 sema: &Semantics<RootDatabase>, 390 sema: &Semantics<RootDatabase>,
369 argument: &ast::Expr, 391 argument: &ast::Expr,
@@ -457,6 +479,88 @@ fn main() {
457 } 479 }
458 480
459 #[test] 481 #[test]
482 fn param_name_similar_to_fn_name_still_hints() {
483 check_with_config(
484 InlayHintsConfig {
485 parameter_hints: true,
486 type_hints: false,
487 chaining_hints: false,
488 max_length: None,
489 },
490 r#"
491fn max(x: i32, y: i32) -> i32 { x + y }
492fn main() {
493 let _x = max(
494 4,
495 //^ x
496 4,
497 //^ y
498 );
499}"#,
500 );
501 }
502
503 #[test]
504 fn param_name_similar_to_fn_name() {
505 check_with_config(
506 InlayHintsConfig {
507 parameter_hints: true,
508 type_hints: false,
509 chaining_hints: false,
510 max_length: None,
511 },
512 r#"
513fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
514fn main() {
515 let _x = param_with_underscore(
516 4,
517 );
518}"#,
519 );
520 }
521
522 #[test]
523 fn param_name_same_as_fn_name() {
524 check_with_config(
525 InlayHintsConfig {
526 parameter_hints: true,
527 type_hints: false,
528 chaining_hints: false,
529 max_length: None,
530 },
531 r#"
532fn foo(foo: i32) -> i32 { foo }
533fn main() {
534 let _x = foo(
535 4,
536 );
537}"#,
538 );
539 }
540
541 #[test]
542 fn never_hide_param_when_multiple_params() {
543 check_with_config(
544 InlayHintsConfig {
545 parameter_hints: true,
546 type_hints: false,
547 chaining_hints: false,
548 max_length: None,
549 },
550 r#"
551fn foo(bar: i32, baz: i32) -> i32 { bar + baz }
552fn main() {
553 let _x = foo(
554 4,
555 //^ bar
556 8,
557 //^ baz
558 );
559}"#,
560 );
561 }
562
563 #[test]
460 fn hints_disabled() { 564 fn hints_disabled() {
461 check_with_config( 565 check_with_config(
462 InlayHintsConfig { 566 InlayHintsConfig {
@@ -1235,4 +1339,25 @@ fn main() {
1235"#, 1339"#,
1236 ); 1340 );
1237 } 1341 }
1342
1343 #[test]
1344 fn infer_call_method_return_associated_types_with_generic() {
1345 check(
1346 r#"
1347 pub trait Default {
1348 fn default() -> Self;
1349 }
1350 pub trait Foo {
1351 type Bar: Default;
1352 }
1353
1354 pub fn quux<T: Foo>() -> T::Bar {
1355 let y = Default::default();
1356 //^ <T as Foo>::Bar
1357
1358 y
1359 }
1360 "#,
1361 );
1362 }
1238} 1363}
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index e37702acd..b5a6f66fd 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -18,7 +18,7 @@ use text_edit::{TextEdit, TextEditBuilder};
18// 18//
19// | VS Code | **Rust Analyzer: Join lines** 19// | VS Code | **Rust Analyzer: Join lines**
20// |=== 20// |===
21pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { 21pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
22 let range = if range.is_empty() { 22 let range = if range.is_empty() {
23 let syntax = file.syntax(); 23 let syntax = file.syntax();
24 let text = syntax.text().slice(range.start()..); 24 let text = syntax.text().slice(range.start()..);
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 4bc733b70..6288f7ea7 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -72,18 +72,20 @@ pub use crate::{
72 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 72 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
73 markup::Markup, 73 markup::Markup,
74 prime_caches::PrimeCachesProgress, 74 prime_caches::PrimeCachesProgress,
75 references::{ 75 references::{rename::RenameError, Declaration, ReferenceSearchResult},
76 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError,
77 },
78 runnables::{Runnable, RunnableKind, TestId}, 76 runnables::{Runnable, RunnableKind, TestId},
79 syntax_highlighting::{ 77 syntax_highlighting::{
80 Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange, 78 tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag},
79 HighlightedRange,
81 }, 80 },
82}; 81};
83pub use completion::{ 82pub use completion::{
84 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, 83 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
85}; 84};
86pub use ide_db::call_info::CallInfo; 85pub use ide_db::{
86 call_info::CallInfo,
87 search::{Reference, ReferenceAccess, ReferenceKind},
88};
87 89
88pub use assists::{ 90pub use assists::{
89 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist, 91 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
@@ -503,7 +505,7 @@ impl Analysis {
503 position: FilePosition, 505 position: FilePosition,
504 new_name: &str, 506 new_name: &str,
505 ) -> Cancelable<Result<RangeInfo<SourceChange>, RenameError>> { 507 ) -> Cancelable<Result<RangeInfo<SourceChange>, RenameError>> {
506 self.with_db(|db| references::rename(db, position, new_name)) 508 self.with_db(|db| references::rename::rename(db, position, new_name))
507 } 509 }
508 510
509 pub fn structural_search_replace( 511 pub fn structural_search_replace(
diff --git a/crates/ide/src/markdown_remove.rs b/crates/ide/src/markdown_remove.rs
index 02ad39dfb..3ec5c629e 100644
--- a/crates/ide/src/markdown_remove.rs
+++ b/crates/ide/src/markdown_remove.rs
@@ -1,11 +1,10 @@
1//! Removes markdown from strings. 1//! Removes markdown from strings.
2
3use pulldown_cmark::{Event, Parser, Tag}; 2use pulldown_cmark::{Event, Parser, Tag};
4 3
5/// Removes all markdown, keeping the text and code blocks 4/// Removes all markdown, keeping the text and code blocks
6/// 5///
7/// Currently limited in styling, i.e. no ascii tables or lists 6/// Currently limited in styling, i.e. no ascii tables or lists
8pub fn remove_markdown(markdown: &str) -> String { 7pub(crate) fn remove_markdown(markdown: &str) -> String {
9 let mut out = String::new(); 8 let mut out = String::new();
10 let parser = Parser::new(markdown); 9 let parser = Parser::new(markdown);
11 10
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs
index cb6abb0db..d70248afe 100644
--- a/crates/ide/src/matching_brace.rs
+++ b/crates/ide/src/matching_brace.rs
@@ -15,7 +15,7 @@ use test_utils::mark;
15// 15//
16// | VS Code | **Rust Analyzer: Find matching brace** 16// | VS Code | **Rust Analyzer: Find matching brace**
17// |=== 17// |===
18pub fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { 18pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
19 const BRACES: &[SyntaxKind] = 19 const BRACES: &[SyntaxKind] =
20 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; 20 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
21 let (brace_token, brace_idx) = file 21 let (brace_token, brace_idx) = file
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index a517081d5..e05465b32 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -14,7 +14,8 @@ pub(crate) mod rename;
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 defs::{Definition, NameClass, NameRefClass}, 16 defs::{Definition, NameClass, NameRefClass},
17 search::SearchScope, 17 search::Reference,
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
18 RootDatabase, 19 RootDatabase,
19}; 20};
20use syntax::{ 21use syntax::{
@@ -25,11 +26,6 @@ use syntax::{
25 26
26use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; 27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
27 28
28pub(crate) use self::rename::rename;
29pub use self::rename::RenameError;
30
31pub use ide_db::search::{Reference, ReferenceAccess, ReferenceKind};
32
33#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
34pub struct ReferenceSearchResult { 30pub struct ReferenceSearchResult {
35 declaration: Declaration, 31 declaration: Declaration,
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index eb82456ad..2bd0e86e5 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -102,6 +102,7 @@ pub(crate) fn runnable(
102) -> Option<Runnable> { 102) -> Option<Runnable> {
103 match_ast! { 103 match_ast! {
104 match item { 104 match item {
105 ast::Struct(it) => runnable_struct(sema, it, file_id),
105 ast::Fn(it) => runnable_fn(sema, it, file_id), 106 ast::Fn(it) => runnable_fn(sema, it, file_id),
106 ast::Module(it) => runnable_mod(sema, it, file_id), 107 ast::Module(it) => runnable_mod(sema, it, file_id),
107 _ => None, 108 _ => None,
@@ -182,6 +183,43 @@ fn runnable_fn(
182 Some(Runnable { nav, kind, cfg }) 183 Some(Runnable { nav, kind, cfg })
183} 184}
184 185
186fn runnable_struct(
187 sema: &Semantics<RootDatabase>,
188 struct_def: ast::Struct,
189 file_id: FileId,
190) -> Option<Runnable> {
191 if !has_runnable_doc_test(&struct_def) {
192 return None;
193 }
194 let name_string = struct_def.name()?.text().to_string();
195
196 let attrs =
197 Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def));
198 let cfg = attrs.cfg();
199
200 let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) {
201 Some(module) => {
202 let path_iter = module
203 .path_to_root(sema.db)
204 .into_iter()
205 .rev()
206 .filter_map(|it| it.name(sema.db))
207 .map(|name| name.to_string());
208 let path = path_iter.chain(std::iter::once(name_string)).join("::");
209
210 TestId::Path(path)
211 }
212 None => TestId::Name(name_string),
213 };
214
215 let nav = NavigationTarget::from_doc_commented(
216 sema.db,
217 InFile::new(file_id.into(), &struct_def),
218 InFile::new(file_id.into(), &struct_def),
219 );
220 Some(Runnable { nav, kind: RunnableKind::DocTest { test_id }, cfg })
221}
222
185#[derive(Debug, Copy, Clone)] 223#[derive(Debug, Copy, Clone)]
186pub struct TestAttr { 224pub struct TestAttr {
187 pub ignore: bool, 225 pub ignore: bool,
@@ -215,8 +253,8 @@ const RUSTDOC_FENCE: &str = "```";
215const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 253const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
216 &["", "rust", "should_panic", "edition2015", "edition2018"]; 254 &["", "rust", "should_panic", "edition2015", "edition2018"];
217 255
218fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool { 256fn has_runnable_doc_test(def: &dyn DocCommentsOwner) -> bool {
219 fn_def.doc_comment_text().map_or(false, |comments_text| { 257 def.doc_comment_text().map_or(false, |comments_text| {
220 let mut in_code_block = false; 258 let mut in_code_block = false;
221 259
222 for line in comments_text.lines() { 260 for line in comments_text.lines() {
@@ -487,8 +525,14 @@ fn should_have_no_runnable_5() {}
487/// let z = 55; 525/// let z = 55;
488/// ``` 526/// ```
489fn should_have_no_runnable_6() {} 527fn should_have_no_runnable_6() {}
528
529/// ```
530/// let x = 5;
531/// ```
532struct StructWithRunnable(String);
533
490"#, 534"#,
491 &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST], 535 &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST],
492 expect![[r#" 536 expect![[r#"
493 [ 537 [
494 Runnable { 538 Runnable {
@@ -569,6 +613,26 @@ fn should_have_no_runnable_6() {}
569 }, 613 },
570 cfg: None, 614 cfg: None,
571 }, 615 },
616 Runnable {
617 nav: NavigationTarget {
618 file_id: FileId(
619 0,
620 ),
621 full_range: 756..821,
622 focus_range: None,
623 name: "StructWithRunnable",
624 kind: STRUCT,
625 container_name: None,
626 description: None,
627 docs: None,
628 },
629 kind: DocTest {
630 test_id: Path(
631 "StructWithRunnable",
632 ),
633 },
634 cfg: None,
635 },
572 ] 636 ]
573 "#]], 637 "#]],
574 ); 638 );
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 9f864179e..efcc8ecfe 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -2,7 +2,7 @@ mod format;
2mod html; 2mod html;
3mod injection; 3mod injection;
4mod macro_rules; 4mod macro_rules;
5mod tags; 5pub(crate) mod tags;
6#[cfg(test)] 6#[cfg(test)]
7mod tests; 7mod tests;
8 8
@@ -20,12 +20,13 @@ use syntax::{
20}; 20};
21 21
22use crate::{ 22use crate::{
23 syntax_highlighting::{format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter}, 23 syntax_highlighting::{
24 FileId, 24 format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter, tags::Highlight,
25 },
26 FileId, HighlightModifier, HighlightTag,
25}; 27};
26 28
27pub(crate) use html::highlight_as_html; 29pub(crate) use html::highlight_as_html;
28pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag};
29 30
30#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
31pub struct HighlightedRange { 32pub struct HighlightedRange {
@@ -562,6 +563,9 @@ fn highlight_element(
562 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 563 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
563 HighlightTag::Macro.into() 564 HighlightTag::Macro.into()
564 } 565 }
566 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
567 HighlightTag::BuiltinType.into()
568 }
565 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { 569 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
566 HighlightTag::Keyword.into() 570 HighlightTag::Keyword.into()
567 } 571 }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index c6b4f5a00..5eb222ee2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -110,11 +110,21 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
110 <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> 110 <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>
111<span class="punctuation">}</span> 111<span class="punctuation">}</span>
112 112
113<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>
114 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span>
115<span class="punctuation">}</span>
116
113<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> 117<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span>
114<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> 118<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>
115 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> 119 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span>
116<span class="punctuation">}</span> 120<span class="punctuation">}</span>
117 121
122<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="unresolved_reference">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span>
123
124<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
125 <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>
126<span class="punctuation">}</span>
127
118<span class="macro">macro_rules!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span> 128<span class="macro">macro_rules!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span>
119 <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> 129 <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>
120<span class="punctuation">}</span> 130<span class="punctuation">}</span>
@@ -179,6 +189,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
179 189
180 <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> 190 <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>
181 <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> 191 <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>
192
193 <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>
182<span class="punctuation">}</span> 194<span class="punctuation">}</span>
183 195
184<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> 196<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>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index dd43f9dd9..2b667b0d4 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -84,11 +84,21 @@ fn foo<'a, T>() -> T {
84 foo::<'a, i32>() 84 foo::<'a, i32>()
85} 85}
86 86
87fn never() -> ! {
88 loop {}
89}
90
87use ops::Fn; 91use ops::Fn;
88fn baz<F: Fn() -> ()>(f: F) { 92fn baz<F: Fn() -> ()>(f: F) {
89 f() 93 f()
90} 94}
91 95
96fn foobar() -> impl Copy {}
97
98fn foo() {
99 let bar = foobar();
100}
101
92macro_rules! def_fn { 102macro_rules! def_fn {
93 ($($tt:tt)*) => {$($tt)*} 103 ($($tt:tt)*) => {$($tt)*}
94} 104}
@@ -153,6 +163,8 @@ fn main() {
153 163
154 let baz = -42; 164 let baz = -42;
155 let baz = -baz; 165 let baz = -baz;
166
167 let _ = !true;
156} 168}
157 169
158enum Option<T> { 170enum Option<T> {