aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock28
-rw-r--r--crates/completion/src/completions/attribute.rs42
-rw-r--r--crates/hir/src/code_model.rs4
-rw-r--r--crates/hir_def/src/body.rs20
-rw-r--r--crates/hir_def/src/body/tests.rs28
-rw-r--r--crates/hir_def/src/lib.rs51
-rw-r--r--crates/hir_expand/src/builtin_macro.rs71
-rw-r--r--crates/hir_expand/src/db.rs1
-rw-r--r--crates/hir_expand/src/eager.rs116
-rw-r--r--crates/hir_expand/src/lib.rs22
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/db.rs6
-rw-r--r--crates/hir_ty/src/method_resolution.rs8
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs19
-rw-r--r--crates/hir_ty/src/tests/regression.rs43
-rw-r--r--crates/hir_ty/src/traits.rs13
-rw-r--r--crates/hir_ty/src/traits/chalk.rs49
-rw-r--r--crates/hir_ty/src/traits/chalk/interner.rs16
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs13
-rw-r--r--crates/ide/src/diagnostics.rs5
-rw-r--r--crates/ide/src/syntax_highlighting.rs15
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html4
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html10
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html36
-rw-r--r--crates/ide_db/src/call_info.rs527
-rw-r--r--crates/ide_db/src/call_info/tests.rs523
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs639
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs620
-rw-r--r--crates/ide_db/src/line_index.rs131
-rw-r--r--crates/ide_db/src/line_index/tests.rs128
-rw-r--r--crates/ide_db/src/traits.rs148
-rw-r--r--crates/ide_db/src/traits/tests.rs144
-rw-r--r--crates/proc_macro_api/src/process.rs61
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs29
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt164
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt60
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt138
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt138
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt138
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt82
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt303
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs189
-rw-r--r--crates/rust-analyzer/src/main_loop.rs33
-rw-r--r--crates/rust-analyzer/src/to_proto.rs1
-rw-r--r--docs/dev/README.md16
49 files changed, 3082 insertions, 1774 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d8838cf2b..f1847e769 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
168 168
169[[package]] 169[[package]]
170name = "chalk-derive" 170name = "chalk-derive"
171version = "0.37.0" 171version = "0.43.0"
172source = "registry+https://github.com/rust-lang/crates.io-index" 172source = "registry+https://github.com/rust-lang/crates.io-index"
173checksum = "564b529b0d620da43dc7ea46fa95b5c602e783e1870aeb07e8cbb6d7ff71bee6" 173checksum = "e2d9e0c8adcced1ab0fea5cb8a38647922893d5b495e363e1814299fd380469b"
174dependencies = [ 174dependencies = [
175 "proc-macro2", 175 "proc-macro2",
176 "quote", 176 "quote",
@@ -180,9 +180,9 @@ dependencies = [
180 180
181[[package]] 181[[package]]
182name = "chalk-ir" 182name = "chalk-ir"
183version = "0.37.0" 183version = "0.43.0"
184source = "registry+https://github.com/rust-lang/crates.io-index" 184source = "registry+https://github.com/rust-lang/crates.io-index"
185checksum = "e67d29482387f4cbed6d8f1b1f7d24f00ff10612c700c65fe4af220df11e4d24" 185checksum = "c5218266a5709bc4943de997e64d3fab41c9e9f68efd54a898de53135e987bd3"
186dependencies = [ 186dependencies = [
187 "chalk-derive", 187 "chalk-derive",
188 "lazy_static", 188 "lazy_static",
@@ -190,9 +190,9 @@ dependencies = [
190 190
191[[package]] 191[[package]]
192name = "chalk-recursive" 192name = "chalk-recursive"
193version = "0.37.0" 193version = "0.43.0"
194source = "registry+https://github.com/rust-lang/crates.io-index" 194source = "registry+https://github.com/rust-lang/crates.io-index"
195checksum = "5c52032be6fbdf91b6a7df3cafba3a6683fdabeff88e7ab73eea96e28657d973" 195checksum = "ed8f34f13fd4f30251f9f6f1dc56f80363201390ecbcac2fdfc8e33036cd9c4a"
196dependencies = [ 196dependencies = [
197 "chalk-derive", 197 "chalk-derive",
198 "chalk-ir", 198 "chalk-ir",
@@ -203,9 +203,9 @@ dependencies = [
203 203
204[[package]] 204[[package]]
205name = "chalk-solve" 205name = "chalk-solve"
206version = "0.37.0" 206version = "0.43.0"
207source = "registry+https://github.com/rust-lang/crates.io-index" 207source = "registry+https://github.com/rust-lang/crates.io-index"
208checksum = "e0378bdfe1547b6fd545f518373b08c1e0c14920f7555a62d049021250a2b89b" 208checksum = "379c9f584488346044709d4c638c38d61a06fe593d4de2ac5f15fd2b0ba4cd9d"
209dependencies = [ 209dependencies = [
210 "chalk-derive", 210 "chalk-derive",
211 "chalk-ir", 211 "chalk-ir",
@@ -802,9 +802,9 @@ checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
802 802
803[[package]] 803[[package]]
804name = "libloading" 804name = "libloading"
805version = "0.6.5" 805version = "0.6.6"
806source = "registry+https://github.com/rust-lang/crates.io-index" 806source = "registry+https://github.com/rust-lang/crates.io-index"
807checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" 807checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc"
808dependencies = [ 808dependencies = [
809 "cfg-if 1.0.0", 809 "cfg-if 1.0.0",
810 "winapi 0.3.9", 810 "winapi 0.3.9",
@@ -956,9 +956,9 @@ dependencies = [
956 956
957[[package]] 957[[package]]
958name = "mio" 958name = "mio"
959version = "0.6.22" 959version = "0.6.23"
960source = "registry+https://github.com/rust-lang/crates.io-index" 960source = "registry+https://github.com/rust-lang/crates.io-index"
961checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" 961checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
962dependencies = [ 962dependencies = [
963 "cfg-if 0.1.10", 963 "cfg-if 0.1.10",
964 "fuchsia-zircon", 964 "fuchsia-zircon",
@@ -1555,9 +1555,9 @@ dependencies = [
1555 1555
1556[[package]] 1556[[package]]
1557name = "serde_json" 1557name = "serde_json"
1558version = "1.0.59" 1558version = "1.0.60"
1559source = "registry+https://github.com/rust-lang/crates.io-index" 1559source = "registry+https://github.com/rust-lang/crates.io-index"
1560checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" 1560checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
1561dependencies = [ 1561dependencies = [
1562 "itoa", 1562 "itoa",
1563 "ryu", 1563 "ryu",
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index f3d669458..5404145d5 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -87,13 +87,23 @@ const fn attr(
87 AttrCompletion { label, lookup, snippet, prefer_inner: false } 87 AttrCompletion { label, lookup, snippet, prefer_inner: false }
88} 88}
89 89
90/// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index
90const ATTRIBUTES: &[AttrCompletion] = &[ 91const ATTRIBUTES: &[AttrCompletion] = &[
91 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), 92 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
93 attr("automatically_derived", None, None),
92 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")), 94 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
93 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")), 95 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
96 attr("cold", None, None),
97 attr(r#"crate_name = """#, Some("crate_name"), Some(r#"crate_name = "${0:crate_name}""#))
98 .prefer_inner(),
94 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")), 99 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
95 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)), 100 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
96 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)), 101 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
102 attr(
103 r#"export_name = "…""#,
104 Some("export_name"),
105 Some(r#"export_name = "${0:exported_symbol_name}""#),
106 ),
97 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), 107 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
98 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), 108 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
99 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), 109 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
@@ -101,16 +111,24 @@ const ATTRIBUTES: &[AttrCompletion] = &[
101 attr("global_allocator", None, None).prefer_inner(), 111 attr("global_allocator", None, None).prefer_inner(),
102 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), 112 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
103 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")), 113 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
104 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
105 attr("link", None, None), 114 attr("link", None, None),
115 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
116 attr(
117 r#"link_section = "…""#,
118 Some("link_section"),
119 Some(r#"link_section = "${0:section_name}""#),
120 ),
106 attr("macro_export", None, None), 121 attr("macro_export", None, None),
107 attr("macro_use", None, None), 122 attr("macro_use", None, None),
108 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)), 123 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
124 attr("no_link", None, None).prefer_inner(),
125 attr("no_implicit_prelude", None, None).prefer_inner(),
126 attr("no_main", None, None).prefer_inner(),
109 attr("no_mangle", None, None), 127 attr("no_mangle", None, None),
110 attr("no_std", None, None).prefer_inner(), 128 attr("no_std", None, None).prefer_inner(),
111 attr("non_exhaustive", None, None), 129 attr("non_exhaustive", None, None),
112 attr("panic_handler", None, None).prefer_inner(), 130 attr("panic_handler", None, None).prefer_inner(),
113 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")), 131 attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)),
114 attr("proc_macro", None, None), 132 attr("proc_macro", None, None),
115 attr("proc_macro_attribute", None, None), 133 attr("proc_macro_attribute", None, None),
116 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")), 134 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
@@ -125,9 +143,12 @@ const ATTRIBUTES: &[AttrCompletion] = &[
125 attr( 143 attr(
126 r#"target_feature = "…""#, 144 r#"target_feature = "…""#,
127 Some("target_feature"), 145 Some("target_feature"),
128 Some("target_feature = \"${0:feature}\""), 146 Some(r#"target_feature = "${0:feature}""#),
129 ), 147 ),
130 attr("test", None, None), 148 attr("test", None, None),
149 attr("track_caller", None, None),
150 attr("type_length_limit = …", Some("type_length_limit"), Some("type_length_limit = ${0:128}"))
151 .prefer_inner(),
131 attr("used", None, None), 152 attr("used", None, None),
132 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")), 153 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
133 attr( 154 attr(
@@ -449,17 +470,21 @@ struct Test {}
449 r#"#[<|>]"#, 470 r#"#[<|>]"#,
450 expect![[r#" 471 expect![[r#"
451 at allow(…) 472 at allow(…)
473 at automatically_derived
452 at cfg(…) 474 at cfg(…)
453 at cfg_attr(…) 475 at cfg_attr(…)
476 at cold
454 at deny(…) 477 at deny(…)
455 at deprecated = "…" 478 at deprecated = "…"
456 at derive(…) 479 at derive(…)
457 at doc = "…" 480 at doc = "…"
481 at export_name = "…"
458 at forbid(…) 482 at forbid(…)
459 at ignore = "…" 483 at ignore = "…"
460 at inline(…) 484 at inline(…)
461 at link 485 at link
462 at link_name = "…" 486 at link_name = "…"
487 at link_section = "…"
463 at macro_export 488 at macro_export
464 at macro_use 489 at macro_use
465 at must_use = "…" 490 at must_use = "…"
@@ -473,6 +498,7 @@ struct Test {}
473 at should_panic(…) 498 at should_panic(…)
474 at target_feature = "…" 499 at target_feature = "…"
475 at test 500 at test
501 at track_caller
476 at used 502 at used
477 at warn(…) 503 at warn(…)
478 "#]], 504 "#]],
@@ -490,12 +516,16 @@ struct Test {}
490 r"#![<|>]", 516 r"#![<|>]",
491 expect![[r#" 517 expect![[r#"
492 at allow(…) 518 at allow(…)
519 at automatically_derived
493 at cfg(…) 520 at cfg(…)
494 at cfg_attr(…) 521 at cfg_attr(…)
522 at cold
523 at crate_name = ""
495 at deny(…) 524 at deny(…)
496 at deprecated = "…" 525 at deprecated = "…"
497 at derive(…) 526 at derive(…)
498 at doc = "…" 527 at doc = "…"
528 at export_name = "…"
499 at feature(…) 529 at feature(…)
500 at forbid(…) 530 at forbid(…)
501 at global_allocator 531 at global_allocator
@@ -503,9 +533,13 @@ struct Test {}
503 at inline(…) 533 at inline(…)
504 at link 534 at link
505 at link_name = "…" 535 at link_name = "…"
536 at link_section = "…"
506 at macro_export 537 at macro_export
507 at macro_use 538 at macro_use
508 at must_use = "…" 539 at must_use = "…"
540 at no_implicit_prelude
541 at no_link
542 at no_main
509 at no_mangle 543 at no_mangle
510 at no_std 544 at no_std
511 at non_exhaustive 545 at non_exhaustive
@@ -519,6 +553,8 @@ struct Test {}
519 at should_panic(…) 553 at should_panic(…)
520 at target_feature = "…" 554 at target_feature = "…"
521 at test 555 at test
556 at track_caller
557 at type_length_limit = …
522 at used 558 at used
523 at warn(…) 559 at warn(…)
524 at windows_subsystem = "…" 560 at windows_subsystem = "…"
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 4500050f1..9a1e9ba49 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -362,7 +362,9 @@ impl Module {
362 } 362 }
363 363
364 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 364 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
365 let _p = profile::span("Module::diagnostics"); 365 let _p = profile::span("Module::diagnostics").detail(|| {
366 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
367 });
366 let crate_def_map = db.crate_def_map(self.id.krate); 368 let crate_def_map = db.crate_def_map(self.id.krate);
367 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 369 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
368 for decl in self.declarations(db) { 370 for decl in self.declarations(db) {
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 33eb5e78c..92bcc1705 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -120,18 +120,24 @@ impl Expander {
120 self.resolve_path_as_macro(db, &path) 120 self.resolve_path_as_macro(db, &path)
121 }; 121 };
122 122
123 let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { 123 let mut err = None;
124 let call_id =
125 macro_call.as_call_id_with_errors(db, self.crate_def_map.krate, resolver, &mut |e| {
126 err.get_or_insert(e);
127 });
128 let call_id = match call_id {
124 Some(it) => it, 129 Some(it) => it,
125 None => { 130 None => {
126 // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough 131 if err.is_none() {
127 // info. 132 eprintln!("no error despite `as_call_id_with_errors` returning `None`");
128 return ExpandResult::only_err(mbe::ExpandError::Other( 133 }
129 "failed to parse or resolve macro invocation".into(), 134 return ExpandResult { value: None, err };
130 ));
131 } 135 }
132 }; 136 };
133 137
134 let err = db.macro_expand_error(call_id); 138 if err.is_none() {
139 err = db.macro_expand_error(call_id);
140 }
135 141
136 let file_id = call_id.as_file(); 142 let file_id = call_id.as_file();
137 143
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index baf1179f1..6dba9817d 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -78,21 +78,41 @@ fn f() {
78fn macro_diag_builtin() { 78fn macro_diag_builtin() {
79 check_diagnostics( 79 check_diagnostics(
80 r#" 80 r#"
81#[rustc_builtin_macro]
82macro_rules! env {}
83
84#[rustc_builtin_macro]
85macro_rules! include {}
86
87#[rustc_builtin_macro]
88macro_rules! compile_error {}
89
90#[rustc_builtin_macro]
91macro_rules! format_args {
92 () => {}
93}
94
81fn f() { 95fn f() {
82 // Test a handful of built-in (eager) macros: 96 // Test a handful of built-in (eager) macros:
83 97
84 include!(invalid); 98 include!(invalid);
85 //^^^^^^^^^^^^^^^^^ failed to parse or resolve macro invocation 99 //^^^^^^^^^^^^^^^^^ could not convert tokens
86 include!("does not exist"); 100 include!("does not exist");
87 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to parse or resolve macro invocation 101 //^^^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
88 102
89 env!(invalid); 103 env!(invalid);
90 //^^^^^^^^^^^^^ failed to parse or resolve macro invocation 104 //^^^^^^^^^^^^^ could not convert tokens
105
106 env!("OUT_DIR");
107 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix
108
109 compile_error!("compile_error works");
110 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
91 111
92 // Lazy: 112 // Lazy:
93 113
94 format_args!(); 114 format_args!();
95 //^^^^^^^^^^^^^^ failed to parse or resolve macro invocation 115 //^^^^^^^^^^^^^^ no rule matches input tokens
96} 116}
97 "#, 117 "#,
98 ); 118 );
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 1b22d1eec..b41c5acb2 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -465,21 +465,37 @@ pub trait AsMacroCall {
465 db: &dyn db::DefDatabase, 465 db: &dyn db::DefDatabase,
466 krate: CrateId, 466 krate: CrateId,
467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
468 ) -> Option<MacroCallId> {
469 self.as_call_id_with_errors(db, krate, resolver, &mut |_| ())
470 }
471
472 fn as_call_id_with_errors(
473 &self,
474 db: &dyn db::DefDatabase,
475 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
477 error_sink: &mut dyn FnMut(mbe::ExpandError),
468 ) -> Option<MacroCallId>; 478 ) -> Option<MacroCallId>;
469} 479}
470 480
471impl AsMacroCall for InFile<&ast::MacroCall> { 481impl AsMacroCall for InFile<&ast::MacroCall> {
472 fn as_call_id( 482 fn as_call_id_with_errors(
473 &self, 483 &self,
474 db: &dyn db::DefDatabase, 484 db: &dyn db::DefDatabase,
475 krate: CrateId, 485 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 486 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
487 error_sink: &mut dyn FnMut(mbe::ExpandError),
477 ) -> Option<MacroCallId> { 488 ) -> Option<MacroCallId> {
478 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); 489 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
479 let h = Hygiene::new(db.upcast(), self.file_id); 490 let h = Hygiene::new(db.upcast(), self.file_id);
480 let path = path::ModPath::from_src(self.value.path()?, &h)?; 491 let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
492
493 if path.is_none() {
494 error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
495 }
481 496
482 AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) 497 AstIdWithPath::new(ast_id.file_id, ast_id.value, path?)
498 .as_call_id_with_errors(db, krate, resolver, error_sink)
483 } 499 }
484} 500}
485 501
@@ -497,22 +513,32 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
497} 513}
498 514
499impl AsMacroCall for AstIdWithPath<ast::MacroCall> { 515impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
500 fn as_call_id( 516 fn as_call_id_with_errors(
501 &self, 517 &self,
502 db: &dyn db::DefDatabase, 518 db: &dyn db::DefDatabase,
503 krate: CrateId, 519 krate: CrateId,
504 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 520 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
521 error_sink: &mut dyn FnMut(mbe::ExpandError),
505 ) -> Option<MacroCallId> { 522 ) -> Option<MacroCallId> {
506 let def: MacroDefId = resolver(self.path.clone())?; 523 let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
524 error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
525 None
526 })?;
507 527
508 if let MacroDefKind::BuiltInEager(_) = def.kind { 528 if let MacroDefKind::BuiltInEager(_) = def.kind {
509 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast())); 529 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast()));
510 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); 530 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
511 531
512 Some( 532 Some(
513 expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { 533 expand_eager_macro(
514 resolver(path::ModPath::from_src(path, &hygiene)?) 534 db.upcast(),
515 })? 535 krate,
536 macro_call,
537 def,
538 &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
539 error_sink,
540 )
541 .ok()?
516 .into(), 542 .into(),
517 ) 543 )
518 } else { 544 } else {
@@ -522,13 +548,18 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
522} 548}
523 549
524impl AsMacroCall for AstIdWithPath<ast::Item> { 550impl AsMacroCall for AstIdWithPath<ast::Item> {
525 fn as_call_id( 551 fn as_call_id_with_errors(
526 &self, 552 &self,
527 db: &dyn db::DefDatabase, 553 db: &dyn db::DefDatabase,
528 krate: CrateId, 554 krate: CrateId,
529 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 555 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
556 error_sink: &mut dyn FnMut(mbe::ExpandError),
530 ) -> Option<MacroCallId> { 557 ) -> Option<MacroCallId> {
531 let def = resolver(self.path.clone())?; 558 let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
559 error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
560 None
561 })?;
562
532 Some( 563 Some(
533 def.as_lazy_macro( 564 def.as_lazy_macro(
534 db.upcast(), 565 db.upcast(),
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 7f4db106d..44a5556b6 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -86,7 +86,6 @@ pub fn find_builtin_macro(
86register_builtin! { 86register_builtin! {
87 LAZY: 87 LAZY:
88 (column, Column) => column_expand, 88 (column, Column) => column_expand,
89 (compile_error, CompileError) => compile_error_expand,
90 (file, File) => file_expand, 89 (file, File) => file_expand,
91 (line, Line) => line_expand, 90 (line, Line) => line_expand,
92 (assert, Assert) => assert_expand, 91 (assert, Assert) => assert_expand,
@@ -97,6 +96,7 @@ register_builtin! {
97 (format_args_nl, FormatArgsNl) => format_args_expand, 96 (format_args_nl, FormatArgsNl) => format_args_expand,
98 97
99 EAGER: 98 EAGER:
99 (compile_error, CompileError) => compile_error_expand,
100 (concat, Concat) => concat_expand, 100 (concat, Concat) => concat_expand,
101 (include, Include) => include_expand, 101 (include, Include) => include_expand,
102 (include_bytes, IncludeBytes) => include_bytes_expand, 102 (include_bytes, IncludeBytes) => include_bytes_expand,
@@ -213,25 +213,6 @@ fn file_expand(
213 ExpandResult::ok(expanded) 213 ExpandResult::ok(expanded)
214} 214}
215 215
216fn compile_error_expand(
217 _db: &dyn AstDatabase,
218 _id: LazyMacroId,
219 tt: &tt::Subtree,
220) -> ExpandResult<tt::Subtree> {
221 if tt.count() == 1 {
222 if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] {
223 let s = it.text.as_str();
224 if s.contains('"') {
225 return ExpandResult::ok(quote! { loop { #it }});
226 }
227 };
228 }
229
230 ExpandResult::only_err(mbe::ExpandError::BindingError(
231 "`compile_error!` argument be a string".into(),
232 ))
233}
234
235fn format_args_expand( 216fn format_args_expand(
236 _db: &dyn AstDatabase, 217 _db: &dyn AstDatabase,
237 _id: LazyMacroId, 218 _id: LazyMacroId,
@@ -280,6 +261,27 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
280 token.value().map(|it| it.into_owned()) 261 token.value().map(|it| it.into_owned())
281} 262}
282 263
264fn compile_error_expand(
265 _db: &dyn AstDatabase,
266 _id: EagerMacroId,
267 tt: &tt::Subtree,
268) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
269 let err = match &*tt.token_trees {
270 [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => {
271 let text = it.text.as_str();
272 if text.starts_with('"') && text.ends_with('"') {
273 // FIXME: does not handle raw strings
274 mbe::ExpandError::Other(text[1..text.len() - 1].to_string())
275 } else {
276 mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into())
277 }
278 }
279 _ => mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()),
280 };
281
282 ExpandResult { value: Some((quote! {}, FragmentKind::Items)), err: Some(err) }
283}
284
283fn concat_expand( 285fn concat_expand(
284 _db: &dyn AstDatabase, 286 _db: &dyn AstDatabase,
285 _arg_id: EagerMacroId, 287 _arg_id: EagerMacroId,
@@ -417,17 +419,25 @@ fn env_expand(
417 Err(e) => return ExpandResult::only_err(e), 419 Err(e) => return ExpandResult::only_err(e),
418 }; 420 };
419 421
420 // FIXME: 422 let mut err = None;
421 // If the environment variable is not defined int rustc, then a compilation error will be emitted. 423 let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| {
422 // We might do the same if we fully support all other stuffs. 424 // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid
423 // But for now on, we should return some dummy string for better type infer purpose. 425 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
424 // However, we cannot use an empty string here, because for 426 if key == "OUT_DIR" {
425 // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become 427 err = Some(mbe::ExpandError::Other(
426 // `include!("foo.rs"), which might go to infinite loop 428 r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(),
427 let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string()); 429 ));
430 }
431
432 // If the variable is unset, still return a dummy string to help type inference along.
433 // We cannot use an empty string here, because for
434 // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become
435 // `include!("foo.rs"), which might go to infinite loop
436 "__RA_UNIMPLEMENTED__".to_string()
437 });
428 let expanded = quote! { #s }; 438 let expanded = quote! { #s };
429 439
430 ExpandResult::ok(Some((expanded, FragmentKind::Expr))) 440 ExpandResult { value: Some((expanded, FragmentKind::Expr)), err }
431} 441}
432 442
433fn option_env_expand( 443fn option_env_expand(
@@ -638,7 +648,8 @@ mod tests {
638 "#, 648 "#,
639 ); 649 );
640 650
641 assert_eq!(expanded, r#"loop{"error!"}"#); 651 // This expands to nothing (since it's in item position), but emits an error.
652 assert_eq!(expanded, "");
642 } 653 }
643 654
644 #[test] 655 #[test]
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 4fd0ba290..842a177db 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -207,6 +207,7 @@ fn macro_expand_with_arg(
207 } else { 207 } else {
208 return ExpandResult { 208 return ExpandResult {
209 value: Some(db.lookup_intern_eager_expansion(id).subtree), 209 value: Some(db.lookup_intern_eager_expansion(id).subtree),
210 // FIXME: There could be errors here!
210 err: None, 211 err: None,
211 }; 212 };
212 } 213 }
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index ab6b4477c..0229a836e 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -26,19 +26,89 @@ use crate::{
26}; 26};
27 27
28use base_db::CrateId; 28use base_db::CrateId;
29use mbe::ExpandResult;
29use parser::FragmentKind; 30use parser::FragmentKind;
30use std::sync::Arc; 31use std::sync::Arc;
31use syntax::{algo::SyntaxRewriter, SyntaxNode}; 32use syntax::{algo::SyntaxRewriter, SyntaxNode};
32 33
34pub struct ErrorEmitted {
35 _private: (),
36}
37
38trait ErrorSink {
39 fn emit(&mut self, err: mbe::ExpandError);
40
41 fn option<T>(
42 &mut self,
43 opt: Option<T>,
44 error: impl FnOnce() -> mbe::ExpandError,
45 ) -> Result<T, ErrorEmitted> {
46 match opt {
47 Some(it) => Ok(it),
48 None => {
49 self.emit(error());
50 Err(ErrorEmitted { _private: () })
51 }
52 }
53 }
54
55 fn option_with<T>(
56 &mut self,
57 opt: impl FnOnce() -> Option<T>,
58 error: impl FnOnce() -> mbe::ExpandError,
59 ) -> Result<T, ErrorEmitted> {
60 self.option(opt(), error)
61 }
62
63 fn result<T>(&mut self, res: Result<T, mbe::ExpandError>) -> Result<T, ErrorEmitted> {
64 match res {
65 Ok(it) => Ok(it),
66 Err(e) => {
67 self.emit(e);
68 Err(ErrorEmitted { _private: () })
69 }
70 }
71 }
72
73 fn expand_result_option<T>(&mut self, res: ExpandResult<Option<T>>) -> Result<T, ErrorEmitted> {
74 match (res.value, res.err) {
75 (None, Some(err)) => {
76 self.emit(err);
77 Err(ErrorEmitted { _private: () })
78 }
79 (Some(value), opt_err) => {
80 if let Some(err) = opt_err {
81 self.emit(err);
82 }
83 Ok(value)
84 }
85 (None, None) => unreachable!("`ExpandResult` without value or error"),
86 }
87 }
88}
89
90impl ErrorSink for &'_ mut dyn FnMut(mbe::ExpandError) {
91 fn emit(&mut self, err: mbe::ExpandError) {
92 self(err);
93 }
94}
95
96fn err(msg: impl Into<String>) -> mbe::ExpandError {
97 mbe::ExpandError::Other(msg.into())
98}
99
33pub fn expand_eager_macro( 100pub fn expand_eager_macro(
34 db: &dyn AstDatabase, 101 db: &dyn AstDatabase,
35 krate: CrateId, 102 krate: CrateId,
36 macro_call: InFile<ast::MacroCall>, 103 macro_call: InFile<ast::MacroCall>,
37 def: MacroDefId, 104 def: MacroDefId,
38 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 105 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
39) -> Option<EagerMacroId> { 106 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
40 let args = macro_call.value.token_tree()?; 107) -> Result<EagerMacroId, ErrorEmitted> {
41 let parsed_args = mbe::ast_to_token_tree(&args)?.0; 108 let parsed_args = diagnostic_sink.option_with(
109 || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?)?.0),
110 || err("malformed macro invocation"),
111 )?;
42 112
43 // Note: 113 // Note:
44 // When `lazy_expand` is called, its *parent* file must be already exists. 114 // When `lazy_expand` is called, its *parent* file must be already exists.
@@ -55,17 +125,22 @@ pub fn expand_eager_macro(
55 }); 125 });
56 let arg_file_id: MacroCallId = arg_id.into(); 126 let arg_file_id: MacroCallId = arg_id.into();
57 127
58 let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr).ok()?.0; 128 let parsed_args =
129 diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0;
59 let result = eager_macro_recur( 130 let result = eager_macro_recur(
60 db, 131 db,
61 InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), 132 InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
62 krate, 133 krate,
63 resolver, 134 resolver,
135 diagnostic_sink,
64 )?; 136 )?;
65 let subtree = to_subtree(&result)?; 137 let subtree =
138 diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;
66 139
67 if let MacroDefKind::BuiltInEager(eager) = def.kind { 140 if let MacroDefKind::BuiltInEager(eager) = def.kind {
68 let (subtree, fragment) = eager.expand(db, arg_id, &subtree).value?; 141 let res = eager.expand(db, arg_id, &subtree);
142
143 let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?;
69 let eager = EagerCallLoc { 144 let eager = EagerCallLoc {
70 def, 145 def,
71 fragment, 146 fragment,
@@ -74,9 +149,9 @@ pub fn expand_eager_macro(
74 file_id: macro_call.file_id, 149 file_id: macro_call.file_id,
75 }; 150 };
76 151
77 Some(db.intern_eager_expansion(eager)) 152 Ok(db.intern_eager_expansion(eager))
78 } else { 153 } else {
79 None 154 panic!("called `expand_eager_macro` on non-eager macro def {:?}", def);
80 } 155 }
81} 156}
82 157
@@ -91,13 +166,16 @@ fn lazy_expand(
91 def: &MacroDefId, 166 def: &MacroDefId,
92 macro_call: InFile<ast::MacroCall>, 167 macro_call: InFile<ast::MacroCall>,
93 krate: CrateId, 168 krate: CrateId,
94) -> Option<InFile<SyntaxNode>> { 169) -> ExpandResult<Option<InFile<SyntaxNode>>> {
95 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 170 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
96 171
97 let id: MacroCallId = 172 let id: MacroCallId =
98 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); 173 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
99 174
100 db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) 175 let err = db.macro_expand_error(id);
176 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
177
178 ExpandResult { value, err }
101} 179}
102 180
103fn eager_macro_recur( 181fn eager_macro_recur(
@@ -105,7 +183,8 @@ fn eager_macro_recur(
105 curr: InFile<SyntaxNode>, 183 curr: InFile<SyntaxNode>,
106 krate: CrateId, 184 krate: CrateId,
107 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 185 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
108) -> Option<SyntaxNode> { 186 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
187) -> Result<SyntaxNode, ErrorEmitted> {
109 let original = curr.value.clone(); 188 let original = curr.value.clone();
110 189
111 let children = curr.value.descendants().filter_map(ast::MacroCall::cast); 190 let children = curr.value.descendants().filter_map(ast::MacroCall::cast);
@@ -113,7 +192,8 @@ fn eager_macro_recur(
113 192
114 // Collect replacement 193 // Collect replacement
115 for child in children { 194 for child in children {
116 let def: MacroDefId = macro_resolver(child.path()?)?; 195 let def = diagnostic_sink
196 .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
117 let insert = match def.kind { 197 let insert = match def.kind {
118 MacroDefKind::BuiltInEager(_) => { 198 MacroDefKind::BuiltInEager(_) => {
119 let id: MacroCallId = expand_eager_macro( 199 let id: MacroCallId = expand_eager_macro(
@@ -122,17 +202,21 @@ fn eager_macro_recur(
122 curr.with_value(child.clone()), 202 curr.with_value(child.clone()),
123 def, 203 def,
124 macro_resolver, 204 macro_resolver,
205 diagnostic_sink,
125 )? 206 )?
126 .into(); 207 .into();
127 db.parse_or_expand(id.as_file())? 208 db.parse_or_expand(id.as_file())
209 .expect("successful macro expansion should be parseable")
128 } 210 }
129 MacroDefKind::Declarative 211 MacroDefKind::Declarative
130 | MacroDefKind::BuiltIn(_) 212 | MacroDefKind::BuiltIn(_)
131 | MacroDefKind::BuiltInDerive(_) 213 | MacroDefKind::BuiltInDerive(_)
132 | MacroDefKind::ProcMacro(_) => { 214 | MacroDefKind::ProcMacro(_) => {
133 let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?; 215 let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
216 let val = diagnostic_sink.expand_result_option(res)?;
217
134 // replace macro inside 218 // replace macro inside
135 eager_macro_recur(db, expanded, krate, macro_resolver)? 219 eager_macro_recur(db, val, krate, macro_resolver, diagnostic_sink)?
136 } 220 }
137 }; 221 };
138 222
@@ -140,5 +224,5 @@ fn eager_macro_recur(
140 } 224 }
141 225
142 let res = rewriter.rewrite(&original); 226 let res = rewriter.rewrite(&original);
143 Some(res) 227 Ok(res)
144} 228}
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 6dad2507b..2633fd8f7 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -143,7 +143,11 @@ impl HirFileId {
143 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); 143 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
144 144
145 let arg_tt = loc.kind.arg(db)?; 145 let arg_tt = loc.kind.arg(db)?;
146 let def_tt = loc.def.ast_id?.to_node(db).token_tree()?; 146
147 let def = loc.def.ast_id.and_then(|id| {
148 let def_tt = id.to_node(db).token_tree()?;
149 Some(InFile::new(id.file_id, def_tt))
150 });
147 151
148 let macro_def = db.macro_def(loc.def)?; 152 let macro_def = db.macro_def(loc.def)?;
149 let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?; 153 let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
@@ -152,7 +156,7 @@ impl HirFileId {
152 Some(ExpansionInfo { 156 Some(ExpansionInfo {
153 expanded: InFile::new(self, parse.syntax_node()), 157 expanded: InFile::new(self, parse.syntax_node()),
154 arg: InFile::new(loc.kind.file_id(), arg_tt), 158 arg: InFile::new(loc.kind.file_id(), arg_tt),
155 def: InFile::new(loc.def.ast_id?.file_id, def_tt), 159 def,
156 macro_arg, 160 macro_arg,
157 macro_def, 161 macro_def,
158 exp_map, 162 exp_map,
@@ -311,7 +315,8 @@ pub struct EagerCallLoc {
311pub struct ExpansionInfo { 315pub struct ExpansionInfo {
312 expanded: InFile<SyntaxNode>, 316 expanded: InFile<SyntaxNode>,
313 arg: InFile<SyntaxNode>, 317 arg: InFile<SyntaxNode>,
314 def: InFile<ast::TokenTree>, 318 /// The `macro_rules!` arguments.
319 def: Option<InFile<ast::TokenTree>>,
315 320
316 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 321 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
317 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 322 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
@@ -348,9 +353,14 @@ impl ExpansionInfo {
348 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 353 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
349 let (token_map, tt) = match origin { 354 let (token_map, tt) = match origin {
350 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), 355 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
351 mbe::Origin::Def => { 356 mbe::Origin::Def => (
352 (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone())) 357 &self.macro_def.1,
353 } 358 self.def
359 .as_ref()
360 .expect("`Origin::Def` used with non-`macro_rules!` macro")
361 .as_ref()
362 .map(|tt| tt.syntax().clone()),
363 ),
354 }; 364 };
355 365
356 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 366 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index cf5c38a23..289e812fe 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.37", default-features = false } 20chalk-solve = { version = "0.43", default-features = false }
21chalk-ir = "0.37" 21chalk-ir = "0.43"
22chalk-recursive = "0.37" 22chalk-recursive = "0.43"
23 23
24stdx = { path = "../stdx", version = "0.0.0" } 24stdx = { path = "../stdx", version = "0.0.0" }
25hir_def = { path = "../hir_def", version = "0.0.0" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 25cf9eb7f..66bdb8e88 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -99,6 +99,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
99 #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] 99 #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
100 fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>; 100 fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
101 101
102 #[salsa::invoke(crate::traits::chalk::fn_def_variance_query)]
103 fn fn_def_variance(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> chalk::Variances;
104
105 #[salsa::invoke(crate::traits::chalk::adt_variance_query)]
106 fn adt_variance(&self, krate: CrateId, adt_id: chalk::AdtId) -> chalk::Variances;
107
102 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 108 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
103 fn associated_ty_value( 109 fn associated_ty_value(
104 &self, 110 &self,
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 5a6f0c67f..8a289f52a 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -720,7 +720,13 @@ fn transform_receiver_ty(
720 .push(self_ty.value.clone()) 720 .push(self_ty.value.clone())
721 .fill_with_unknown() 721 .fill_with_unknown()
722 .build(), 722 .build(),
723 AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, 723 AssocContainerId::ImplId(impl_id) => {
724 let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?;
725 Substs::build_for_def(db, function_id)
726 .use_parent_substs(&impl_substs)
727 .fill_with_unknown()
728 .build()
729 }
724 AssocContainerId::ContainerId(_) => unreachable!(), 730 AssocContainerId::ContainerId(_) => unreachable!(),
725 }; 731 };
726 let sig = db.callable_item_signature(function_id.into()); 732 let sig = db.callable_item_signature(function_id.into());
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 0f17ff151..a6a54e542 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1087,3 +1087,22 @@ fn method_resolution_foreign_opaque_type() {
1087 "#]], 1087 "#]],
1088 ); 1088 );
1089} 1089}
1090
1091#[test]
1092fn method_with_allocator_box_self_type() {
1093 check_types(
1094 r#"
1095struct Slice<T> {}
1096struct Box<T, A> {}
1097
1098impl<T> Slice<T> {
1099 pub fn into_vec<A>(self: Box<Self, A>) { }
1100}
1101
1102fn main() {
1103 let foo: Slice<u32>;
1104 (foo.into_vec()); // we don't actually support arbitrary self types, but we shouldn't crash at least
1105} //^ {unknown}
1106"#,
1107 );
1108}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 94d86b0d1..8cf4e7012 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -840,3 +840,46 @@ fn issue_4966() {
840 "#]], 840 "#]],
841 ); 841 );
842} 842}
843
844#[test]
845fn issue_6628() {
846 check_infer(
847 r#"
848 #[lang = "fn_once"]
849 pub trait FnOnce<Args> {
850 type Output;
851 }
852
853 struct S<T>();
854 impl<T> S<T> {
855 fn f(&self, _t: T) {}
856 fn g<F: FnOnce(&T)>(&self, _f: F) {}
857 }
858 fn main() {
859 let s = S();
860 s.g(|_x| {});
861 s.f(10);
862 }
863 "#,
864 expect![[r#"
865 105..109 'self': &S<T>
866 111..113 '_t': T
867 118..120 '{}': ()
868 146..150 'self': &S<T>
869 152..154 '_f': F
870 159..161 '{}': ()
871 174..225 '{ ...10); }': ()
872 184..185 's': S<i32>
873 188..189 'S': S<i32>() -> S<i32>
874 188..191 'S()': S<i32>
875 197..198 's': S<i32>
876 197..209 's.g(|_x| {})': ()
877 201..208 '|_x| {}': |&i32| -> ()
878 202..204 '_x': &i32
879 206..208 '{}': ()
880 215..216 's': S<i32>
881 215..222 's.f(10)': ()
882 219..221 '10': i32
883 "#]],
884 );
885}
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index ce1174cbe..dfa51896b 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -1,4 +1,5 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::env::var;
2use std::sync::Arc; 3use std::sync::Arc;
3 4
4use base_db::CrateId; 5use base_db::CrateId;
@@ -15,12 +16,6 @@ use self::chalk::{from_chalk, Interner, ToChalk};
15 16
16pub(crate) mod chalk; 17pub(crate) mod chalk;
17 18
18// This controls the maximum size of types Chalk considers. If we set this too
19// high, we can run into slow edge cases; if we set it too low, Chalk won't
20// find some solutions.
21// FIXME this is currently hardcoded in the recursive solver
22// const CHALK_SOLVER_MAX_SIZE: usize = 10;
23
24/// This controls how much 'time' we give the Chalk solver before giving up. 19/// This controls how much 'time' we give the Chalk solver before giving up.
25const CHALK_SOLVER_FUEL: i32 = 100; 20const CHALK_SOLVER_FUEL: i32 = 100;
26 21
@@ -31,9 +26,11 @@ struct ChalkContext<'a> {
31} 26}
32 27
33fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> { 28fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
34 let overflow_depth = 100; 29 let overflow_depth =
30 var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(100);
35 let caching_enabled = true; 31 let caching_enabled = true;
36 chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled) 32 let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(30);
33 chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, caching_enabled)
37} 34}
38 35
39/// A set of clauses that we assume to be true. E.g. if we are inside this function: 36/// A set of clauses that we assume to be true. E.g. if we are inside this function:
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 55e2c3a3e..69eae6f79 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -104,7 +104,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
104 }; 104 };
105 105
106 // Note: Since we're using impls_for_trait, only impls where the trait 106 // Note: Since we're using impls_for_trait, only impls where the trait
107 // can be resolved should ever reach Chalk. `impl_datum` relies on that 107 // can be resolved should ever reach Chalk. Symbol’s value as variable is void: impl_datum relies on that
108 // and will panic if the trait can't be resolved. 108 // and will panic if the trait can't be resolved.
109 let in_deps = self.db.trait_impls_in_deps(self.krate); 109 let in_deps = self.db.trait_impls_in_deps(self.krate);
110 let in_self = self.db.trait_impls_in_crate(self.krate); 110 let in_self = self.db.trait_impls_in_crate(self.krate);
@@ -206,7 +206,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
206 Some((trait_, alias)) 206 Some((trait_, alias))
207 }) 207 })
208 { 208 {
209 // Making up `AsyncBlock<T>: Future<Output = T>` 209 // Making up Symbol’s value as variable is void: AsyncBlock<T>:
210 // 210 //
211 // |--------------------OpaqueTyDatum-------------------| 211 // |--------------------OpaqueTyDatum-------------------|
212 // |-------------OpaqueTyDatumBound--------------| 212 // |-------------OpaqueTyDatumBound--------------|
@@ -242,7 +242,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
242 // The opaque type has 1 parameter. 242 // The opaque type has 1 parameter.
243 make_binders(bound, 1) 243 make_binders(bound, 1)
244 } else { 244 } else {
245 // If failed to find `Future::Output`, return empty bounds as fallback. 245 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
246 let bound = OpaqueTyDatumBound { 246 let bound = OpaqueTyDatumBound {
247 bounds: make_binders(vec![], 0), 247 bounds: make_binders(vec![], 0),
248 where_clauses: make_binders(vec![], 0), 248 where_clauses: make_binders(vec![], 0),
@@ -343,6 +343,23 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
343 // FIXME 343 // FIXME
344 unimplemented!() 344 unimplemented!()
345 } 345 }
346
347 fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
348 self
349 }
350}
351
352impl<'a> chalk_ir::UnificationDatabase<Interner> for ChalkContext<'a> {
353 fn fn_def_variance(
354 &self,
355 fn_def_id: chalk_ir::FnDefId<Interner>,
356 ) -> chalk_ir::Variances<Interner> {
357 self.db.fn_def_variance(self.krate, fn_def_id)
358 }
359
360 fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
361 self.db.adt_variance(self.krate, adt_id)
362 }
346} 363}
347 364
348pub(crate) fn program_clauses_for_chalk_env_query( 365pub(crate) fn program_clauses_for_chalk_env_query(
@@ -644,6 +661,32 @@ pub(crate) fn fn_def_datum_query(
644 Arc::new(datum) 661 Arc::new(datum)
645} 662}
646 663
664pub(crate) fn fn_def_variance_query(
665 db: &dyn HirDatabase,
666 _krate: CrateId,
667 fn_def_id: FnDefId,
668) -> Variances {
669 let callable_def: CallableDefId = from_chalk(db, fn_def_id);
670 let generic_params = generics(db.upcast(), callable_def.into());
671 Variances::from(
672 &Interner,
673 std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
674 )
675}
676
677pub(crate) fn adt_variance_query(
678 db: &dyn HirDatabase,
679 _krate: CrateId,
680 adt_id: AdtId,
681) -> Variances {
682 let adt: crate::AdtId = from_chalk(db, adt_id);
683 let generic_params = generics(db.upcast(), adt.into());
684 Variances::from(
685 &Interner,
686 std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
687 )
688}
689
647impl From<FnDefId> for crate::db::InternedCallableDefId { 690impl From<FnDefId> for crate::db::InternedCallableDefId {
648 fn from(fn_def_id: FnDefId) -> Self { 691 fn from(fn_def_id: FnDefId) -> Self {
649 InternKey::from_intern_id(fn_def_id.0) 692 InternKey::from_intern_id(fn_def_id.0)
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs
index 39569e690..6a4aa8333 100644
--- a/crates/hir_ty/src/traits/chalk/interner.rs
+++ b/crates/hir_ty/src/traits/chalk/interner.rs
@@ -25,6 +25,7 @@ pub(crate) type FnDefId = chalk_ir::FnDefId<Interner>;
25pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; 25pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
26pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 26pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
27pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; 27pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
28pub(crate) type Variances = chalk_ir::Variances<Interner>;
28 29
29impl chalk_ir::interner::Interner for Interner { 30impl chalk_ir::interner::Interner for Interner {
30 type InternedType = Arc<chalk_ir::TyData<Self>>; 31 type InternedType = Arc<chalk_ir::TyData<Self>>;
@@ -41,6 +42,7 @@ impl chalk_ir::interner::Interner for Interner {
41 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; 42 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
42 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; 43 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
43 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; 44 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
45 type InternedVariances = Arc<[chalk_ir::Variance]>;
44 type DefId = InternId; 46 type DefId = InternId;
45 type InternedAdtId = hir_def::AdtId; 47 type InternedAdtId = hir_def::AdtId;
46 type Identifier = TypeAliasId; 48 type Identifier = TypeAliasId;
@@ -370,6 +372,20 @@ impl chalk_ir::interner::Interner for Interner {
370 ) -> Option<fmt::Result> { 372 ) -> Option<fmt::Result> {
371 None 373 None
372 } 374 }
375
376 fn intern_variances<E>(
377 &self,
378 data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
379 ) -> Result<Self::InternedVariances, E> {
380 data.into_iter().collect()
381 }
382
383 fn variances_data<'a>(
384 &self,
385 variances: &'a Self::InternedVariances,
386 ) -> &'a [chalk_ir::Variance] {
387 &variances
388 }
373} 389}
374 390
375impl chalk_ir::interner::HasInterner for Interner { 391impl chalk_ir::interner::HasInterner for Interner {
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 86cbc4c7e..8700d664e 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -31,7 +31,8 @@ impl ToChalk for Ty {
31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), 31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
32 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters), 32 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
33 TypeCtor::FnPtr { num_args: _, is_varargs } => { 33 TypeCtor::FnPtr { num_args: _, is_varargs } => {
34 let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); 34 let substitution =
35 chalk_ir::FnSubst(apply_ty.parameters.to_chalk(db).shifted_in(&Interner));
35 chalk_ir::TyKind::Function(chalk_ir::FnPointer { 36 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
36 num_binders: 0, 37 num_binders: 0,
37 sig: chalk_ir::FnSig { 38 sig: chalk_ir::FnSig {
@@ -183,7 +184,7 @@ impl ToChalk for Ty {
183 assert_eq!(num_binders, 0); 184 assert_eq!(num_binders, 0);
184 let parameters: Substs = from_chalk( 185 let parameters: Substs = from_chalk(
185 db, 186 db,
186 substitution.shifted_out(&Interner).expect("fn ptr should have no binders"), 187 substitution.0.shifted_out(&Interner).expect("fn ptr should have no binders"),
187 ); 188 );
188 Ty::Apply(ApplicationTy { 189 Ty::Apply(ApplicationTy {
189 ctor: TypeCtor::FnPtr { 190 ctor: TypeCtor::FnPtr {
@@ -536,6 +537,7 @@ impl ToChalk for GenericPredicate {
536 // we don't produce any where clauses with binders and can't currently deal with them 537 // we don't produce any where clauses with binders and can't currently deal with them
537 match where_clause 538 match where_clause
538 .skip_binders() 539 .skip_binders()
540 .clone()
539 .shifted_out(&Interner) 541 .shifted_out(&Interner)
540 .expect("unexpected bound vars in where clause") 542 .expect("unexpected bound vars in where clause")
541 { 543 {
@@ -661,7 +663,12 @@ where
661 chalk_ir::TyVariableKind::Integer => TyKind::Integer, 663 chalk_ir::TyVariableKind::Integer => TyKind::Integer,
662 chalk_ir::TyVariableKind::Float => TyKind::Float, 664 chalk_ir::TyVariableKind::Float => TyKind::Float,
663 }, 665 },
664 chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"), 666 // HACK: Chalk can sometimes return new lifetime variables. We
667 // want to just skip them, but to not mess up the indices of
668 // other variables, we'll just create a new type variable in
669 // their place instead. This should not matter (we never see the
670 // actual *uses* of the lifetime variable).
671 chalk_ir::VariableKind::Lifetime => TyKind::General,
665 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"), 672 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
666 }) 673 })
667 .collect(); 674 .collect();
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 9d3d88289..c8453edb3 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -135,6 +135,11 @@ pub(crate) fn diagnostics(
135 res.borrow_mut().push(warning_with_fix(d, &sema)); 135 res.borrow_mut().push(warning_with_fix(d, &sema));
136 }) 136 })
137 .on::<hir::diagnostics::InactiveCode, _>(|d| { 137 .on::<hir::diagnostics::InactiveCode, _>(|d| {
138 // If there's inactive code somewhere in a macro, don't propagate to the call-site.
139 if d.display_source().file_id.expansion_info(db).is_some() {
140 return;
141 }
142
138 // Override severity and mark as unused. 143 // Override severity and mark as unused.
139 res.borrow_mut().push( 144 res.borrow_mut().push(
140 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) 145 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 5150a970c..f5c6eabef 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -726,7 +726,7 @@ fn highlight_method_call(
726 method_call: &ast::MethodCallExpr, 726 method_call: &ast::MethodCallExpr,
727) -> Option<Highlight> { 727) -> Option<Highlight> {
728 let func = sema.resolve_method_call(&method_call)?; 728 let func = sema.resolve_method_call(&method_call)?;
729 let mut h = HighlightTag::Function.into(); 729 let mut h = HighlightTag::Method.into();
730 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { 730 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
731 h |= HighlightModifier::Unsafe; 731 h |= HighlightModifier::Unsafe;
732 } 732 }
@@ -755,13 +755,18 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
755 Definition::ModuleDef(def) => match def { 755 Definition::ModuleDef(def) => match def {
756 hir::ModuleDef::Module(_) => HighlightTag::Module, 756 hir::ModuleDef::Module(_) => HighlightTag::Module,
757 hir::ModuleDef::Function(func) => { 757 hir::ModuleDef::Function(func) => {
758 let mut h = HighlightTag::Function.into(); 758 let mut h = if func.as_assoc_item(db).is_some() {
759 if func.self_param(db).is_none() {
760 Highlight::from(HighlightTag::Method) | HighlightModifier::Static
761 } else {
762 HighlightTag::Method.into()
763 }
764 } else {
765 HighlightTag::Function.into()
766 };
759 if func.is_unsafe(db) { 767 if func.is_unsafe(db) {
760 h |= HighlightModifier::Unsafe; 768 h |= HighlightModifier::Unsafe;
761 } 769 }
762 if func.as_assoc_item(db).is_some() && func.self_param(db).is_none() {
763 h |= HighlightModifier::Static;
764 }
765 return h; 770 return h;
766 } 771 }
767 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, 772 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 65e0671a5..ffd9588b8 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -30,6 +30,7 @@ pub enum HighlightTag {
30 Keyword, 30 Keyword,
31 Lifetime, 31 Lifetime,
32 Macro, 32 Macro,
33 Method,
33 Module, 34 Module,
34 NumericLiteral, 35 NumericLiteral,
35 Punctuation, 36 Punctuation,
@@ -90,6 +91,7 @@ impl HighlightTag {
90 HighlightTag::Lifetime => "lifetime", 91 HighlightTag::Lifetime => "lifetime",
91 HighlightTag::Punctuation => "punctuation", 92 HighlightTag::Punctuation => "punctuation",
92 HighlightTag::Macro => "macro", 93 HighlightTag::Macro => "macro",
94 HighlightTag::Method => "method",
93 HighlightTag::Module => "module", 95 HighlightTag::Module => "module",
94 HighlightTag::NumericLiteral => "numeric_literal", 96 HighlightTag::NumericLiteral => "numeric_literal",
95 HighlightTag::Operator => "operator", 97 HighlightTag::Operator => "operator",
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 cd80d72b7..6fb606a47 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
@@ -40,17 +40,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
40<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span> 40<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span>
41 41
42<span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span> 42<span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span>
43 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 43 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method declaration static">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">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> 44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method declaration">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="punctuation">}</span> 45<span class="punctuation">}</span>
46 46
47<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span> 47<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span>
48 <span class="keyword">fn</span> <span class="function declaration static">t_is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 48 <span class="keyword">fn</span> <span class="method declaration static">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">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> 49 <span class="keyword">fn</span> <span class="method declaration">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="punctuation">}</span> 50<span class="punctuation">}</span>
51 51
52<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="punctuation">{</span> 52<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">pub</span> <span class="keyword">fn</span> <span class="function declaration static">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 53 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method declaration static">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">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> 54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method declaration">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="punctuation">}</span> 55<span class="punctuation">}</span>
56 </code></pre> \ No newline at end of file 56 </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 d79fa6dca..396fd46fb 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -53,7 +53,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
53 <span class="comment documentation">/// #</span><span class="generic 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> 53 <span class="comment documentation">/// #</span><span class="generic 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>
54 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="keyword injected">mut</span><span class="generic injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic 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><span class="punctuation injected"> 54 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="keyword injected">mut</span><span class="generic injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic 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><span class="punctuation injected">
55</span> <span class="comment documentation">/// ```</span> 55</span> <span class="comment documentation">/// ```</span>
56 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 56 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="method declaration static">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
57 <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> 57 <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>
58 <span class="punctuation">}</span> 58 <span class="punctuation">}</span>
59 59
@@ -87,7 +87,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
87 <span class="comment documentation">/// ```sh</span> 87 <span class="comment documentation">/// ```sh</span>
88 <span class="comment documentation">/// echo 1</span> 88 <span class="comment documentation">/// echo 1</span>
89 <span class="comment documentation">/// ```</span> 89 <span class="comment documentation">/// ```</span>
90 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">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> 90 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="method declaration">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>
91 <span class="bool_literal">true</span> 91 <span class="bool_literal">true</span>
92 <span class="punctuation">}</span> 92 <span class="punctuation">}</span>
93<span class="punctuation">}</span> 93<span class="punctuation">}</span>
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 57c178916..31daf2bd0 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -40,7 +40,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
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="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
41 <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> 41 <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span>
42 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> 42 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span>
43 <span class="keyword">fn</span> <span class="function declaration static">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 43 <span class="keyword">fn</span> <span class="method declaration static">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
44 <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> 44 <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="punctuation">}</span> 45 <span class="punctuation">}</span>
46 <span class="punctuation">}</span><span class="string_literal">"#</span> 46 <span class="punctuation">}</span><span class="string_literal">"#</span>
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 1d05b7713..67ec73f15 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
45<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> 45<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span>
46 46
47<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> 47<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span>
48 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration 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> 48 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method declaration 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="punctuation">}</span> 49<span class="punctuation">}</span>
50 50
51<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span> 51<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span>
@@ -60,11 +60,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
60<span class="punctuation">}</span> 60<span class="punctuation">}</span>
61 61
62<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span> 62<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span>
63 <span class="keyword">fn</span> <span class="function declaration">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> 63 <span class="keyword">fn</span> <span class="method declaration">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="punctuation">}</span> 64<span class="punctuation">}</span>
65 65
66<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> 66<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">fn</span> <span class="function declaration">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> 67 <span class="keyword">fn</span> <span class="method declaration">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="punctuation">}</span> 68<span class="punctuation">}</span>
69 69
70<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 70<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
@@ -78,7 +78,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
78 <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> 78 <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="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> 79 <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="punctuation">}</span> 80 <span class="punctuation">}</span>
81 <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 81 <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="method unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
82 82
83 <span class="comment">// unsafe deref</span> 83 <span class="comment">// unsafe deref</span>
84 <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> 84 <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>
@@ -94,6 +94,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
94 <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> 94 <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 95
96 <span class="comment">// unsafe auto ref of packed field</span> 96 <span class="comment">// unsafe auto ref of packed field</span>
97 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 97 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="method unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
98 <span class="punctuation">}</span> 98 <span class="punctuation">}</span>
99<span class="punctuation">}</span></code></pre> \ No newline at end of file 99<span class="punctuation">}</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 15fbf2ce3..a3b4f20e8 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -62,25 +62,25 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62<span class="punctuation">}</span> 62<span class="punctuation">}</span>
63 63
64<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span> 64<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span>
65 <span class="keyword">fn</span> <span class="function declaration">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> 65 <span class="keyword">fn</span> <span class="method declaration">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>
66<span class="punctuation">}</span> 66<span class="punctuation">}</span>
67 67
68<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 68<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
69 <span class="keyword">fn</span> <span class="function declaration">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="method declaration">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>
70 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 70 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
71 <span class="punctuation">}</span> 71 <span class="punctuation">}</span>
72<span class="punctuation">}</span> 72<span class="punctuation">}</span>
73 73
74<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 74<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
75 <span class="keyword">fn</span> <span class="function declaration">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> 75 <span class="keyword">fn</span> <span class="method declaration">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>
76 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span> 76 <span class="value_param">f</span><span class="operator">.</span><span class="method consuming">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span>
77 <span class="punctuation">}</span> 77 <span class="punctuation">}</span>
78 78
79 <span class="keyword">fn</span> <span class="function declaration">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> 79 <span class="keyword">fn</span> <span class="method declaration">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>
80 <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> 80 <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>
81 <span class="punctuation">}</span> 81 <span class="punctuation">}</span>
82 82
83 <span class="keyword">fn</span> <span class="function declaration">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> 83 <span class="keyword">fn</span> <span class="method declaration">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>
84 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 84 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
85 <span class="punctuation">}</span> 85 <span class="punctuation">}</span>
86<span class="punctuation">}</span> 86<span class="punctuation">}</span>
@@ -91,15 +91,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
91<span class="punctuation">}</span> 91<span class="punctuation">}</span>
92 92
93<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> 93<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span>
94 <span class="keyword">fn</span> <span class="function declaration">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> 94 <span class="keyword">fn</span> <span class="method declaration">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>
95 <span class="value_param">f</span><span class="operator">.</span><span class="function">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> 95 <span class="value_param">f</span><span class="operator">.</span><span class="method">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span>
96 <span class="punctuation">}</span> 96 <span class="punctuation">}</span>
97 97
98 <span class="keyword">fn</span> <span class="function declaration">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> 98 <span class="keyword">fn</span> <span class="method declaration">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>
99 <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> 99 <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>
100 <span class="punctuation">}</span> 100 <span class="punctuation">}</span>
101 101
102 <span class="keyword">fn</span> <span class="function declaration">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> 102 <span class="keyword">fn</span> <span class="method declaration">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>
103 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 103 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
104 <span class="punctuation">}</span> 104 <span class="punctuation">}</span>
105<span class="punctuation">}</span> 105<span class="punctuation">}</span>
@@ -175,17 +175,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
175 175
176 <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> 176 <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>
177 <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> 177 <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>
178 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 178 <span class="variable mutable">foo</span><span class="operator">.</span><span class="method">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
179 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 179 <span class="variable mutable">foo</span><span class="operator">.</span><span class="method mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
180 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span> 180 <span class="variable mutable">foo</span><span class="operator">.</span><span class="method consuming">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span>
181 181
182 <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> 182 <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>
183 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 183 <span class="variable mutable">copy</span><span class="operator">.</span><span class="method">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
184 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 184 <span class="variable mutable">copy</span><span class="operator">.</span><span class="method mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
185 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span> 185 <span class="variable mutable">copy</span><span class="operator">.</span><span class="method">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span>
186 186
187 <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> 187 <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>
188 <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">baz</span><span class="punctuation">;</span> 188 <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="method">baz</span><span class="punctuation">;</span>
189 189
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> 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>
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> 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>
@@ -200,7 +200,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
200<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span> 200<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span>
201 201
202<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> 202<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>
203 <span class="keyword">fn</span> <span class="function declaration">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> 203 <span class="keyword">fn</span> <span class="method declaration">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>
204 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span> 204 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span>
205 <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> 205 <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>
206 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="punctuation">,</span> 206 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="punctuation">,</span>
diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs
index 83a602b9a..615fa7b0e 100644
--- a/crates/ide_db/src/call_info.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -228,529 +228,4 @@ impl FnCallNode {
228} 228}
229 229
230#[cfg(test)] 230#[cfg(test)]
231mod tests { 231mod tests;
232 use crate::RootDatabase;
233 use base_db::{fixture::ChangeFixture, FilePosition};
234 use expect_test::{expect, Expect};
235 use test_utils::{mark, RangeOrOffset};
236
237 /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
238 pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
239 let change_fixture = ChangeFixture::parse(ra_fixture);
240 let mut database = RootDatabase::default();
241 database.apply_change(change_fixture.change);
242 let (file_id, range_or_offset) =
243 change_fixture.file_position.expect("expected a marker (<|>)");
244 let offset = match range_or_offset {
245 RangeOrOffset::Range(_) => panic!(),
246 RangeOrOffset::Offset(it) => it,
247 };
248 (database, FilePosition { file_id, offset })
249 }
250
251 fn check(ra_fixture: &str, expect: Expect) {
252 let (db, position) = position(ra_fixture);
253 let call_info = crate::call_info::call_info(&db, position);
254 let actual = match call_info {
255 Some(call_info) => {
256 let docs = match &call_info.doc {
257 None => "".to_string(),
258 Some(docs) => format!("{}\n------\n", docs.as_str()),
259 };
260 let params = call_info
261 .parameter_labels()
262 .enumerate()
263 .map(|(i, param)| {
264 if Some(i) == call_info.active_parameter {
265 format!("<{}>", param)
266 } else {
267 param.to_string()
268 }
269 })
270 .collect::<Vec<_>>()
271 .join(", ");
272 format!("{}{}\n({})\n", docs, call_info.signature, params)
273 }
274 None => String::new(),
275 };
276 expect.assert_eq(&actual);
277 }
278
279 #[test]
280 fn test_fn_signature_two_args() {
281 check(
282 r#"
283fn foo(x: u32, y: u32) -> u32 {x + y}
284fn bar() { foo(<|>3, ); }
285"#,
286 expect![[r#"
287 fn foo(x: u32, y: u32) -> u32
288 (<x: u32>, y: u32)
289 "#]],
290 );
291 check(
292 r#"
293fn foo(x: u32, y: u32) -> u32 {x + y}
294fn bar() { foo(3<|>, ); }
295"#,
296 expect![[r#"
297 fn foo(x: u32, y: u32) -> u32
298 (<x: u32>, y: u32)
299 "#]],
300 );
301 check(
302 r#"
303fn foo(x: u32, y: u32) -> u32 {x + y}
304fn bar() { foo(3,<|> ); }
305"#,
306 expect![[r#"
307 fn foo(x: u32, y: u32) -> u32
308 (x: u32, <y: u32>)
309 "#]],
310 );
311 check(
312 r#"
313fn foo(x: u32, y: u32) -> u32 {x + y}
314fn bar() { foo(3, <|>); }
315"#,
316 expect![[r#"
317 fn foo(x: u32, y: u32) -> u32
318 (x: u32, <y: u32>)
319 "#]],
320 );
321 }
322
323 #[test]
324 fn test_fn_signature_two_args_empty() {
325 check(
326 r#"
327fn foo(x: u32, y: u32) -> u32 {x + y}
328fn bar() { foo(<|>); }
329"#,
330 expect![[r#"
331 fn foo(x: u32, y: u32) -> u32
332 (<x: u32>, y: u32)
333 "#]],
334 );
335 }
336
337 #[test]
338 fn test_fn_signature_two_args_first_generics() {
339 check(
340 r#"
341fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
342 where T: Copy + Display, U: Debug
343{ x + y }
344
345fn bar() { foo(<|>3, ); }
346"#,
347 expect![[r#"
348 fn foo(x: i32, y: {unknown}) -> u32
349 (<x: i32>, y: {unknown})
350 "#]],
351 );
352 }
353
354 #[test]
355 fn test_fn_signature_no_params() {
356 check(
357 r#"
358fn foo<T>() -> T where T: Copy + Display {}
359fn bar() { foo(<|>); }
360"#,
361 expect![[r#"
362 fn foo() -> {unknown}
363 ()
364 "#]],
365 );
366 }
367
368 #[test]
369 fn test_fn_signature_for_impl() {
370 check(
371 r#"
372struct F;
373impl F { pub fn new() { } }
374fn bar() {
375 let _ : F = F::new(<|>);
376}
377"#,
378 expect![[r#"
379 fn new()
380 ()
381 "#]],
382 );
383 }
384
385 #[test]
386 fn test_fn_signature_for_method_self() {
387 check(
388 r#"
389struct S;
390impl S { pub fn do_it(&self) {} }
391
392fn bar() {
393 let s: S = S;
394 s.do_it(<|>);
395}
396"#,
397 expect![[r#"
398 fn do_it(&self)
399 ()
400 "#]],
401 );
402 }
403
404 #[test]
405 fn test_fn_signature_for_method_with_arg() {
406 check(
407 r#"
408struct S;
409impl S {
410 fn foo(&self, x: i32) {}
411}
412
413fn main() { S.foo(<|>); }
414"#,
415 expect![[r#"
416 fn foo(&self, x: i32)
417 (<x: i32>)
418 "#]],
419 );
420 }
421
422 #[test]
423 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
424 check(
425 r#"
426struct S;
427impl S {
428 fn foo(&self, x: i32) {}
429}
430
431fn main() { S::foo(<|>); }
432"#,
433 expect![[r#"
434 fn foo(self: &S, x: i32)
435 (<self: &S>, x: i32)
436 "#]],
437 );
438 }
439
440 #[test]
441 fn test_fn_signature_with_docs_simple() {
442 check(
443 r#"
444/// test
445// non-doc-comment
446fn foo(j: u32) -> u32 {
447 j
448}
449
450fn bar() {
451 let _ = foo(<|>);
452}
453"#,
454 expect![[r#"
455 test
456 ------
457 fn foo(j: u32) -> u32
458 (<j: u32>)
459 "#]],
460 );
461 }
462
463 #[test]
464 fn test_fn_signature_with_docs() {
465 check(
466 r#"
467/// Adds one to the number given.
468///
469/// # Examples
470///
471/// ```
472/// let five = 5;
473///
474/// assert_eq!(6, my_crate::add_one(5));
475/// ```
476pub fn add_one(x: i32) -> i32 {
477 x + 1
478}
479
480pub fn do() {
481 add_one(<|>
482}"#,
483 expect![[r##"
484 Adds one to the number given.
485
486 # Examples
487
488 ```
489 let five = 5;
490
491 assert_eq!(6, my_crate::add_one(5));
492 ```
493 ------
494 fn add_one(x: i32) -> i32
495 (<x: i32>)
496 "##]],
497 );
498 }
499
500 #[test]
501 fn test_fn_signature_with_docs_impl() {
502 check(
503 r#"
504struct addr;
505impl addr {
506 /// Adds one to the number given.
507 ///
508 /// # Examples
509 ///
510 /// ```
511 /// let five = 5;
512 ///
513 /// assert_eq!(6, my_crate::add_one(5));
514 /// ```
515 pub fn add_one(x: i32) -> i32 {
516 x + 1
517 }
518}
519
520pub fn do_it() {
521 addr {};
522 addr::add_one(<|>);
523}
524"#,
525 expect![[r##"
526 Adds one to the number given.
527
528 # Examples
529
530 ```
531 let five = 5;
532
533 assert_eq!(6, my_crate::add_one(5));
534 ```
535 ------
536 fn add_one(x: i32) -> i32
537 (<x: i32>)
538 "##]],
539 );
540 }
541
542 #[test]
543 fn test_fn_signature_with_docs_from_actix() {
544 check(
545 r#"
546struct WriteHandler<E>;
547
548impl<E> WriteHandler<E> {
549 /// Method is called when writer emits error.
550 ///
551 /// If this method returns `ErrorAction::Continue` writer processing
552 /// continues otherwise stream processing stops.
553 fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
554 Running::Stop
555 }
556
557 /// Method is called when writer finishes.
558 ///
559 /// By default this method stops actor's `Context`.
560 fn finished(&mut self, ctx: &mut Self::Context) {
561 ctx.stop()
562 }
563}
564
565pub fn foo(mut r: WriteHandler<()>) {
566 r.finished(<|>);
567}
568"#,
569 expect![[r#"
570 Method is called when writer finishes.
571
572 By default this method stops actor's `Context`.
573 ------
574 fn finished(&mut self, ctx: &mut {unknown})
575 (<ctx: &mut {unknown}>)
576 "#]],
577 );
578 }
579
580 #[test]
581 fn call_info_bad_offset() {
582 mark::check!(call_info_bad_offset);
583 check(
584 r#"
585fn foo(x: u32, y: u32) -> u32 {x + y}
586fn bar() { foo <|> (3, ); }
587"#,
588 expect![[""]],
589 );
590 }
591
592 #[test]
593 fn test_nested_method_in_lambda() {
594 check(
595 r#"
596struct Foo;
597impl Foo { fn bar(&self, _: u32) { } }
598
599fn bar(_: u32) { }
600
601fn main() {
602 let foo = Foo;
603 std::thread::spawn(move || foo.bar(<|>));
604}
605"#,
606 expect![[r#"
607 fn bar(&self, _: u32)
608 (<_: u32>)
609 "#]],
610 );
611 }
612
613 #[test]
614 fn works_for_tuple_structs() {
615 check(
616 r#"
617/// A cool tuple struct
618struct S(u32, i32);
619fn main() {
620 let s = S(0, <|>);
621}
622"#,
623 expect![[r#"
624 A cool tuple struct
625 ------
626 struct S(u32, i32)
627 (u32, <i32>)
628 "#]],
629 );
630 }
631
632 #[test]
633 fn generic_struct() {
634 check(
635 r#"
636struct S<T>(T);
637fn main() {
638 let s = S(<|>);
639}
640"#,
641 expect![[r#"
642 struct S({unknown})
643 (<{unknown}>)
644 "#]],
645 );
646 }
647
648 #[test]
649 fn works_for_enum_variants() {
650 check(
651 r#"
652enum E {
653 /// A Variant
654 A(i32),
655 /// Another
656 B,
657 /// And C
658 C { a: i32, b: i32 }
659}
660
661fn main() {
662 let a = E::A(<|>);
663}
664"#,
665 expect![[r#"
666 A Variant
667 ------
668 enum E::A(i32)
669 (<i32>)
670 "#]],
671 );
672 }
673
674 #[test]
675 fn cant_call_struct_record() {
676 check(
677 r#"
678struct S { x: u32, y: i32 }
679fn main() {
680 let s = S(<|>);
681}
682"#,
683 expect![[""]],
684 );
685 }
686
687 #[test]
688 fn cant_call_enum_record() {
689 check(
690 r#"
691enum E {
692 /// A Variant
693 A(i32),
694 /// Another
695 B,
696 /// And C
697 C { a: i32, b: i32 }
698}
699
700fn main() {
701 let a = E::C(<|>);
702}
703"#,
704 expect![[""]],
705 );
706 }
707
708 #[test]
709 fn fn_signature_for_call_in_macro() {
710 check(
711 r#"
712macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
713fn foo() { }
714id! {
715 fn bar() { foo(<|>); }
716}
717"#,
718 expect![[r#"
719 fn foo()
720 ()
721 "#]],
722 );
723 }
724
725 #[test]
726 fn call_info_for_lambdas() {
727 check(
728 r#"
729struct S;
730fn foo(s: S) -> i32 { 92 }
731fn main() {
732 (|s| foo(s))(<|>)
733}
734 "#,
735 expect![[r#"
736 (S) -> i32
737 (<S>)
738 "#]],
739 )
740 }
741
742 #[test]
743 fn call_info_for_fn_ptr() {
744 check(
745 r#"
746fn main(f: fn(i32, f64) -> char) {
747 f(0, <|>)
748}
749 "#,
750 expect![[r#"
751 (i32, f64) -> char
752 (i32, <f64>)
753 "#]],
754 )
755 }
756}
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs
new file mode 100644
index 000000000..9335aeaa5
--- /dev/null
+++ b/crates/ide_db/src/call_info/tests.rs
@@ -0,0 +1,523 @@
1use crate::RootDatabase;
2use base_db::{fixture::ChangeFixture, FilePosition};
3use expect_test::{expect, Expect};
4use test_utils::{mark, RangeOrOffset};
5
6/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
7pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
8 let change_fixture = ChangeFixture::parse(ra_fixture);
9 let mut database = RootDatabase::default();
10 database.apply_change(change_fixture.change);
11 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
12 let offset = match range_or_offset {
13 RangeOrOffset::Range(_) => panic!(),
14 RangeOrOffset::Offset(it) => it,
15 };
16 (database, FilePosition { file_id, offset })
17}
18
19fn check(ra_fixture: &str, expect: Expect) {
20 let (db, position) = position(ra_fixture);
21 let call_info = crate::call_info::call_info(&db, position);
22 let actual = match call_info {
23 Some(call_info) => {
24 let docs = match &call_info.doc {
25 None => "".to_string(),
26 Some(docs) => format!("{}\n------\n", docs.as_str()),
27 };
28 let params = call_info
29 .parameter_labels()
30 .enumerate()
31 .map(|(i, param)| {
32 if Some(i) == call_info.active_parameter {
33 format!("<{}>", param)
34 } else {
35 param.to_string()
36 }
37 })
38 .collect::<Vec<_>>()
39 .join(", ");
40 format!("{}{}\n({})\n", docs, call_info.signature, params)
41 }
42 None => String::new(),
43 };
44 expect.assert_eq(&actual);
45}
46
47#[test]
48fn test_fn_signature_two_args() {
49 check(
50 r#"
51fn foo(x: u32, y: u32) -> u32 {x + y}
52fn bar() { foo(<|>3, ); }
53"#,
54 expect![[r#"
55 fn foo(x: u32, y: u32) -> u32
56 (<x: u32>, y: u32)
57 "#]],
58 );
59 check(
60 r#"
61fn foo(x: u32, y: u32) -> u32 {x + y}
62fn bar() { foo(3<|>, ); }
63"#,
64 expect![[r#"
65 fn foo(x: u32, y: u32) -> u32
66 (<x: u32>, y: u32)
67 "#]],
68 );
69 check(
70 r#"
71fn foo(x: u32, y: u32) -> u32 {x + y}
72fn bar() { foo(3,<|> ); }
73"#,
74 expect![[r#"
75 fn foo(x: u32, y: u32) -> u32
76 (x: u32, <y: u32>)
77 "#]],
78 );
79 check(
80 r#"
81fn foo(x: u32, y: u32) -> u32 {x + y}
82fn bar() { foo(3, <|>); }
83"#,
84 expect![[r#"
85 fn foo(x: u32, y: u32) -> u32
86 (x: u32, <y: u32>)
87 "#]],
88 );
89}
90
91#[test]
92fn test_fn_signature_two_args_empty() {
93 check(
94 r#"
95fn foo(x: u32, y: u32) -> u32 {x + y}
96fn bar() { foo(<|>); }
97"#,
98 expect![[r#"
99 fn foo(x: u32, y: u32) -> u32
100 (<x: u32>, y: u32)
101 "#]],
102 );
103}
104
105#[test]
106fn test_fn_signature_two_args_first_generics() {
107 check(
108 r#"
109fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
110 where T: Copy + Display, U: Debug
111{ x + y }
112
113fn bar() { foo(<|>3, ); }
114"#,
115 expect![[r#"
116 fn foo(x: i32, y: {unknown}) -> u32
117 (<x: i32>, y: {unknown})
118 "#]],
119 );
120}
121
122#[test]
123fn test_fn_signature_no_params() {
124 check(
125 r#"
126fn foo<T>() -> T where T: Copy + Display {}
127fn bar() { foo(<|>); }
128"#,
129 expect![[r#"
130 fn foo() -> {unknown}
131 ()
132 "#]],
133 );
134}
135
136#[test]
137fn test_fn_signature_for_impl() {
138 check(
139 r#"
140struct F;
141impl F { pub fn new() { } }
142fn bar() {
143 let _ : F = F::new(<|>);
144}
145"#,
146 expect![[r#"
147 fn new()
148 ()
149 "#]],
150 );
151}
152
153#[test]
154fn test_fn_signature_for_method_self() {
155 check(
156 r#"
157struct S;
158impl S { pub fn do_it(&self) {} }
159
160fn bar() {
161 let s: S = S;
162 s.do_it(<|>);
163}
164"#,
165 expect![[r#"
166 fn do_it(&self)
167 ()
168 "#]],
169 );
170}
171
172#[test]
173fn test_fn_signature_for_method_with_arg() {
174 check(
175 r#"
176struct S;
177impl S {
178 fn foo(&self, x: i32) {}
179}
180
181fn main() { S.foo(<|>); }
182"#,
183 expect![[r#"
184 fn foo(&self, x: i32)
185 (<x: i32>)
186 "#]],
187 );
188}
189
190#[test]
191fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
192 check(
193 r#"
194struct S;
195impl S {
196 fn foo(&self, x: i32) {}
197}
198
199fn main() { S::foo(<|>); }
200"#,
201 expect![[r#"
202 fn foo(self: &S, x: i32)
203 (<self: &S>, x: i32)
204 "#]],
205 );
206}
207
208#[test]
209fn test_fn_signature_with_docs_simple() {
210 check(
211 r#"
212/// test
213// non-doc-comment
214fn foo(j: u32) -> u32 {
215 j
216}
217
218fn bar() {
219 let _ = foo(<|>);
220}
221"#,
222 expect![[r#"
223 test
224 ------
225 fn foo(j: u32) -> u32
226 (<j: u32>)
227 "#]],
228 );
229}
230
231#[test]
232fn test_fn_signature_with_docs() {
233 check(
234 r#"
235/// Adds one to the number given.
236///
237/// # Examples
238///
239/// ```
240/// let five = 5;
241///
242/// assert_eq!(6, my_crate::add_one(5));
243/// ```
244pub fn add_one(x: i32) -> i32 {
245 x + 1
246}
247
248pub fn do() {
249 add_one(<|>
250}"#,
251 expect![[r##"
252 Adds one to the number given.
253
254 # Examples
255
256 ```
257 let five = 5;
258
259 assert_eq!(6, my_crate::add_one(5));
260 ```
261 ------
262 fn add_one(x: i32) -> i32
263 (<x: i32>)
264 "##]],
265 );
266}
267
268#[test]
269fn test_fn_signature_with_docs_impl() {
270 check(
271 r#"
272struct addr;
273impl addr {
274 /// Adds one to the number given.
275 ///
276 /// # Examples
277 ///
278 /// ```
279 /// let five = 5;
280 ///
281 /// assert_eq!(6, my_crate::add_one(5));
282 /// ```
283 pub fn add_one(x: i32) -> i32 {
284 x + 1
285 }
286}
287
288pub fn do_it() {
289 addr {};
290 addr::add_one(<|>);
291}
292"#,
293 expect![[r##"
294 Adds one to the number given.
295
296 # Examples
297
298 ```
299 let five = 5;
300
301 assert_eq!(6, my_crate::add_one(5));
302 ```
303 ------
304 fn add_one(x: i32) -> i32
305 (<x: i32>)
306 "##]],
307 );
308}
309
310#[test]
311fn test_fn_signature_with_docs_from_actix() {
312 check(
313 r#"
314struct WriteHandler<E>;
315
316impl<E> WriteHandler<E> {
317 /// Method is called when writer emits error.
318 ///
319 /// If this method returns `ErrorAction::Continue` writer processing
320 /// continues otherwise stream processing stops.
321 fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
322 Running::Stop
323 }
324
325 /// Method is called when writer finishes.
326 ///
327 /// By default this method stops actor's `Context`.
328 fn finished(&mut self, ctx: &mut Self::Context) {
329 ctx.stop()
330 }
331}
332
333pub fn foo(mut r: WriteHandler<()>) {
334 r.finished(<|>);
335}
336"#,
337 expect![[r#"
338 Method is called when writer finishes.
339
340 By default this method stops actor's `Context`.
341 ------
342 fn finished(&mut self, ctx: &mut {unknown})
343 (<ctx: &mut {unknown}>)
344 "#]],
345 );
346}
347
348#[test]
349fn call_info_bad_offset() {
350 mark::check!(call_info_bad_offset);
351 check(
352 r#"
353fn foo(x: u32, y: u32) -> u32 {x + y}
354fn bar() { foo <|> (3, ); }
355"#,
356 expect![[""]],
357 );
358}
359
360#[test]
361fn test_nested_method_in_lambda() {
362 check(
363 r#"
364struct Foo;
365impl Foo { fn bar(&self, _: u32) { } }
366
367fn bar(_: u32) { }
368
369fn main() {
370 let foo = Foo;
371 std::thread::spawn(move || foo.bar(<|>));
372}
373"#,
374 expect![[r#"
375 fn bar(&self, _: u32)
376 (<_: u32>)
377 "#]],
378 );
379}
380
381#[test]
382fn works_for_tuple_structs() {
383 check(
384 r#"
385/// A cool tuple struct
386struct S(u32, i32);
387fn main() {
388 let s = S(0, <|>);
389}
390"#,
391 expect![[r#"
392 A cool tuple struct
393 ------
394 struct S(u32, i32)
395 (u32, <i32>)
396 "#]],
397 );
398}
399
400#[test]
401fn generic_struct() {
402 check(
403 r#"
404struct S<T>(T);
405fn main() {
406 let s = S(<|>);
407}
408"#,
409 expect![[r#"
410 struct S({unknown})
411 (<{unknown}>)
412 "#]],
413 );
414}
415
416#[test]
417fn works_for_enum_variants() {
418 check(
419 r#"
420enum E {
421 /// A Variant
422 A(i32),
423 /// Another
424 B,
425 /// And C
426 C { a: i32, b: i32 }
427}
428
429fn main() {
430 let a = E::A(<|>);
431}
432"#,
433 expect![[r#"
434 A Variant
435 ------
436 enum E::A(i32)
437 (<i32>)
438 "#]],
439 );
440}
441
442#[test]
443fn cant_call_struct_record() {
444 check(
445 r#"
446struct S { x: u32, y: i32 }
447fn main() {
448 let s = S(<|>);
449}
450"#,
451 expect![[""]],
452 );
453}
454
455#[test]
456fn cant_call_enum_record() {
457 check(
458 r#"
459enum E {
460 /// A Variant
461 A(i32),
462 /// Another
463 B,
464 /// And C
465 C { a: i32, b: i32 }
466}
467
468fn main() {
469 let a = E::C(<|>);
470}
471"#,
472 expect![[""]],
473 );
474}
475
476#[test]
477fn fn_signature_for_call_in_macro() {
478 check(
479 r#"
480macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
481fn foo() { }
482id! {
483 fn bar() { foo(<|>); }
484}
485"#,
486 expect![[r#"
487 fn foo()
488 ()
489 "#]],
490 );
491}
492
493#[test]
494fn call_info_for_lambdas() {
495 check(
496 r#"
497struct S;
498fn foo(s: S) -> i32 { 92 }
499fn main() {
500 (|s| foo(s))(<|>)
501}
502 "#,
503 expect![[r#"
504 (S) -> i32
505 (<S>)
506 "#]],
507 )
508}
509
510#[test]
511fn call_info_for_fn_ptr() {
512 check(
513 r#"
514fn main(f: fn(i32, f64) -> char) {
515 f(0, <|>)
516}
517 "#,
518 expect![[r#"
519 (i32, f64) -> char
520 (i32, <f64>)
521 "#]],
522 )
523}
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 201a3d6fa..5d2cd30d1 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -258,7 +258,7 @@ impl NameRefClass {
258 sema: &Semantics<RootDatabase>, 258 sema: &Semantics<RootDatabase>,
259 name_ref: &ast::NameRef, 259 name_ref: &ast::NameRef,
260 ) -> Option<NameRefClass> { 260 ) -> Option<NameRefClass> {
261 let _p = profile::span("classify_name_ref"); 261 let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string());
262 262
263 let parent = name_ref.syntax().parent()?; 263 let parent = name_ref.syntax().parent()?;
264 264
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 08d246c16..040843990 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -573,641 +573,4 @@ fn find_insert_position(
573} 573}
574 574
575#[cfg(test)] 575#[cfg(test)]
576mod tests { 576mod tests;
577 use super::*;
578
579 use test_utils::assert_eq_text;
580
581 #[test]
582 fn insert_existing() {
583 check_full("std::fs", "use std::fs;", "use std::fs;")
584 }
585
586 #[test]
587 fn insert_start() {
588 check_none(
589 "std::bar::AA",
590 r"
591use std::bar::B;
592use std::bar::D;
593use std::bar::F;
594use std::bar::G;",
595 r"
596use std::bar::AA;
597use std::bar::B;
598use std::bar::D;
599use std::bar::F;
600use std::bar::G;",
601 )
602 }
603
604 #[test]
605 fn insert_start_indent() {
606 mark::check!(insert_use_indent_after);
607 check_none(
608 "std::bar::AA",
609 r"
610 use std::bar::B;
611 use std::bar::D;",
612 r"
613 use std::bar::AA;
614 use std::bar::B;
615 use std::bar::D;",
616 )
617 }
618
619 #[test]
620 fn insert_middle() {
621 check_none(
622 "std::bar::EE",
623 r"
624use std::bar::A;
625use std::bar::D;
626use std::bar::F;
627use std::bar::G;",
628 r"
629use std::bar::A;
630use std::bar::D;
631use std::bar::EE;
632use std::bar::F;
633use std::bar::G;",
634 )
635 }
636
637 #[test]
638 fn insert_middle_indent() {
639 check_none(
640 "std::bar::EE",
641 r"
642 use std::bar::A;
643 use std::bar::D;
644 use std::bar::F;
645 use std::bar::G;",
646 r"
647 use std::bar::A;
648 use std::bar::D;
649 use std::bar::EE;
650 use std::bar::F;
651 use std::bar::G;",
652 )
653 }
654
655 #[test]
656 fn insert_end() {
657 check_none(
658 "std::bar::ZZ",
659 r"
660use std::bar::A;
661use std::bar::D;
662use std::bar::F;
663use std::bar::G;",
664 r"
665use std::bar::A;
666use std::bar::D;
667use std::bar::F;
668use std::bar::G;
669use std::bar::ZZ;",
670 )
671 }
672
673 #[test]
674 fn insert_end_indent() {
675 mark::check!(insert_use_indent_before);
676 check_none(
677 "std::bar::ZZ",
678 r"
679 use std::bar::A;
680 use std::bar::D;
681 use std::bar::F;
682 use std::bar::G;",
683 r"
684 use std::bar::A;
685 use std::bar::D;
686 use std::bar::F;
687 use std::bar::G;
688 use std::bar::ZZ;",
689 )
690 }
691
692 #[test]
693 fn insert_middle_nested() {
694 check_none(
695 "std::bar::EE",
696 r"
697use std::bar::A;
698use std::bar::{D, Z}; // example of weird imports due to user
699use std::bar::F;
700use std::bar::G;",
701 r"
702use std::bar::A;
703use std::bar::EE;
704use std::bar::{D, Z}; // example of weird imports due to user
705use std::bar::F;
706use std::bar::G;",
707 )
708 }
709
710 #[test]
711 fn insert_middle_groups() {
712 check_none(
713 "foo::bar::GG",
714 r"
715 use std::bar::A;
716 use std::bar::D;
717
718 use foo::bar::F;
719 use foo::bar::H;",
720 r"
721 use std::bar::A;
722 use std::bar::D;
723
724 use foo::bar::F;
725 use foo::bar::GG;
726 use foo::bar::H;",
727 )
728 }
729
730 #[test]
731 fn insert_first_matching_group() {
732 check_none(
733 "foo::bar::GG",
734 r"
735 use foo::bar::A;
736 use foo::bar::D;
737
738 use std;
739
740 use foo::bar::F;
741 use foo::bar::H;",
742 r"
743 use foo::bar::A;
744 use foo::bar::D;
745 use foo::bar::GG;
746
747 use std;
748
749 use foo::bar::F;
750 use foo::bar::H;",
751 )
752 }
753
754 #[test]
755 fn insert_missing_group_std() {
756 check_none(
757 "std::fmt",
758 r"
759 use foo::bar::A;
760 use foo::bar::D;",
761 r"
762 use std::fmt;
763
764 use foo::bar::A;
765 use foo::bar::D;",
766 )
767 }
768
769 #[test]
770 fn insert_missing_group_self() {
771 check_none(
772 "self::fmt",
773 r"
774use foo::bar::A;
775use foo::bar::D;",
776 r"
777use foo::bar::A;
778use foo::bar::D;
779
780use self::fmt;",
781 )
782 }
783
784 #[test]
785 fn insert_no_imports() {
786 check_full(
787 "foo::bar",
788 "fn main() {}",
789 r"use foo::bar;
790
791fn main() {}",
792 )
793 }
794
795 #[test]
796 fn insert_empty_file() {
797 // empty files will get two trailing newlines
798 // this is due to the test case insert_no_imports above
799 check_full(
800 "foo::bar",
801 "",
802 r"use foo::bar;
803
804",
805 )
806 }
807
808 #[test]
809 fn insert_empty_module() {
810 mark::check!(insert_use_no_indent_after);
811 check(
812 "foo::bar",
813 "mod x {}",
814 r"{
815 use foo::bar;
816}",
817 None,
818 true,
819 )
820 }
821
822 #[test]
823 fn insert_after_inner_attr() {
824 check_full(
825 "foo::bar",
826 r"#![allow(unused_imports)]",
827 r"#![allow(unused_imports)]
828
829use foo::bar;",
830 )
831 }
832
833 #[test]
834 fn insert_after_inner_attr2() {
835 check_full(
836 "foo::bar",
837 r"#![allow(unused_imports)]
838
839#![no_std]
840fn main() {}",
841 r"#![allow(unused_imports)]
842
843#![no_std]
844
845use foo::bar;
846fn main() {}",
847 );
848 }
849
850 #[test]
851 fn inserts_after_single_line_inner_comments() {
852 check_none(
853 "foo::bar::Baz",
854 "//! Single line inner comments do not allow any code before them.",
855 r#"//! Single line inner comments do not allow any code before them.
856
857use foo::bar::Baz;"#,
858 );
859 }
860
861 #[test]
862 fn inserts_after_multiline_inner_comments() {
863 check_none(
864 "foo::bar::Baz",
865 r#"/*! Multiline inner comments do not allow any code before them. */
866
867/*! Still an inner comment, cannot place any code before. */
868fn main() {}"#,
869 r#"/*! Multiline inner comments do not allow any code before them. */
870
871/*! Still an inner comment, cannot place any code before. */
872
873use foo::bar::Baz;
874fn main() {}"#,
875 )
876 }
877
878 #[test]
879 fn inserts_after_all_inner_items() {
880 check_none(
881 "foo::bar::Baz",
882 r#"#![allow(unused_imports)]
883/*! Multiline line comment 2 */
884
885
886//! Single line comment 1
887#![no_std]
888//! Single line comment 2
889fn main() {}"#,
890 r#"#![allow(unused_imports)]
891/*! Multiline line comment 2 */
892
893
894//! Single line comment 1
895#![no_std]
896//! Single line comment 2
897
898use foo::bar::Baz;
899fn main() {}"#,
900 )
901 }
902
903 #[test]
904 fn merge_groups() {
905 check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
906 }
907
908 #[test]
909 fn merge_groups_last() {
910 check_last(
911 "std::io",
912 r"use std::fmt::{Result, Display};",
913 r"use std::fmt::{Result, Display};
914use std::io;",
915 )
916 }
917
918 #[test]
919 fn merge_last_into_self() {
920 check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
921 }
922
923 #[test]
924 fn merge_groups_full() {
925 check_full(
926 "std::io",
927 r"use std::fmt::{Result, Display};",
928 r"use std::{fmt::{Result, Display}, io};",
929 )
930 }
931
932 #[test]
933 fn merge_groups_long_full() {
934 check_full(
935 "std::foo::bar::Baz",
936 r"use std::foo::bar::Qux;",
937 r"use std::foo::bar::{Baz, Qux};",
938 )
939 }
940
941 #[test]
942 fn merge_groups_long_last() {
943 check_last(
944 "std::foo::bar::Baz",
945 r"use std::foo::bar::Qux;",
946 r"use std::foo::bar::{Baz, Qux};",
947 )
948 }
949
950 #[test]
951 fn merge_groups_long_full_list() {
952 check_full(
953 "std::foo::bar::Baz",
954 r"use std::foo::bar::{Qux, Quux};",
955 r"use std::foo::bar::{Baz, Quux, Qux};",
956 )
957 }
958
959 #[test]
960 fn merge_groups_long_last_list() {
961 check_last(
962 "std::foo::bar::Baz",
963 r"use std::foo::bar::{Qux, Quux};",
964 r"use std::foo::bar::{Baz, Quux, Qux};",
965 )
966 }
967
968 #[test]
969 fn merge_groups_long_full_nested() {
970 check_full(
971 "std::foo::bar::Baz",
972 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
973 r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
974 )
975 }
976
977 #[test]
978 fn merge_groups_long_last_nested() {
979 check_last(
980 "std::foo::bar::Baz",
981 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
982 r"use std::foo::bar::Baz;
983use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
984 )
985 }
986
987 #[test]
988 fn merge_groups_full_nested_deep() {
989 check_full(
990 "std::foo::bar::quux::Baz",
991 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
992 r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
993 )
994 }
995
996 #[test]
997 fn merge_groups_full_nested_long() {
998 check_full(
999 "std::foo::bar::Baz",
1000 r"use std::{foo::bar::Qux};",
1001 r"use std::{foo::bar::{Baz, Qux}};",
1002 );
1003 }
1004
1005 #[test]
1006 fn merge_groups_last_nested_long() {
1007 check_full(
1008 "std::foo::bar::Baz",
1009 r"use std::{foo::bar::Qux};",
1010 r"use std::{foo::bar::{Baz, Qux}};",
1011 );
1012 }
1013
1014 #[test]
1015 fn merge_groups_skip_pub() {
1016 check_full(
1017 "std::io",
1018 r"pub use std::fmt::{Result, Display};",
1019 r"pub use std::fmt::{Result, Display};
1020use std::io;",
1021 )
1022 }
1023
1024 #[test]
1025 fn merge_groups_skip_pub_crate() {
1026 check_full(
1027 "std::io",
1028 r"pub(crate) use std::fmt::{Result, Display};",
1029 r"pub(crate) use std::fmt::{Result, Display};
1030use std::io;",
1031 )
1032 }
1033
1034 #[test]
1035 #[ignore] // FIXME: Support this
1036 fn split_out_merge() {
1037 check_last(
1038 "std::fmt::Result",
1039 r"use std::{fmt, io};",
1040 r"use std::fmt::{self, Result};
1041use std::io;",
1042 )
1043 }
1044
1045 #[test]
1046 fn merge_into_module_import() {
1047 check_full(
1048 "std::fmt::Result",
1049 r"use std::{fmt, io};",
1050 r"use std::{fmt::{self, Result}, io};",
1051 )
1052 }
1053
1054 #[test]
1055 fn merge_groups_self() {
1056 check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
1057 }
1058
1059 #[test]
1060 fn merge_mod_into_glob() {
1061 check_full(
1062 "token::TokenKind",
1063 r"use token::TokenKind::*;",
1064 r"use token::TokenKind::{*, self};",
1065 )
1066 // FIXME: have it emit `use token::TokenKind::{self, *}`?
1067 }
1068
1069 #[test]
1070 fn merge_self_glob() {
1071 check_full("self", r"use self::*;", r"use self::{*, self};")
1072 // FIXME: have it emit `use {self, *}`?
1073 }
1074
1075 #[test]
1076 fn merge_glob_nested() {
1077 check_full(
1078 "foo::bar::quux::Fez",
1079 r"use foo::bar::{Baz, quux::*};",
1080 r"use foo::bar::{Baz, quux::{self::*, Fez}};",
1081 )
1082 }
1083
1084 #[test]
1085 fn merge_nested_considers_first_segments() {
1086 check_full(
1087 "hir_ty::display::write_bounds_like_dyn_trait",
1088 r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
1089 r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
1090 );
1091 }
1092
1093 #[test]
1094 fn skip_merge_last_too_long() {
1095 check_last(
1096 "foo::bar",
1097 r"use foo::bar::baz::Qux;",
1098 r"use foo::bar;
1099use foo::bar::baz::Qux;",
1100 );
1101 }
1102
1103 #[test]
1104 fn skip_merge_last_too_long2() {
1105 check_last(
1106 "foo::bar::baz::Qux",
1107 r"use foo::bar;",
1108 r"use foo::bar;
1109use foo::bar::baz::Qux;",
1110 );
1111 }
1112
1113 #[test]
1114 fn insert_short_before_long() {
1115 check_none(
1116 "foo::bar",
1117 r"use foo::bar::baz::Qux;",
1118 r"use foo::bar;
1119use foo::bar::baz::Qux;",
1120 );
1121 }
1122
1123 #[test]
1124 fn merge_last_fail() {
1125 check_merge_only_fail(
1126 r"use foo::bar::{baz::{Qux, Fez}};",
1127 r"use foo::bar::{baaz::{Quux, Feez}};",
1128 MergeBehaviour::Last,
1129 );
1130 }
1131
1132 #[test]
1133 fn merge_last_fail1() {
1134 check_merge_only_fail(
1135 r"use foo::bar::{baz::{Qux, Fez}};",
1136 r"use foo::bar::baaz::{Quux, Feez};",
1137 MergeBehaviour::Last,
1138 );
1139 }
1140
1141 #[test]
1142 fn merge_last_fail2() {
1143 check_merge_only_fail(
1144 r"use foo::bar::baz::{Qux, Fez};",
1145 r"use foo::bar::{baaz::{Quux, Feez}};",
1146 MergeBehaviour::Last,
1147 );
1148 }
1149
1150 #[test]
1151 fn merge_last_fail3() {
1152 check_merge_only_fail(
1153 r"use foo::bar::baz::{Qux, Fez};",
1154 r"use foo::bar::baaz::{Quux, Feez};",
1155 MergeBehaviour::Last,
1156 );
1157 }
1158
1159 fn check(
1160 path: &str,
1161 ra_fixture_before: &str,
1162 ra_fixture_after: &str,
1163 mb: Option<MergeBehaviour>,
1164 module: bool,
1165 ) {
1166 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
1167 if module {
1168 syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
1169 }
1170 let file = super::ImportScope::from(syntax).unwrap();
1171 let path = ast::SourceFile::parse(&format!("use {};", path))
1172 .tree()
1173 .syntax()
1174 .descendants()
1175 .find_map(ast::Path::cast)
1176 .unwrap();
1177
1178 let rewriter = insert_use(&file, path, mb);
1179 let result = rewriter.rewrite(file.as_syntax_node()).to_string();
1180 assert_eq_text!(&result, ra_fixture_after);
1181 }
1182
1183 fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1184 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false)
1185 }
1186
1187 fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1188 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false)
1189 }
1190
1191 fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1192 check(path, ra_fixture_before, ra_fixture_after, None, false)
1193 }
1194
1195 fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) {
1196 let use0 = ast::SourceFile::parse(ra_fixture0)
1197 .tree()
1198 .syntax()
1199 .descendants()
1200 .find_map(ast::Use::cast)
1201 .unwrap();
1202
1203 let use1 = ast::SourceFile::parse(ra_fixture1)
1204 .tree()
1205 .syntax()
1206 .descendants()
1207 .find_map(ast::Use::cast)
1208 .unwrap();
1209
1210 let result = try_merge_imports(&use0, &use1, mb);
1211 assert_eq!(result.map(|u| u.to_string()), None);
1212 }
1213}
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
new file mode 100644
index 000000000..86bfa5b41
--- /dev/null
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -0,0 +1,620 @@
1use super::*;
2
3use test_utils::assert_eq_text;
4
5#[test]
6fn insert_existing() {
7 check_full("std::fs", "use std::fs;", "use std::fs;")
8}
9
10#[test]
11fn insert_start() {
12 check_none(
13 "std::bar::AA",
14 r"
15use std::bar::B;
16use std::bar::D;
17use std::bar::F;
18use std::bar::G;",
19 r"
20use std::bar::AA;
21use std::bar::B;
22use std::bar::D;
23use std::bar::F;
24use std::bar::G;",
25 )
26}
27
28#[test]
29fn insert_start_indent() {
30 mark::check!(insert_use_indent_after);
31 check_none(
32 "std::bar::AA",
33 r"
34 use std::bar::B;
35 use std::bar::D;",
36 r"
37 use std::bar::AA;
38 use std::bar::B;
39 use std::bar::D;",
40 )
41}
42
43#[test]
44fn insert_middle() {
45 check_none(
46 "std::bar::EE",
47 r"
48use std::bar::A;
49use std::bar::D;
50use std::bar::F;
51use std::bar::G;",
52 r"
53use std::bar::A;
54use std::bar::D;
55use std::bar::EE;
56use std::bar::F;
57use std::bar::G;",
58 )
59}
60
61#[test]
62fn insert_middle_indent() {
63 check_none(
64 "std::bar::EE",
65 r"
66 use std::bar::A;
67 use std::bar::D;
68 use std::bar::F;
69 use std::bar::G;",
70 r"
71 use std::bar::A;
72 use std::bar::D;
73 use std::bar::EE;
74 use std::bar::F;
75 use std::bar::G;",
76 )
77}
78
79#[test]
80fn insert_end() {
81 check_none(
82 "std::bar::ZZ",
83 r"
84use std::bar::A;
85use std::bar::D;
86use std::bar::F;
87use std::bar::G;",
88 r"
89use std::bar::A;
90use std::bar::D;
91use std::bar::F;
92use std::bar::G;
93use std::bar::ZZ;",
94 )
95}
96
97#[test]
98fn insert_end_indent() {
99 mark::check!(insert_use_indent_before);
100 check_none(
101 "std::bar::ZZ",
102 r"
103 use std::bar::A;
104 use std::bar::D;
105 use std::bar::F;
106 use std::bar::G;",
107 r"
108 use std::bar::A;
109 use std::bar::D;
110 use std::bar::F;
111 use std::bar::G;
112 use std::bar::ZZ;",
113 )
114}
115
116#[test]
117fn insert_middle_nested() {
118 check_none(
119 "std::bar::EE",
120 r"
121use std::bar::A;
122use std::bar::{D, Z}; // example of weird imports due to user
123use std::bar::F;
124use std::bar::G;",
125 r"
126use std::bar::A;
127use std::bar::EE;
128use std::bar::{D, Z}; // example of weird imports due to user
129use std::bar::F;
130use std::bar::G;",
131 )
132}
133
134#[test]
135fn insert_middle_groups() {
136 check_none(
137 "foo::bar::GG",
138 r"
139 use std::bar::A;
140 use std::bar::D;
141
142 use foo::bar::F;
143 use foo::bar::H;",
144 r"
145 use std::bar::A;
146 use std::bar::D;
147
148 use foo::bar::F;
149 use foo::bar::GG;
150 use foo::bar::H;",
151 )
152}
153
154#[test]
155fn insert_first_matching_group() {
156 check_none(
157 "foo::bar::GG",
158 r"
159 use foo::bar::A;
160 use foo::bar::D;
161
162 use std;
163
164 use foo::bar::F;
165 use foo::bar::H;",
166 r"
167 use foo::bar::A;
168 use foo::bar::D;
169 use foo::bar::GG;
170
171 use std;
172
173 use foo::bar::F;
174 use foo::bar::H;",
175 )
176}
177
178#[test]
179fn insert_missing_group_std() {
180 check_none(
181 "std::fmt",
182 r"
183 use foo::bar::A;
184 use foo::bar::D;",
185 r"
186 use std::fmt;
187
188 use foo::bar::A;
189 use foo::bar::D;",
190 )
191}
192
193#[test]
194fn insert_missing_group_self() {
195 check_none(
196 "self::fmt",
197 r"
198use foo::bar::A;
199use foo::bar::D;",
200 r"
201use foo::bar::A;
202use foo::bar::D;
203
204use self::fmt;",
205 )
206}
207
208#[test]
209fn insert_no_imports() {
210 check_full(
211 "foo::bar",
212 "fn main() {}",
213 r"use foo::bar;
214
215fn main() {}",
216 )
217}
218
219#[test]
220fn insert_empty_file() {
221 // empty files will get two trailing newlines
222 // this is due to the test case insert_no_imports above
223 check_full(
224 "foo::bar",
225 "",
226 r"use foo::bar;
227
228",
229 )
230}
231
232#[test]
233fn insert_empty_module() {
234 mark::check!(insert_use_no_indent_after);
235 check(
236 "foo::bar",
237 "mod x {}",
238 r"{
239 use foo::bar;
240}",
241 None,
242 true,
243 )
244}
245
246#[test]
247fn insert_after_inner_attr() {
248 check_full(
249 "foo::bar",
250 r"#![allow(unused_imports)]",
251 r"#![allow(unused_imports)]
252
253use foo::bar;",
254 )
255}
256
257#[test]
258fn insert_after_inner_attr2() {
259 check_full(
260 "foo::bar",
261 r"#![allow(unused_imports)]
262
263#![no_std]
264fn main() {}",
265 r"#![allow(unused_imports)]
266
267#![no_std]
268
269use foo::bar;
270fn main() {}",
271 );
272}
273
274#[test]
275fn inserts_after_single_line_inner_comments() {
276 check_none(
277 "foo::bar::Baz",
278 "//! Single line inner comments do not allow any code before them.",
279 r#"//! Single line inner comments do not allow any code before them.
280
281use foo::bar::Baz;"#,
282 );
283}
284
285#[test]
286fn inserts_after_multiline_inner_comments() {
287 check_none(
288 "foo::bar::Baz",
289 r#"/*! Multiline inner comments do not allow any code before them. */
290
291/*! Still an inner comment, cannot place any code before. */
292fn main() {}"#,
293 r#"/*! Multiline inner comments do not allow any code before them. */
294
295/*! Still an inner comment, cannot place any code before. */
296
297use foo::bar::Baz;
298fn main() {}"#,
299 )
300}
301
302#[test]
303fn inserts_after_all_inner_items() {
304 check_none(
305 "foo::bar::Baz",
306 r#"#![allow(unused_imports)]
307/*! Multiline line comment 2 */
308
309
310//! Single line comment 1
311#![no_std]
312//! Single line comment 2
313fn main() {}"#,
314 r#"#![allow(unused_imports)]
315/*! Multiline line comment 2 */
316
317
318//! Single line comment 1
319#![no_std]
320//! Single line comment 2
321
322use foo::bar::Baz;
323fn main() {}"#,
324 )
325}
326
327#[test]
328fn merge_groups() {
329 check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
330}
331
332#[test]
333fn merge_groups_last() {
334 check_last(
335 "std::io",
336 r"use std::fmt::{Result, Display};",
337 r"use std::fmt::{Result, Display};
338use std::io;",
339 )
340}
341
342#[test]
343fn merge_last_into_self() {
344 check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
345}
346
347#[test]
348fn merge_groups_full() {
349 check_full(
350 "std::io",
351 r"use std::fmt::{Result, Display};",
352 r"use std::{fmt::{Result, Display}, io};",
353 )
354}
355
356#[test]
357fn merge_groups_long_full() {
358 check_full("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
359}
360
361#[test]
362fn merge_groups_long_last() {
363 check_last("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
364}
365
366#[test]
367fn merge_groups_long_full_list() {
368 check_full(
369 "std::foo::bar::Baz",
370 r"use std::foo::bar::{Qux, Quux};",
371 r"use std::foo::bar::{Baz, Quux, Qux};",
372 )
373}
374
375#[test]
376fn merge_groups_long_last_list() {
377 check_last(
378 "std::foo::bar::Baz",
379 r"use std::foo::bar::{Qux, Quux};",
380 r"use std::foo::bar::{Baz, Quux, Qux};",
381 )
382}
383
384#[test]
385fn merge_groups_long_full_nested() {
386 check_full(
387 "std::foo::bar::Baz",
388 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
389 r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
390 )
391}
392
393#[test]
394fn merge_groups_long_last_nested() {
395 check_last(
396 "std::foo::bar::Baz",
397 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
398 r"use std::foo::bar::Baz;
399use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
400 )
401}
402
403#[test]
404fn merge_groups_full_nested_deep() {
405 check_full(
406 "std::foo::bar::quux::Baz",
407 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
408 r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
409 )
410}
411
412#[test]
413fn merge_groups_full_nested_long() {
414 check_full(
415 "std::foo::bar::Baz",
416 r"use std::{foo::bar::Qux};",
417 r"use std::{foo::bar::{Baz, Qux}};",
418 );
419}
420
421#[test]
422fn merge_groups_last_nested_long() {
423 check_full(
424 "std::foo::bar::Baz",
425 r"use std::{foo::bar::Qux};",
426 r"use std::{foo::bar::{Baz, Qux}};",
427 );
428}
429
430#[test]
431fn merge_groups_skip_pub() {
432 check_full(
433 "std::io",
434 r"pub use std::fmt::{Result, Display};",
435 r"pub use std::fmt::{Result, Display};
436use std::io;",
437 )
438}
439
440#[test]
441fn merge_groups_skip_pub_crate() {
442 check_full(
443 "std::io",
444 r"pub(crate) use std::fmt::{Result, Display};",
445 r"pub(crate) use std::fmt::{Result, Display};
446use std::io;",
447 )
448}
449
450#[test]
451#[ignore] // FIXME: Support this
452fn split_out_merge() {
453 check_last(
454 "std::fmt::Result",
455 r"use std::{fmt, io};",
456 r"use std::fmt::{self, Result};
457use std::io;",
458 )
459}
460
461#[test]
462fn merge_into_module_import() {
463 check_full("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};")
464}
465
466#[test]
467fn merge_groups_self() {
468 check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
469}
470
471#[test]
472fn merge_mod_into_glob() {
473 check_full("token::TokenKind", r"use token::TokenKind::*;", r"use token::TokenKind::{*, self};")
474 // FIXME: have it emit `use token::TokenKind::{self, *}`?
475}
476
477#[test]
478fn merge_self_glob() {
479 check_full("self", r"use self::*;", r"use self::{*, self};")
480 // FIXME: have it emit `use {self, *}`?
481}
482
483#[test]
484fn merge_glob_nested() {
485 check_full(
486 "foo::bar::quux::Fez",
487 r"use foo::bar::{Baz, quux::*};",
488 r"use foo::bar::{Baz, quux::{self::*, Fez}};",
489 )
490}
491
492#[test]
493fn merge_nested_considers_first_segments() {
494 check_full(
495 "hir_ty::display::write_bounds_like_dyn_trait",
496 r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
497 r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
498 );
499}
500
501#[test]
502fn skip_merge_last_too_long() {
503 check_last(
504 "foo::bar",
505 r"use foo::bar::baz::Qux;",
506 r"use foo::bar;
507use foo::bar::baz::Qux;",
508 );
509}
510
511#[test]
512fn skip_merge_last_too_long2() {
513 check_last(
514 "foo::bar::baz::Qux",
515 r"use foo::bar;",
516 r"use foo::bar;
517use foo::bar::baz::Qux;",
518 );
519}
520
521#[test]
522fn insert_short_before_long() {
523 check_none(
524 "foo::bar",
525 r"use foo::bar::baz::Qux;",
526 r"use foo::bar;
527use foo::bar::baz::Qux;",
528 );
529}
530
531#[test]
532fn merge_last_fail() {
533 check_merge_only_fail(