aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock67
-rw-r--r--crates/hir/src/code_model.rs2095
-rw-r--r--crates/hir/src/from_id.rs5
-rw-r--r--crates/hir/src/lib.rs2146
-rw-r--r--crates/hir/src/semantics.rs5
-rw-r--r--crates/hir/src/source_analyzer.rs5
-rw-r--r--crates/hir_def/Cargo.toml1
-rw-r--r--crates/hir_def/src/attr.rs3
-rw-r--r--crates/hir_def/src/body.rs3
-rw-r--r--crates/hir_def/src/body/lower.rs3
-rw-r--r--crates/hir_def/src/body/scope.rs4
-rw-r--r--crates/hir_def/src/body/tests.rs3
-rw-r--r--crates/hir_def/src/body/tests/block.rs10
-rw-r--r--crates/hir_def/src/find_path.rs22
-rw-r--r--crates/hir_def/src/import_map.rs101
-rw-r--r--crates/hir_def/src/item_scope.rs3
-rw-r--r--crates/hir_def/src/item_tree.rs1
-rw-r--r--crates/hir_def/src/item_tree/lower.rs2
-rw-r--r--crates/hir_def/src/nameres/collector.rs17
-rw-r--r--crates/hir_def/src/nameres/mod_resolution.rs3
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs11
-rw-r--r--crates/hir_def/src/nameres/tests.rs9
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs5
-rw-r--r--crates/hir_def/src/nameres/tests/globs.rs8
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs10
-rw-r--r--crates/hir_def/src/nameres/tests/mod_resolution.rs4
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs3
-rw-r--r--crates/hir_ty/Cargo.toml7
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs11
-rw-r--r--crates/hir_ty/src/infer/coerce.rs5
-rw-r--r--crates/hir_ty/src/infer/expr.rs3
-rw-r--r--crates/hir_ty/src/infer/pat.rs3
-rw-r--r--crates/hir_ty/src/infer/unify.rs8
-rw-r--r--crates/hir_ty/src/lower.rs5
-rw-r--r--crates/hir_ty/src/method_resolution.rs2
-rw-r--r--crates/hir_ty/src/tests/coercion.rs5
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs2
-rw-r--r--crates/hir_ty/src/tests/patterns.rs3
-rw-r--r--crates/hir_ty/src/tests/regression.rs7
-rw-r--r--crates/hir_ty/src/tests/simple.rs3
-rw-r--r--crates/hir_ty/src/tests/traits.rs5
-rw-r--r--crates/ide/Cargo.toml1
-rw-r--r--crates/ide/src/hover.rs9
-rw-r--r--crates/ide/src/join_lines.rs8
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/matching_brace.rs5
-rw-r--r--crates/ide/src/parent_module.rs6
-rw-r--r--crates/ide/src/references/rename.rs58
-rw-r--r--crates/ide/src/runnables.rs8
-rw-r--r--crates/ide/src/typing/on_enter.rs8
-rw-r--r--crates/ide_assists/Cargo.toml1
-rw-r--r--crates/ide_assists/src/handlers/add_turbo_fish.rs22
-rw-r--r--crates/ide_assists/src/handlers/apply_demorgan.rs10
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs52
-rw-r--r--crates/ide_assists/src/handlers/change_visibility.rs7
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs21
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs4
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs15
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs11
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs17
-rw-r--r--crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs7
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs73
-rw-r--r--crates/ide_assists/src/handlers/infer_function_return_type.rs37
-rw-r--r--crates/ide_assists/src/handlers/inline_function.rs5
-rw-r--r--crates/ide_assists/src/handlers/inline_local_variable.rs19
-rw-r--r--crates/ide_assists/src/handlers/move_module_to_file.rs5
-rw-r--r--crates/ide_assists/src/handlers/pull_assignment_up.rs13
-rw-r--r--crates/ide_assists/src/handlers/qualify_path.rs63
-rw-r--r--crates/ide_assists/src/handlers/raw_string.rs7
-rw-r--r--crates/ide_assists/src/handlers/remove_unused_param.rs6
-rw-r--r--crates/ide_assists/src/handlers/reorder_fields.rs7
-rw-r--r--crates/ide_assists/src/handlers/reorder_impl.rs7
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs33
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs5
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs5
-rw-r--r--crates/ide_assists/src/handlers/unmerge_use.rs5
-rw-r--r--crates/ide_assists/src/handlers/wrap_return_type_in_result.rs5
-rw-r--r--crates/ide_completion/Cargo.toml1
-rw-r--r--crates/ide_completion/src/completions/dot.rs6
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs280
-rw-r--r--crates/ide_completion/src/completions/keyword.rs14
-rw-r--r--crates/ide_completion/src/completions/postfix.rs14
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs6
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs12
-rw-r--r--crates/ide_completion/src/context.rs4
-rw-r--r--crates/ide_completion/src/item.rs58
-rw-r--r--crates/ide_completion/src/lib.rs28
-rw-r--r--crates/ide_completion/src/render.rs45
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs9
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs7
-rw-r--r--crates/ide_completion/src/render/function.rs11
-rw-r--r--crates/ide_completion/src/render/macro_.rs7
-rw-r--r--crates/ide_db/Cargo.toml1
-rw-r--r--crates/ide_db/src/call_info.rs5
-rw-r--r--crates/ide_db/src/call_info/tests.rs4
-rw-r--r--crates/ide_db/src/helpers.rs10
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs578
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs7
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs6
-rw-r--r--crates/ide_db/src/items_locator.rs (renamed from crates/ide_db/src/imports_locator.rs)79
-rw-r--r--crates/ide_db/src/lib.rs2
-rw-r--r--crates/ide_ssr/Cargo.toml1
-rw-r--r--crates/ide_ssr/src/matching.rs3
-rw-r--r--crates/ide_ssr/src/parsing.rs3
-rw-r--r--crates/ide_ssr/src/replacing.rs4
-rw-r--r--crates/ide_ssr/src/resolving.rs9
-rw-r--r--crates/ide_ssr/src/search.rs5
-rw-r--r--crates/ide_ssr/src/tests.rs20
-rw-r--r--crates/mbe/Cargo.toml1
-rw-r--r--crates/mbe/src/lib.rs5
-rw-r--r--crates/mbe/src/tests.rs6
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/mod.rs2
-rw-r--r--crates/project_model/src/cargo_workspace.rs23
-rw-r--r--crates/project_model/src/workspace.rs138
-rw-r--r--crates/rust-analyzer/src/config.rs66
-rw-r--r--crates/rust-analyzer/src/handlers.rs10
-rw-r--r--crates/rust-analyzer/src/to_proto.rs52
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs97
-rw-r--r--crates/syntax/Cargo.toml3
-rw-r--r--crates/syntax/src/algo.rs26
-rw-r--r--crates/syntax/src/ast/make.rs4
-rw-r--r--crates/syntax/src/lib.rs1
-rw-r--r--crates/syntax/src/tests.rs6
-rw-r--r--crates/syntax/src/utils.rs43
-rw-r--r--crates/test_utils/Cargo.toml1
-rw-r--r--crates/test_utils/src/bench_fixture.rs6
-rw-r--r--crates/test_utils/src/lib.rs142
-rw-r--r--crates/test_utils/src/mark.rs78
-rw-r--r--docs/dev/architecture.md5
-rw-r--r--docs/dev/lsp-extensions.md20
-rw-r--r--docs/dev/style.md2
-rw-r--r--docs/user/generated_config.adoc324
-rw-r--r--editors/code/package-lock.json17
-rw-r--r--editors/code/package.json51
-rw-r--r--editors/code/src/config.ts8
-rw-r--r--editors/code/src/main.ts6
-rw-r--r--editors/code/src/net.ts25
-rw-r--r--xtask/src/codegen.rs78
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs20
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs8
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs8
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs12
-rw-r--r--xtask/src/codegen/gen_parser_tests.rs12
-rw-r--r--xtask/src/codegen/gen_syntax.rs10
-rw-r--r--xtask/src/flags.rs10
-rw-r--r--xtask/src/main.rs15
-rw-r--r--xtask/src/release.rs5
-rw-r--r--xtask/src/tidy.rs50
149 files changed, 4248 insertions, 3578 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c392a8907..51a07abe3 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.59.0" 171version = "0.60.0"
172source = "registry+https://github.com/rust-lang/crates.io-index" 172source = "registry+https://github.com/rust-lang/crates.io-index"
173checksum = "4b9000fbcb67353dc8973ab9fd136277d321d85b79bd36b8756bb3ae0979a94a" 173checksum = "ab0f74445d4fbeaf0217bc1d23978cc73b95b28e8a738b81894580dd646822d2"
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.59.0" 183version = "0.60.0"
184source = "registry+https://github.com/rust-lang/crates.io-index" 184source = "registry+https://github.com/rust-lang/crates.io-index"
185checksum = "b23528d61b3557c676eccf508fa0771a38453b379f0b780154eaa7f70afe8dfc" 185checksum = "294b1fc6210a5b3bd06c1d01dda48a581e2cafec80b8d659139ce45456644be2"
186dependencies = [ 186dependencies = [
187 "bitflags", 187 "bitflags",
188 "chalk-derive", 188 "chalk-derive",
@@ -191,9 +191,9 @@ dependencies = [
191 191
192[[package]] 192[[package]]
193name = "chalk-recursive" 193name = "chalk-recursive"
194version = "0.59.0" 194version = "0.60.0"
195source = "registry+https://github.com/rust-lang/crates.io-index" 195source = "registry+https://github.com/rust-lang/crates.io-index"
196checksum = "a8bdd37afc666b771de8b4429fe014363d0e74aae5cc26f320f60a3eab34d744" 196checksum = "1b9386936070be4545bfa22b094b7065af79aa2aeaccc945438f1c5ffe74c30a"
197dependencies = [ 197dependencies = [
198 "chalk-derive", 198 "chalk-derive",
199 "chalk-ir", 199 "chalk-ir",
@@ -204,9 +204,9 @@ dependencies = [
204 204
205[[package]] 205[[package]]
206name = "chalk-solve" 206name = "chalk-solve"
207version = "0.59.0" 207version = "0.60.0"
208source = "registry+https://github.com/rust-lang/crates.io-index" 208source = "registry+https://github.com/rust-lang/crates.io-index"
209checksum = "4182c42ca319cb71c89898ebc3d2671d1fa7d928123b171b66f1797a2000b9c8" 209checksum = "7c12a1ec7e850b50a049f27ef9cf5df3056bbd1acbb3eeb44d024e501a641f3a"
210dependencies = [ 210dependencies = [
211 "chalk-derive", 211 "chalk-derive",
212 "chalk-ir", 212 "chalk-ir",
@@ -232,15 +232,6 @@ dependencies = [
232] 232]
233 233
234[[package]] 234[[package]]
235name = "cmake"
236version = "0.1.45"
237source = "registry+https://github.com/rust-lang/crates.io-index"
238checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
239dependencies = [
240 "cc",
241]
242
243[[package]]
244name = "countme" 235name = "countme"
245version = "2.0.4" 236version = "2.0.4"
246source = "registry+https://github.com/rust-lang/crates.io-index" 237source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -252,6 +243,12 @@ dependencies = [
252] 243]
253 244
254[[package]] 245[[package]]
246name = "cov-mark"
247version = "1.1.0"
248source = "registry+https://github.com/rust-lang/crates.io-index"
249checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3"
250
251[[package]]
255name = "crc32fast" 252name = "crc32fast"
256version = "1.2.1" 253version = "1.2.1"
257source = "registry+https://github.com/rust-lang/crates.io-index" 254source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -501,6 +498,7 @@ dependencies = [
501 "anymap", 498 "anymap",
502 "base_db", 499 "base_db",
503 "cfg", 500 "cfg",
501 "cov-mark",
504 "drop_bomb", 502 "drop_bomb",
505 "either", 503 "either",
506 "expect-test", 504 "expect-test",
@@ -547,6 +545,7 @@ dependencies = [
547 "chalk-ir", 545 "chalk-ir",
548 "chalk-recursive", 546 "chalk-recursive",
549 "chalk-solve", 547 "chalk-solve",
548 "cov-mark",
550 "ena", 549 "ena",
551 "expect-test", 550 "expect-test",
552 "hir_def", 551 "hir_def",
@@ -581,6 +580,7 @@ name = "ide"
581version = "0.0.0" 580version = "0.0.0"
582dependencies = [ 581dependencies = [
583 "cfg", 582 "cfg",
583 "cov-mark",
584 "either", 584 "either",
585 "expect-test", 585 "expect-test",
586 "hir", 586 "hir",
@@ -607,6 +607,7 @@ dependencies = [
607name = "ide_assists" 607name = "ide_assists"
608version = "0.0.0" 608version = "0.0.0"
609dependencies = [ 609dependencies = [
610 "cov-mark",
610 "either", 611 "either",
611 "expect-test", 612 "expect-test",
612 "hir", 613 "hir",
@@ -625,6 +626,7 @@ name = "ide_completion"
625version = "0.0.0" 626version = "0.0.0"
626dependencies = [ 627dependencies = [
627 "base_db", 628 "base_db",
629 "cov-mark",
628 "either", 630 "either",
629 "expect-test", 631 "expect-test",
630 "hir", 632 "hir",
@@ -644,6 +646,7 @@ name = "ide_db"
644version = "0.0.0" 646version = "0.0.0"
645dependencies = [ 647dependencies = [
646 "base_db", 648 "base_db",
649 "cov-mark",
647 "either", 650 "either",
648 "expect-test", 651 "expect-test",
649 "fst", 652 "fst",
@@ -664,6 +667,7 @@ dependencies = [
664name = "ide_ssr" 667name = "ide_ssr"
665version = "0.0.0" 668version = "0.0.0"
666dependencies = [ 669dependencies = [
670 "cov-mark",
667 "expect-test", 671 "expect-test",
668 "hir", 672 "hir",
669 "ide_db", 673 "ide_db",
@@ -687,9 +691,9 @@ dependencies = [
687 691
688[[package]] 692[[package]]
689name = "indexmap" 693name = "indexmap"
690version = "1.6.1" 694version = "1.6.2"
691source = "registry+https://github.com/rust-lang/crates.io-index" 695source = "registry+https://github.com/rust-lang/crates.io-index"
692checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" 696checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
693dependencies = [ 697dependencies = [
694 "autocfg", 698 "autocfg",
695 "hashbrown", 699 "hashbrown",
@@ -805,11 +809,11 @@ dependencies = [
805 809
806[[package]] 810[[package]]
807name = "libmimalloc-sys" 811name = "libmimalloc-sys"
808version = "0.1.20" 812version = "0.1.21"
809source = "registry+https://github.com/rust-lang/crates.io-index" 813source = "registry+https://github.com/rust-lang/crates.io-index"
810checksum = "e58f42b6424a0ed536678c65fd97cd64b4344bcf86251e284f7c0ce9eee40e64" 814checksum = "2396cf99d2f58611cd69f0efeee4af3d2e2c7b61bed433515029163aa567e65c"
811dependencies = [ 815dependencies = [
812 "cmake", 816 "cc",
813] 817]
814 818
815[[package]] 819[[package]]
@@ -874,6 +878,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
874name = "mbe" 878name = "mbe"
875version = "0.0.0" 879version = "0.0.0"
876dependencies = [ 880dependencies = [
881 "cov-mark",
877 "log", 882 "log",
878 "parser", 883 "parser",
879 "profile", 884 "profile",
@@ -911,9 +916,9 @@ dependencies = [
911 916
912[[package]] 917[[package]]
913name = "mimalloc" 918name = "mimalloc"
914version = "0.1.24" 919version = "0.1.25"
915source = "registry+https://github.com/rust-lang/crates.io-index" 920source = "registry+https://github.com/rust-lang/crates.io-index"
916checksum = "757efec188b3d2088949d912e01ea2fe87164ed6376b6c5d7dd4f3ce1668a93d" 921checksum = "1e7c6b11afd1e5e689ac96b6d18b1fc763398fe3d7eed99e8773426bc2033dfb"
917dependencies = [ 922dependencies = [
918 "libmimalloc-sys", 923 "libmimalloc-sys",
919] 924]
@@ -1466,18 +1471,18 @@ dependencies = [
1466 1471
1467[[package]] 1472[[package]]
1468name = "serde" 1473name = "serde"
1469version = "1.0.123" 1474version = "1.0.124"
1470source = "registry+https://github.com/rust-lang/crates.io-index" 1475source = "registry+https://github.com/rust-lang/crates.io-index"
1471checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" 1476checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
1472dependencies = [ 1477dependencies = [
1473 "serde_derive", 1478 "serde_derive",
1474] 1479]
1475 1480
1476[[package]] 1481[[package]]
1477name = "serde_derive" 1482name = "serde_derive"
1478version = "1.0.123" 1483version = "1.0.124"
1479source = "registry+https://github.com/rust-lang/crates.io-index" 1484source = "registry+https://github.com/rust-lang/crates.io-index"
1480checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" 1485checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
1481dependencies = [ 1486dependencies = [
1482 "proc-macro2", 1487 "proc-macro2",
1483 "quote", 1488 "quote",
@@ -1561,9 +1566,9 @@ dependencies = [
1561 1566
1562[[package]] 1567[[package]]
1563name = "syn" 1568name = "syn"
1564version = "1.0.61" 1569version = "1.0.62"
1565source = "registry+https://github.com/rust-lang/crates.io-index" 1570source = "registry+https://github.com/rust-lang/crates.io-index"
1566checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" 1571checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512"
1567dependencies = [ 1572dependencies = [
1568 "proc-macro2", 1573 "proc-macro2",
1569 "quote", 1574 "quote",
@@ -1587,6 +1592,7 @@ name = "syntax"
1587version = "0.0.0" 1592version = "0.0.0"
1588dependencies = [ 1593dependencies = [
1589 "arrayvec", 1594 "arrayvec",
1595 "cov-mark",
1590 "expect-test", 1596 "expect-test",
1591 "indexmap", 1597 "indexmap",
1592 "itertools", 1598 "itertools",
@@ -1621,7 +1627,6 @@ dependencies = [
1621 "dissimilar", 1627 "dissimilar",
1622 "profile", 1628 "profile",
1623 "rustc-hash", 1629 "rustc-hash",
1624 "serde_json",
1625 "stdx", 1630 "stdx",
1626 "text-size", 1631 "text-size",
1627] 1632]
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
deleted file mode 100644
index 9ee4b3059..000000000
--- a/crates/hir/src/code_model.rs
+++ /dev/null
@@ -1,2095 +0,0 @@
1//! FIXME: write short doc here
2use std::{iter, sync::Arc};
3
4use arrayvec::ArrayVec;
5use base_db::{CrateDisplayName, CrateId, Edition, FileId};
6use either::Either;
7use hir_def::{
8 adt::{ReprKind, StructKind, VariantData},
9 expr::{BindingAnnotation, LabelId, Pat, PatId},
10 import_map,
11 item_tree::ItemTreeNode,
12 lang_item::LangItemTarget,
13 path::ModPath,
14 per_ns::PerNs,
15 resolver::{HasResolver, Resolver},
16 src::HasSource as _,
17 type_ref::TypeRef,
18 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
19 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
20 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
21 TypeParamId, UnionId,
22};
23use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility};
24use hir_expand::{
25 diagnostics::DiagnosticSink,
26 name::{name, AsName},
27 MacroDefId, MacroDefKind,
28};
29use hir_ty::{
30 autoderef,
31 display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
32 method_resolution,
33 traits::{FnTrait, Solution, SolutionVariables},
34 AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
35 InEnvironment, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs,
36 TraitEnvironment, Ty, TyDefId, TyVariableKind,
37};
38use rustc_hash::FxHashSet;
39use stdx::{format_to, impl_from};
40use syntax::{
41 ast::{self, AttrsOwner, NameOwner},
42 AstNode, SmolStr,
43};
44use tt::{Ident, Leaf, Literal, TokenTree};
45
46use crate::{
47 db::{DefDatabase, HirDatabase},
48 has_source::HasSource,
49 HirDisplay, InFile, Name,
50};
51
52/// hir::Crate describes a single crate. It's the main interface with which
53/// a crate's dependencies interact. Mostly, it should be just a proxy for the
54/// root module.
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56pub struct Crate {
57 pub(crate) id: CrateId,
58}
59
60#[derive(Debug)]
61pub struct CrateDependency {
62 pub krate: Crate,
63 pub name: Name,
64}
65
66impl Crate {
67 pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
68 db.crate_graph()[self.id]
69 .dependencies
70 .iter()
71 .map(|dep| {
72 let krate = Crate { id: dep.crate_id };
73 let name = dep.as_name();
74 CrateDependency { krate, name }
75 })
76 .collect()
77 }
78
79 // FIXME: add `transitive_reverse_dependencies`.
80 pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
81 let crate_graph = db.crate_graph();
82 crate_graph
83 .iter()
84 .filter(|&krate| {
85 crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
86 })
87 .map(|id| Crate { id })
88 .collect()
89 }
90
91 pub fn root_module(self, db: &dyn HirDatabase) -> Module {
92 let def_map = db.crate_def_map(self.id);
93 Module { id: def_map.module_id(def_map.root()) }
94 }
95
96 pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
97 db.crate_graph()[self.id].root_file_id
98 }
99
100 pub fn edition(self, db: &dyn HirDatabase) -> Edition {
101 db.crate_graph()[self.id].edition
102 }
103
104 pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
105 db.crate_graph()[self.id].display_name.clone()
106 }
107
108 pub fn query_external_importables(
109 self,
110 db: &dyn DefDatabase,
111 query: import_map::Query,
112 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
113 import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item {
114 ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()),
115 ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()),
116 })
117 }
118
119 pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
120 db.crate_graph().iter().map(|id| Crate { id }).collect()
121 }
122
123 /// Try to get the root URL of the documentation of a crate.
124 pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
125 // Look for #![doc(html_root_url = "...")]
126 let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
127 let doc_attr_q = attrs.by_key("doc");
128
129 if !doc_attr_q.exists() {
130 return None;
131 }
132
133 let doc_url = doc_attr_q.tt_values().map(|tt| {
134 let name = tt.token_trees.iter()
135 .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url"))
136 .skip(2)
137 .next();
138
139 match name {
140 Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text),
141 _ => None
142 }
143 }).flat_map(|t| t).next();
144
145 doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
146 }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
150pub struct Module {
151 pub(crate) id: ModuleId,
152}
153
154/// The defs which can be visible in the module.
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
156pub enum ModuleDef {
157 Module(Module),
158 Function(Function),
159 Adt(Adt),
160 // Can't be directly declared, but can be imported.
161 Variant(Variant),
162 Const(Const),
163 Static(Static),
164 Trait(Trait),
165 TypeAlias(TypeAlias),
166 BuiltinType(BuiltinType),
167}
168impl_from!(
169 Module,
170 Function,
171 Adt(Struct, Enum, Union),
172 Variant,
173 Const,
174 Static,
175 Trait,
176 TypeAlias,
177 BuiltinType
178 for ModuleDef
179);
180
181impl From<VariantDef> for ModuleDef {
182 fn from(var: VariantDef) -> Self {
183 match var {
184 VariantDef::Struct(t) => Adt::from(t).into(),
185 VariantDef::Union(t) => Adt::from(t).into(),
186 VariantDef::Variant(t) => t.into(),
187 }
188 }
189}
190
191impl ModuleDef {
192 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
193 match self {
194 ModuleDef::Module(it) => it.parent(db),
195 ModuleDef::Function(it) => Some(it.module(db)),
196 ModuleDef::Adt(it) => Some(it.module(db)),
197 ModuleDef::Variant(it) => Some(it.module(db)),
198 ModuleDef::Const(it) => Some(it.module(db)),
199 ModuleDef::Static(it) => Some(it.module(db)),
200 ModuleDef::Trait(it) => Some(it.module(db)),
201 ModuleDef::TypeAlias(it) => Some(it.module(db)),
202 ModuleDef::BuiltinType(_) => None,
203 }
204 }
205
206 pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
207 let mut segments = Vec::new();
208 segments.push(self.name(db)?.to_string());
209 for m in self.module(db)?.path_to_root(db) {
210 segments.extend(m.name(db).map(|it| it.to_string()))
211 }
212 segments.reverse();
213 Some(segments.join("::"))
214 }
215
216 pub fn definition_visibility(&self, db: &dyn HirDatabase) -> Option<Visibility> {
217 let module = match self {
218 ModuleDef::Module(it) => it.parent(db)?,
219 ModuleDef::Function(it) => return Some(it.visibility(db)),
220 ModuleDef::Adt(it) => it.module(db),
221 ModuleDef::Variant(it) => {
222 let parent = it.parent_enum(db);
223 let module = it.module(db);
224 return module.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent)));
225 }
226 ModuleDef::Const(it) => return Some(it.visibility(db)),
227 ModuleDef::Static(it) => it.module(db),
228 ModuleDef::Trait(it) => it.module(db),
229 ModuleDef::TypeAlias(it) => return Some(it.visibility(db)),
230 ModuleDef::BuiltinType(_) => return None,
231 };
232
233 module.visibility_of(db, self)
234 }
235
236 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
237 match self {
238 ModuleDef::Adt(it) => Some(it.name(db)),
239 ModuleDef::Trait(it) => Some(it.name(db)),
240 ModuleDef::Function(it) => Some(it.name(db)),
241 ModuleDef::Variant(it) => Some(it.name(db)),
242 ModuleDef::TypeAlias(it) => Some(it.name(db)),
243 ModuleDef::Module(it) => it.name(db),
244 ModuleDef::Const(it) => it.name(db),
245 ModuleDef::Static(it) => it.name(db),
246
247 ModuleDef::BuiltinType(it) => Some(it.name()),
248 }
249 }
250
251 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
252 let id = match self {
253 ModuleDef::Adt(it) => match it {
254 Adt::Struct(it) => it.id.into(),
255 Adt::Enum(it) => it.id.into(),
256 Adt::Union(it) => it.id.into(),
257 },
258 ModuleDef::Trait(it) => it.id.into(),
259 ModuleDef::Function(it) => it.id.into(),
260 ModuleDef::TypeAlias(it) => it.id.into(),
261 ModuleDef::Module(it) => it.id.into(),
262 ModuleDef::Const(it) => it.id.into(),
263 ModuleDef::Static(it) => it.id.into(),
264 _ => return,
265 };
266
267 let module = match self.module(db) {
268 Some(it) => it,
269 None => return,
270 };
271
272 hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink)
273 }
274}
275
276impl Module {
277 /// Name of this module.
278 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
279 let def_map = self.id.def_map(db.upcast());
280 let parent = def_map[self.id.local_id].parent?;
281 def_map[parent].children.iter().find_map(|(name, module_id)| {
282 if *module_id == self.id.local_id {
283 Some(name.clone())
284 } else {
285 None
286 }
287 })
288 }
289
290 /// Returns the crate this module is part of.
291 pub fn krate(self) -> Crate {
292 Crate { id: self.id.krate() }
293 }
294
295 /// Topmost parent of this module. Every module has a `crate_root`, but some
296 /// might be missing `krate`. This can happen if a module's file is not included
297 /// in the module tree of any target in `Cargo.toml`.
298 pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
299 let def_map = db.crate_def_map(self.id.krate());
300 Module { id: def_map.module_id(def_map.root()) }
301 }
302
303 /// Iterates over all child modules.
304 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
305 let def_map = self.id.def_map(db.upcast());
306 let children = def_map[self.id.local_id]
307 .children
308 .iter()
309 .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
310 .collect::<Vec<_>>();
311 children.into_iter()
312 }
313
314 /// Finds a parent module.
315 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
316 // FIXME: handle block expressions as modules (their parent is in a different DefMap)
317 let def_map = self.id.def_map(db.upcast());
318 let parent_id = def_map[self.id.local_id].parent?;
319 Some(Module { id: def_map.module_id(parent_id) })
320 }
321
322 pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
323 let mut res = vec![self];
324 let mut curr = self;
325 while let Some(next) = curr.parent(db) {
326 res.push(next);
327 curr = next
328 }
329 res
330 }
331
332 /// Returns a `ModuleScope`: a set of items, visible in this module.
333 pub fn scope(
334 self,
335 db: &dyn HirDatabase,
336 visible_from: Option<Module>,
337 ) -> Vec<(Name, ScopeDef)> {
338 self.id.def_map(db.upcast())[self.id.local_id]
339 .scope
340 .entries()
341 .filter_map(|(name, def)| {
342 if let Some(m) = visible_from {
343 let filtered =
344 def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
345 if filtered.is_none() && !def.is_none() {
346 None
347 } else {
348 Some((name, filtered))
349 }
350 } else {
351 Some((name, def))
352 }
353 })
354 .flat_map(|(name, def)| {
355 ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
356 })
357 .collect()
358 }
359
360 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> {
361 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into())
362 }
363
364 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
365 let _p = profile::span("Module::diagnostics").detail(|| {
366 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
367 });
368 let def_map = self.id.def_map(db.upcast());
369 def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
370 for decl in self.declarations(db) {
371 match decl {
372 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
373 crate::ModuleDef::Module(m) => {
374 // Only add diagnostics from inline modules
375 if def_map[m.id.local_id].origin.is_inline() {
376 m.diagnostics(db, sink)
377 }
378 }
379 _ => {
380 decl.diagnostics(db, sink);
381 }
382 }
383 }
384
385 for impl_def in self.impl_defs(db) {
386 for item in impl_def.items(db) {
387 if let AssocItem::Function(f) = item {
388 f.diagnostics(db, sink);
389 }
390 }
391 }
392 }
393
394 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
395 let def_map = self.id.def_map(db.upcast());
396 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect()
397 }
398
399 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
400 let def_map = self.id.def_map(db.upcast());
401 def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
402 }
403
404 /// Finds a path that can be used to refer to the given item from within
405 /// this module, if possible.
406 pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> {
407 hir_def::find_path::find_path(db, item.into(), self.into())
408 }
409
410 /// Finds a path that can be used to refer to the given item from within
411 /// this module, if possible. This is used for returning import paths for use-statements.
412 pub fn find_use_path_prefixed(
413 self,
414 db: &dyn DefDatabase,
415 item: impl Into<ItemInNs>,
416 prefix_kind: PrefixKind,
417 ) -> Option<ModPath> {
418 hir_def::find_path::find_path_prefixed(db, item.into(), self.into(), prefix_kind)
419 }
420}
421
422#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
423pub struct Field {
424 pub(crate) parent: VariantDef,
425 pub(crate) id: LocalFieldId,
426}
427
428#[derive(Debug, PartialEq, Eq)]
429pub enum FieldSource {
430 Named(ast::RecordField),
431 Pos(ast::TupleField),
432}
433
434impl Field {
435 pub fn name(&self, db: &dyn HirDatabase) -> Name {
436 self.parent.variant_data(db).fields()[self.id].name.clone()
437 }
438
439 /// Returns the type as in the signature of the struct (i.e., with
440 /// placeholder types for type parameters). This is good for showing
441 /// signature help, but not so good to actually get the type of the field
442 /// when you actually have a variable of the struct.
443 pub fn signature_ty(&self, db: &dyn HirDatabase) -> Type {
444 let var_id = self.parent.into();
445 let generic_def_id: GenericDefId = match self.parent {
446 VariantDef::Struct(it) => it.id.into(),
447 VariantDef::Union(it) => it.id.into(),
448 VariantDef::Variant(it) => it.parent.id.into(),
449 };
450 let substs = Substs::type_params(db, generic_def_id);
451 let ty = db.field_types(var_id)[self.id].clone().subst(&substs);
452 Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
453 }
454
455 pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
456 self.parent
457 }
458}
459
460impl HasVisibility for Field {
461 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
462 let variant_data = self.parent.variant_data(db);
463 let visibility = &variant_data.fields()[self.id].visibility;
464 let parent_id: hir_def::VariantId = self.parent.into();
465 visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
466 }
467}
468
469#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
470pub struct Struct {
471 pub(crate) id: StructId,
472}
473
474impl Struct {
475 pub fn module(self, db: &dyn HirDatabase) -> Module {
476 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
477 }
478
479 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
480 Some(self.module(db).krate())
481 }
482
483 pub fn name(self, db: &dyn HirDatabase) -> Name {
484 db.struct_data(self.id).name.clone()
485 }
486
487 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
488 db.struct_data(self.id)
489 .variant_data
490 .fields()
491 .iter()
492 .map(|(id, _)| Field { parent: self.into(), id })
493 .collect()
494 }
495
496 pub fn ty(self, db: &dyn HirDatabase) -> Type {
497 Type::from_def(
498 db,
499 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
500 self.id,
501 )
502 }
503
504 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
505 db.struct_data(self.id).repr.clone()
506 }
507
508 pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
509 self.variant_data(db).kind()
510 }
511
512 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
513 db.struct_data(self.id).variant_data.clone()
514 }
515}
516
517#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
518pub struct Union {
519 pub(crate) id: UnionId,
520}
521
522impl Union {
523 pub fn name(self, db: &dyn HirDatabase) -> Name {
524 db.union_data(self.id).name.clone()
525 }
526
527 pub fn module(self, db: &dyn HirDatabase) -> Module {
528 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
529 }
530
531 pub fn ty(self, db: &dyn HirDatabase) -> Type {
532 Type::from_def(
533 db,
534 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
535 self.id,
536 )
537 }
538
539 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
540 db.union_data(self.id)
541 .variant_data
542 .fields()
543 .iter()
544 .map(|(id, _)| Field { parent: self.into(), id })
545 .collect()
546 }
547
548 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
549 db.union_data(self.id).variant_data.clone()
550 }
551}
552
553#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
554pub struct Enum {
555 pub(crate) id: EnumId,
556}
557
558impl Enum {
559 pub fn module(self, db: &dyn HirDatabase) -> Module {
560 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
561 }
562
563 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
564 Some(self.module(db).krate())
565 }
566
567 pub fn name(self, db: &dyn HirDatabase) -> Name {
568 db.enum_data(self.id).name.clone()
569 }
570
571 pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
572 db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
573 }
574
575 pub fn ty(self, db: &dyn HirDatabase) -> Type {
576 Type::from_def(
577 db,
578 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
579 self.id,
580 )
581 }
582}
583
584#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
585pub struct Variant {
586 pub(crate) parent: Enum,
587 pub(crate) id: LocalEnumVariantId,
588}
589
590impl Variant {
591 pub fn module(self, db: &dyn HirDatabase) -> Module {
592 self.parent.module(db)
593 }
594 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
595 self.parent
596 }
597
598 pub fn name(self, db: &dyn HirDatabase) -> Name {
599 db.enum_data(self.parent.id).variants[self.id].name.clone()
600 }
601
602 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
603 self.variant_data(db)
604 .fields()
605 .iter()
606 .map(|(id, _)| Field { parent: self.into(), id })
607 .collect()
608 }
609
610 pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
611 self.variant_data(db).kind()
612 }
613
614 pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
615 db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
616 }
617}
618
619/// A Data Type
620#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
621pub enum Adt {
622 Struct(Struct),
623 Union(Union),
624 Enum(Enum),
625}
626impl_from!(Struct, Union, Enum for Adt);
627
628impl Adt {
629 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
630 let subst = db.generic_defaults(self.into());
631 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
632 }
633
634 /// Turns this ADT into a type. Any type parameters of the ADT will be
635 /// turned into unknown types, which is good for e.g. finding the most
636 /// general set of completions, but will not look very nice when printed.
637 pub fn ty(self, db: &dyn HirDatabase) -> Type {
638 let id = AdtId::from(self);
639 Type::from_def(db, id.module(db.upcast()).krate(), id)
640 }
641
642 pub fn module(self, db: &dyn HirDatabase) -> Module {
643 match self {
644 Adt::Struct(s) => s.module(db),
645 Adt::Union(s) => s.module(db),
646 Adt::Enum(e) => e.module(db),
647 }
648 }
649
650 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
651 Some(self.module(db).krate())
652 }
653
654 pub fn name(self, db: &dyn HirDatabase) -> Name {
655 match self {
656 Adt::Struct(s) => s.name(db),
657 Adt::Union(u) => u.name(db),
658 Adt::Enum(e) => e.name(db),
659 }
660 }
661}
662
663#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
664pub enum VariantDef {
665 Struct(Struct),
666 Union(Union),
667 Variant(Variant),
668}
669impl_from!(Struct, Union, Variant for VariantDef);
670
671impl VariantDef {
672 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
673 match self {
674 VariantDef::Struct(it) => it.fields(db),
675 VariantDef::Union(it) => it.fields(db),
676 VariantDef::Variant(it) => it.fields(db),
677 }
678 }
679
680 pub fn module(self, db: &dyn HirDatabase) -> Module {
681 match self {
682 VariantDef::Struct(it) => it.module(db),
683 VariantDef::Union(it) => it.module(db),
684 VariantDef::Variant(it) => it.module(db),
685 }
686 }
687
688 pub fn name(&self, db: &dyn HirDatabase) -> Name {
689 match self {
690 VariantDef::Struct(s) => s.name(db),
691 VariantDef::Union(u) => u.name(db),
692 VariantDef::Variant(e) => e.name(db),
693 }
694 }
695
696 pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
697 match self {
698 VariantDef::Struct(it) => it.variant_data(db),
699 VariantDef::Union(it) => it.variant_data(db),
700 VariantDef::Variant(it) => it.variant_data(db),
701 }
702 }
703}
704
705/// The defs which have a body.
706#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
707pub enum DefWithBody {
708 Function(Function),
709 Static(Static),
710 Const(Const),
711}
712impl_from!(Function, Const, Static for DefWithBody);
713
714impl DefWithBody {
715 pub fn module(self, db: &dyn HirDatabase) -> Module {
716 match self {
717 DefWithBody::Const(c) => c.module(db),
718 DefWithBody::Function(f) => f.module(db),
719 DefWithBody::Static(s) => s.module(db),
720 }
721 }
722
723 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
724 match self {
725 DefWithBody::Function(f) => Some(f.name(db)),
726 DefWithBody::Static(s) => s.name(db),
727 DefWithBody::Const(c) => c.name(db),
728 }
729 }
730}
731
732#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
733pub struct Function {
734 pub(crate) id: FunctionId,
735}
736
737impl Function {
738 pub fn module(self, db: &dyn HirDatabase) -> Module {
739 self.id.lookup(db.upcast()).module(db.upcast()).into()
740 }
741
742 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
743 Some(self.module(db).krate())
744 }
745
746 pub fn name(self, db: &dyn HirDatabase) -> Name {
747 db.function_data(self.id).name.clone()
748 }
749
750 /// Get this function's return type
751 pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
752 let resolver = self.id.resolver(db.upcast());
753 let ret_type = &db.function_data(self.id).ret_type;
754 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
755 let environment = TraitEnvironment::lower(db, &resolver);
756 Type {
757 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
758 ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment },
759 }
760 }
761
762 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
763 if !db.function_data(self.id).has_self_param {
764 return None;
765 }
766 Some(SelfParam { func: self.id })
767 }
768
769 pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
770 let resolver = self.id.resolver(db.upcast());
771 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
772 let environment = TraitEnvironment::lower(db, &resolver);
773 db.function_data(self.id)
774 .params
775 .iter()
776 .map(|type_ref| {
777 let ty = Type {
778 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
779 ty: InEnvironment {
780 value: Ty::from_hir_ext(&ctx, type_ref).0,
781 environment: environment.clone(),
782 },
783 };
784 Param { ty }
785 })
786 .collect()
787 }
788 pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
789 if self.self_param(db).is_none() {
790 return None;
791 }
792 let mut res = self.assoc_fn_params(db);
793 res.remove(0);
794 Some(res)
795 }
796
797 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
798 db.function_data(self.id).is_unsafe
799 }
800
801 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
802 let krate = self.module(db).id.krate();
803 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink);
804 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
805 hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
806 }
807
808 /// Whether this function declaration has a definition.
809 ///
810 /// This is false in the case of required (not provided) trait methods.
811 pub fn has_body(self, db: &dyn HirDatabase) -> bool {
812 db.function_data(self.id).has_body
813 }
814
815 /// A textual representation of the HIR of this function for debugging purposes.
816 pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
817 let body = db.body(self.id.into());
818
819 let mut result = String::new();
820 format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
821 for (id, expr) in body.exprs.iter() {
822 format_to!(result, "{:?}: {:?}\n", id, expr);
823 }
824
825 result
826 }
827}
828
829// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
830pub enum Access {
831 Shared,
832 Exclusive,
833 Owned,
834}
835
836impl From<Mutability> for Access {
837 fn from(mutability: Mutability) -> Access {
838 match mutability {
839 Mutability::Not => Access::Shared,
840 Mutability::Mut => Access::Exclusive,
841 }
842 }
843}
844
845#[derive(Debug)]
846pub struct Param {
847 ty: Type,
848}
849
850impl Param {
851 pub fn ty(&self) -> &Type {
852 &self.ty
853 }
854}
855
856#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
857pub struct SelfParam {
858 func: FunctionId,
859}
860
861impl SelfParam {
862 pub fn access(self, db: &dyn HirDatabase) -> Access {
863 let func_data = db.function_data(self.func);
864 func_data
865 .params
866 .first()
867 .map(|param| match *param {
868 TypeRef::Reference(.., mutability) => match mutability {
869 hir_def::type_ref::Mutability::Shared => Access::Shared,
870 hir_def::type_ref::Mutability::Mut => Access::Exclusive,
871 },
872 _ => Access::Owned,
873 })
874 .unwrap_or(Access::Owned)
875 }
876}
877
878impl HasVisibility for Function {
879 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
880 let function_data = db.function_data(self.id);
881 let visibility = &function_data.visibility;
882 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
883 }
884}
885
886#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
887pub struct Const {
888 pub(crate) id: ConstId,
889}
890
891impl Const {
892 pub fn module(self, db: &dyn HirDatabase) -> Module {
893 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
894 }
895
896 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
897 Some(self.module(db).krate())
898 }
899
900 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
901 db.const_data(self.id).name.clone()
902 }
903}
904
905impl HasVisibility for Const {
906 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
907 let function_data = db.const_data(self.id);
908 let visibility = &function_data.visibility;
909 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
910 }
911}
912
913#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
914pub struct Static {
915 pub(crate) id: StaticId,
916}
917
918impl Static {
919 pub fn module(self, db: &dyn HirDatabase) -> Module {
920 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
921 }
922
923 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
924 Some(self.module(db).krate())
925 }
926
927 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
928 db.static_data(self.id).name.clone()
929 }
930
931 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
932 db.static_data(self.id).mutable
933 }
934}
935
936#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
937pub struct Trait {
938 pub(crate) id: TraitId,
939}
940
941impl Trait {
942 pub fn module(self, db: &dyn HirDatabase) -> Module {
943 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
944 }
945
946 pub fn name(self, db: &dyn HirDatabase) -> Name {
947 db.trait_data(self.id).name.clone()
948 }
949
950 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
951 db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
952 }
953
954 pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
955 db.trait_data(self.id).auto
956 }
957}
958
959#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
960pub struct TypeAlias {
961 pub(crate) id: TypeAliasId,
962}
963
964impl TypeAlias {
965 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
966 let subst = db.generic_defaults(self.id.into());
967 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
968 }
969
970 pub fn module(self, db: &dyn HirDatabase) -> Module {
971 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
972 }
973
974 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
975 Some(self.module(db).krate())
976 }
977
978 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
979 db.type_alias_data(self.id).type_ref.clone()
980 }
981
982 pub fn ty(self, db: &dyn HirDatabase) -> Type {
983 Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate(), self.id)
984 }
985
986 pub fn name(self, db: &dyn HirDatabase) -> Name {
987 db.type_alias_data(self.id).name.clone()
988 }
989}
990
991impl HasVisibility for TypeAlias {
992 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
993 let function_data = db.type_alias_data(self.id);
994 let visibility = &function_data.visibility;
995 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
996 }
997}
998
999#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1000pub struct BuiltinType {
1001 pub(crate) inner: hir_def::builtin_type::BuiltinType,
1002}
1003
1004impl BuiltinType {
1005 pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type {
1006 let resolver = module.id.resolver(db.upcast());
1007 Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner))
1008 .expect("crate not present in resolver")
1009 }
1010
1011 pub fn name(self) -> Name {
1012 self.inner.as_name()
1013 }
1014}
1015
1016#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1017pub struct MacroDef {
1018 pub(crate) id: MacroDefId,
1019}
1020
1021impl MacroDef {
1022 /// FIXME: right now, this just returns the root module of the crate that
1023 /// defines this macro. The reasons for this is that macros are expanded
1024 /// early, in `hir_expand`, where modules simply do not exist yet.
1025 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
1026 let krate = self.id.krate;
1027 let def_map = db.crate_def_map(krate);
1028 let module_id = def_map.root();
1029 Some(Module { id: def_map.module_id(module_id) })
1030 }
1031
1032 /// XXX: this parses the file
1033 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1034 self.source(db)?.value.name().map(|it| it.as_name())
1035 }
1036
1037 /// Indicate it is a proc-macro
1038 pub fn is_proc_macro(&self) -> bool {
1039 matches!(self.id.kind, MacroDefKind::ProcMacro(_))
1040 }
1041
1042 /// Indicate it is a derive macro
1043 pub fn is_derive_macro(&self) -> bool {
1044 matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_))
1045 }
1046}
1047
1048/// Invariant: `inner.as_assoc_item(db).is_some()`
1049/// We do not actively enforce this invariant.
1050#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1051pub enum AssocItem {
1052 Function(Function),
1053 Const(Const),
1054 TypeAlias(TypeAlias),
1055}
1056pub enum AssocItemContainer {
1057 Trait(Trait),
1058 Impl(Impl),
1059}
1060pub trait AsAssocItem {
1061 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
1062}
1063
1064impl AsAssocItem for Function {
1065 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1066 as_assoc_item(db, AssocItem::Function, self.id)
1067 }
1068}
1069impl AsAssocItem for Const {
1070 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1071 as_assoc_item(db, AssocItem::Const, self.id)
1072 }
1073}
1074impl AsAssocItem for TypeAlias {
1075 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1076 as_assoc_item(db, AssocItem::TypeAlias, self.id)
1077 }
1078}
1079impl AsAssocItem for ModuleDef {
1080 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1081 match self {
1082 ModuleDef::Function(it) => it.as_assoc_item(db),
1083 ModuleDef::Const(it) => it.as_assoc_item(db),
1084 ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
1085 _ => None,
1086 }
1087 }
1088}
1089fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
1090where
1091 ID: Lookup<Data = AssocItemLoc<AST>>,
1092 DEF: From<ID>,
1093 CTOR: FnOnce(DEF) -> AssocItem,
1094 AST: ItemTreeNode,
1095{
1096 match id.lookup(db.upcast()).container {
1097 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
1098 AssocContainerId::ContainerId(_) => None,
1099 }
1100}
1101
1102impl AssocItem {
1103 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1104 match self {
1105 AssocItem::Function(it) => Some(it.name(db)),
1106 AssocItem::Const(it) => it.name(db),
1107 AssocItem::TypeAlias(it) => Some(it.name(db)),
1108 }
1109 }
1110 pub fn module(self, db: &dyn HirDatabase) -> Module {
1111 match self {
1112 AssocItem::Function(f) => f.module(db),
1113 AssocItem::Const(c) => c.module(db),
1114 AssocItem::TypeAlias(t) => t.module(db),
1115 }
1116 }
1117 pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
1118 let container = match self {
1119 AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
1120 AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
1121 AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
1122 };
1123 match container {
1124 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
1125 AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
1126 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"),
1127 }
1128 }
1129
1130 pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
1131 match self.container(db) {
1132 AssocItemContainer::Trait(t) => Some(t),
1133 _ => None,
1134 }
1135 }
1136}
1137
1138impl HasVisibility for AssocItem {
1139 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
1140 match self {
1141 AssocItem::Function(f) => f.visibility(db),
1142 AssocItem::Const(c) => c.visibility(db),
1143 AssocItem::TypeAlias(t) => t.visibility(db),
1144 }
1145 }
1146}
1147
1148#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1149pub enum GenericDef {
1150 Function(Function),
1151 Adt(Adt),
1152 Trait(Trait),
1153 TypeAlias(TypeAlias),
1154 Impl(Impl),
1155 // enum variants cannot have generics themselves, but their parent enums
1156 // can, and this makes some code easier to write
1157 Variant(Variant),
1158 // consts can have type parameters from their parents (i.e. associated consts of traits)
1159 Const(Const),
1160}
1161impl_from!(
1162 Function,
1163 Adt(Struct, Enum, Union),
1164 Trait,
1165 TypeAlias,
1166 Impl,
1167 Variant,
1168 Const
1169 for GenericDef
1170);
1171
1172impl GenericDef {
1173 pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
1174 let generics = db.generic_params(self.into());
1175 let ty_params = generics
1176 .types
1177 .iter()
1178 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
1179 .map(GenericParam::TypeParam);
1180 let lt_params = generics
1181 .lifetimes
1182 .iter()
1183 .map(|(local_id, _)| LifetimeParam {
1184 id: LifetimeParamId { parent: self.into(), local_id },
1185 })
1186 .map(GenericParam::LifetimeParam);
1187 let const_params = generics
1188 .consts
1189 .iter()
1190 .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } })
1191 .map(GenericParam::ConstParam);
1192 ty_params.chain(lt_params).chain(const_params).collect()
1193 }
1194
1195 pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
1196 let generics = db.generic_params(self.into());
1197 generics
1198 .types
1199 .iter()
1200 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
1201 .collect()
1202 }
1203}
1204
1205#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1206pub struct Local {
1207 pub(crate) parent: DefWithBodyId,
1208 pub(crate) pat_id: PatId,
1209}
1210
1211impl Local {
1212 pub fn is_param(self, db: &dyn HirDatabase) -> bool {
1213 let src = self.source(db);
1214 match src.value {
1215 Either::Left(bind_pat) => {
1216 bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind()))
1217 }
1218 Either::Right(_self_param) => true,
1219 }
1220 }
1221
1222 // FIXME: why is this an option? It shouldn't be?
1223 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1224 let body = db.body(self.parent.into());
1225 match &body[self.pat_id] {
1226 Pat::Bind { name, .. } => Some(name.clone()),
1227 _ => None,
1228 }
1229 }
1230
1231 pub fn is_self(self, db: &dyn HirDatabase) -> bool {
1232 self.name(db) == Some(name![self])
1233 }
1234
1235 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
1236 let body = db.body(self.parent.into());
1237 match &body[self.pat_id] {
1238 Pat::Bind { mode, .. } => match mode {
1239 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
1240 _ => false,
1241 },
1242 _ => false,
1243 }
1244 }
1245
1246 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
1247 self.parent.into()
1248 }
1249
1250 pub fn module(self, db: &dyn HirDatabase) -> Module {
1251 self.parent(db).module(db)
1252 }
1253
1254 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1255 let def = DefWithBodyId::from(self.parent);
1256 let infer = db.infer(def);
1257 let ty = infer[self.pat_id].clone();
1258 let krate = def.module(db.upcast()).krate();
1259 Type::new(db, krate, def, ty)
1260 }
1261
1262 pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> {
1263 let (_body, source_map) = db.body_with_source_map(self.parent.into());
1264 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
1265 let root = src.file_syntax(db.upcast());
1266 src.map(|ast| {
1267 ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root))
1268 })
1269 }
1270}
1271
1272#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1273pub struct Label {
1274 pub(crate) parent: DefWithBodyId,
1275 pub(crate) label_id: LabelId,
1276}
1277
1278impl Label {
1279 pub fn module(self, db: &dyn HirDatabase) -> Module {
1280 self.parent(db).module(db)
1281 }
1282
1283 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
1284 self.parent.into()
1285 }
1286
1287 pub fn name(self, db: &dyn HirDatabase) -> Name {
1288 let body = db.body(self.parent.into());
1289 body[self.label_id].name.clone()
1290 }
1291
1292 pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
1293 let (_body, source_map) = db.body_with_source_map(self.parent.into());
1294 let src = source_map.label_syntax(self.label_id);
1295 let root = src.file_syntax(db.upcast());
1296 src.map(|ast| ast.to_node(&root))
1297 }
1298}
1299
1300#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1301pub enum GenericParam {
1302 TypeParam(TypeParam),
1303 LifetimeParam(LifetimeParam),
1304 ConstParam(ConstParam),
1305}
1306impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
1307
1308impl GenericParam {
1309 pub fn module(self, db: &dyn HirDatabase) -> Module {
1310 match self {
1311 GenericParam::TypeParam(it) => it.module(db),
1312 GenericParam::LifetimeParam(it) => it.module(db),
1313 GenericParam::ConstParam(it) => it.module(db),
1314 }
1315 }
1316
1317 pub fn name(self, db: &dyn HirDatabase) -> Name {
1318 match self {
1319 GenericParam::TypeParam(it) => it.name(db),
1320 GenericParam::LifetimeParam(it) => it.name(db),
1321 GenericParam::ConstParam(it) => it.name(db),
1322 }
1323 }
1324}
1325
1326#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1327pub struct TypeParam {
1328 pub(crate) id: TypeParamId,
1329}
1330
1331impl TypeParam {
1332 pub fn name(self, db: &dyn HirDatabase) -> Name {
1333 let params = db.generic_params(self.id.parent);
1334 params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
1335 }
1336
1337 pub fn module(self, db: &dyn HirDatabase) -> Module {
1338 self.id.parent.module(db.upcast()).into()
1339 }
1340
1341 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1342 let resolver = self.id.parent.resolver(db.upcast());
1343 let environment = TraitEnvironment::lower(db, &resolver);
1344 let ty = Ty::Placeholder(self.id);
1345 Type {
1346 krate: self.id.parent.module(db.upcast()).krate(),
1347 ty: InEnvironment { value: ty, environment },
1348 }
1349 }
1350
1351 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
1352 db.generic_predicates_for_param(self.id)
1353 .into_iter()
1354 .filter_map(|pred| match &pred.value {
1355 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1356 Some(Trait::from(trait_ref.trait_))
1357 }
1358 _ => None,
1359 })
1360 .collect()
1361 }
1362
1363 pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
1364 let params = db.generic_defaults(self.id.parent);
1365 let local_idx = hir_ty::param_idx(db, self.id)?;
1366 let resolver = self.id.parent.resolver(db.upcast());
1367 let environment = TraitEnvironment::lower(db, &resolver);
1368 let ty = params.get(local_idx)?.clone();
1369 let subst = Substs::type_params(db, self.id.parent);
1370 let ty = ty.subst(&subst.prefix(local_idx));
1371 Some(Type {
1372 krate: self.id.parent.module(db.upcast()).krate(),
1373 ty: InEnvironment { value: ty, environment },
1374 })
1375 }
1376}
1377
1378impl HirDisplay for TypeParam {
1379 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1380 write!(f, "{}", self.name(f.db))?;
1381 let bounds = f.db.generic_predicates_for_param(self.id);
1382 let substs = Substs::type_params(f.db, self.id.parent);
1383 let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
1384 if !(predicates.is_empty() || f.omit_verbose_types()) {
1385 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
1386 }
1387 Ok(())
1388 }
1389}
1390
1391#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1392pub struct LifetimeParam {
1393 pub(crate) id: LifetimeParamId,
1394}
1395
1396impl LifetimeParam {
1397 pub fn name(self, db: &dyn HirDatabase) -> Name {
1398 let params = db.generic_params(self.id.parent);
1399 params.lifetimes[self.id.local_id].name.clone()
1400 }
1401
1402 pub fn module(self, db: &dyn HirDatabase) -> Module {
1403 self.id.parent.module(db.upcast()).into()
1404 }
1405
1406 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
1407 self.id.parent.into()
1408 }
1409}
1410
1411#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1412pub struct ConstParam {
1413 pub(crate) id: ConstParamId,
1414}
1415
1416impl ConstParam {
1417 pub fn name(self, db: &dyn HirDatabase) -> Name {
1418 let params = db.generic_params(self.id.parent);
1419 params.consts[self.id.local_id].name.clone()
1420 }
1421
1422 pub fn module(self, db: &dyn HirDatabase) -> Module {
1423 self.id.parent.module(db.upcast()).into()
1424 }
1425
1426 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
1427 self.id.parent.into()
1428 }
1429
1430 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1431 let def = self.id.parent;
1432 let krate = def.module(db.upcast()).krate();
1433 Type::new(db, krate, def, db.const_param_ty(self.id))
1434 }
1435}
1436
1437#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1438pub struct Impl {
1439 pub(crate) id: ImplId,
1440}
1441
1442impl Impl {
1443 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
1444 let inherent = db.inherent_impls_in_crate(krate.id);
1445 let trait_ = db.trait_impls_in_crate(krate.id);
1446
1447 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1448 }
1449 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> {
1450 let impls = db.trait_impls_in_crate(krate.id);
1451 impls.for_trait(trait_.id).map(Self::from).collect()
1452 }
1453
1454 // FIXME: the return type is wrong. This should be a hir version of
1455 // `TraitRef` (ie, resolved `TypeRef`).
1456 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1457 db.impl_data(self.id).target_trait.clone()
1458 }
1459
1460 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1461 let impl_data = db.impl_data(self.id);
1462 let resolver = self.id.resolver(db.upcast());
1463 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
1464 let environment = TraitEnvironment::lower(db, &resolver);
1465 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
1466 Type {
1467 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
1468 ty: InEnvironment { value: ty, environment },
1469 }
1470 }
1471
1472 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
1473 db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
1474 }
1475
1476 pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
1477 db.impl_data(self.id).is_negative
1478 }
1479
1480 pub fn module(self, db: &dyn HirDatabase) -> Module {
1481 self.id.lookup(db.upcast()).container.module(db.upcast()).into()
1482 }
1483
1484 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1485 Crate { id: self.module(db).id.krate() }
1486 }
1487
1488 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1489 let src = self.source(db)?;
1490 let item = src.file_id.is_builtin_derive(db.upcast())?;
1491 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
1492
1493 // FIXME: handle `cfg_attr`
1494 let attr = item
1495 .value
1496 .attrs()
1497 .filter_map(|it| {
1498 let path = ModPath::from_src(it.path()?, &hygenic)?;
1499 if path.as_ident()?.to_string() == "derive" {
1500 Some(it)
1501 } else {
1502 None
1503 }
1504 })
1505 .last()?;
1506
1507 Some(item.with_value(attr))
1508 }
1509}
1510
1511#[derive(Clone, PartialEq, Eq, Debug)]
1512pub struct Type {
1513 krate: CrateId,
1514 ty: InEnvironment<Ty>,
1515}
1516
1517impl Type {
1518 pub(crate) fn new_with_resolver(
1519 db: &dyn HirDatabase,
1520 resolver: &Resolver,
1521 ty: Ty,
1522 ) -> Option<Type> {
1523 let krate = resolver.krate()?;
1524 Some(Type::new_with_resolver_inner(db, krate, resolver, ty))
1525 }
1526 pub(crate) fn new_with_resolver_inner(
1527 db: &dyn HirDatabase,
1528 krate: CrateId,
1529 resolver: &Resolver,
1530 ty: Ty,
1531 ) -> Type {
1532 let environment = TraitEnvironment::lower(db, &resolver);
1533 Type { krate, ty: InEnvironment { value: ty, environment } }
1534 }
1535
1536 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1537 let resolver = lexical_env.resolver(db.upcast());
1538 let environment = TraitEnvironment::lower(db, &resolver);
1539 Type { krate, ty: InEnvironment { value: ty, environment } }
1540 }
1541
1542 fn from_def(
1543 db: &dyn HirDatabase,
1544 krate: CrateId,
1545 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
1546 ) -> Type {
1547 let substs = Substs::build_for_def(db, def).fill_with_unknown().build();
1548 let ty = db.ty(def.into()).subst(&substs);
1549 Type::new(db, krate, def, ty)
1550 }
1551
1552 pub fn is_unit(&self) -> bool {
1553 matches!(self.ty.value, Ty::Tuple(0, ..))
1554 }
1555 pub fn is_bool(&self) -> bool {
1556 matches!(self.ty.value, Ty::Scalar(Scalar::Bool))
1557 }
1558
1559 pub fn is_mutable_reference(&self) -> bool {
1560 matches!(self.ty.value, Ty::Ref(Mutability::Mut, ..))
1561 }
1562
1563 pub fn remove_ref(&self) -> Option<Type> {
1564 if let Ty::Ref(.., substs) = &self.ty.value {
1565 Some(self.derived(substs[0].clone()))
1566 } else {
1567 None
1568 }
1569 }
1570
1571 pub fn is_unknown(&self) -> bool {
1572 matches!(self.ty.value, Ty::Unknown)
1573 }
1574
1575 /// Checks that particular type `ty` implements `std::future::Future`.
1576 /// This function is used in `.await` syntax completion.
1577 pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
1578 // No special case for the type of async block, since Chalk can figure it out.
1579
1580 let krate = self.krate;
1581
1582 let std_future_trait =
1583 db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait());
1584 let std_future_trait = match std_future_trait {
1585 Some(it) => it,
1586 None => return false,
1587 };
1588
1589 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1590 method_resolution::implements_trait(
1591 &canonical_ty,
1592 db,
1593 self.ty.environment.clone(),
1594 krate,
1595 std_future_trait,
1596 )
1597 }
1598
1599 /// Checks that particular type `ty` implements `std::ops::FnOnce`.
1600 ///
1601 /// This function can be used to check if a particular type is callable, since FnOnce is a
1602 /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
1603 pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
1604 let krate = self.krate;
1605
1606 let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) {
1607 Some(it) => it,
1608 None => return false,
1609 };
1610
1611 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1612 method_resolution::implements_trait_unique(
1613 &canonical_ty,
1614 db,
1615 self.ty.environment.clone(),
1616 krate,
1617 fnonce_trait,
1618 )
1619 }
1620
1621 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1622 let trait_ref = hir_ty::TraitRef {
1623 trait_: trait_.id,
1624 substs: Substs::build_for_def(db, trait_.id)
1625 .push(self.ty.value.clone())
1626 .fill(args.iter().map(|t| t.ty.value.clone()))
1627 .build(),
1628 };
1629
1630 let goal = Canonical {
1631 value: hir_ty::InEnvironment::new(
1632 self.ty.environment.clone(),
1633 hir_ty::Obligation::Trait(trait_ref),
1634 ),
1635 kinds: Arc::new([]),
1636 };
1637
1638 db.trait_solve(self.krate, goal).is_some()
1639 }
1640
1641 pub fn normalize_trait_assoc_type(
1642 &self,
1643 db: &dyn HirDatabase,
1644 trait_: Trait,
1645 args: &[Type],
1646 alias: TypeAlias,
1647 ) -> Option<Type> {
1648 let subst = Substs::build_for_def(db, trait_.id)
1649 .push(self.ty.value.clone())
1650 .fill(args.iter().map(|t| t.ty.value.clone()))
1651 .build();
1652 let predicate = ProjectionPredicate {
1653 projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst },
1654 ty: Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)),
1655 };
1656 let goal = Canonical {
1657 value: InEnvironment::new(
1658 self.ty.environment.clone(),
1659 Obligation::Projection(predicate),
1660 ),
1661 kinds: Arc::new([TyVariableKind::General]),
1662 };
1663
1664 match db.trait_solve(self.krate, goal)? {
1665 Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(),
1666 Solution::Ambig(_) => None,
1667 }
1668 .map(|ty| Type {
1669 krate: self.krate,
1670 ty: InEnvironment { value: ty, environment: Arc::clone(&self.ty.environment) },
1671 })
1672 }
1673
1674 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
1675 let lang_item = db.lang_item(self.krate, SmolStr::new("copy"));
1676 let copy_trait = match lang_item {
1677 Some(LangItemTarget::TraitId(it)) => it,
1678 _ => return false,
1679 };
1680 self.impls_trait(db, copy_trait.into(), &[])
1681 }
1682
1683 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1684 let def = match self.ty.value {
1685 Ty::FnDef(def, _) => Some(def),
1686 _ => None,
1687 };
1688
1689 let sig = self.ty.value.callable_sig(db)?;
1690 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
1691 }
1692
1693 pub fn is_closure(&self) -> bool {
1694 matches!(&self.ty.value, Ty::Closure { .. })
1695 }
1696
1697 pub fn is_fn(&self) -> bool {
1698 matches!(&self.ty.value, Ty::FnDef(..) | Ty::Function { .. })
1699 }
1700
1701 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1702 let adt_id = match self.ty.value {
1703 Ty::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
1704 _ => return false,
1705 };
1706
1707 let adt = adt_id.into();
1708 match adt {
1709 Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
1710 _ => false,
1711 }
1712 }
1713
1714 pub fn is_raw_ptr(&self) -> bool {
1715 matches!(&self.ty.value, Ty::Raw(..))
1716 }
1717
1718 pub fn contains_unknown(&self) -> bool {
1719 return go(&self.ty.value);
1720
1721 fn go(ty: &Ty) -> bool {
1722 match ty {
1723 Ty::Unknown => true,
1724 _ => ty.substs().map_or(false, |substs| substs.iter().any(go)),
1725 }
1726 }
1727 }
1728
1729 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1730 let (variant_id, substs) = match self.ty.value {
1731 Ty::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs),
1732 Ty::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs),
1733 _ => return Vec::new(),
1734 };
1735
1736 db.field_types(variant_id)
1737 .iter()
1738 .map(|(local_id, ty)| {
1739 let def = Field { parent: variant_id.into(), id: local_id };
1740 let ty = ty.clone().subst(substs);
1741 (def, self.derived(ty))
1742 })
1743 .collect()
1744 }
1745
1746 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
1747 if let Ty::Tuple(_, substs) = &self.ty.value {
1748 substs.iter().map(|ty| self.derived(ty.clone())).collect()
1749 } else {
1750 Vec::new()
1751 }
1752 }
1753
1754 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1755 // There should be no inference vars in types passed here
1756 // FIXME check that?
1757 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1758 let environment = self.ty.environment.clone();
1759 let ty = InEnvironment { value: canonical, environment };
1760 autoderef(db, Some(self.krate), ty)
1761 .map(|canonical| canonical.value)
1762 .map(move |ty| self.derived(ty))
1763 }
1764
1765 // This would be nicer if it just returned an iterator, but that runs into
1766 // lifetime problems, because we need to borrow temp `CrateImplDefs`.
1767 pub fn iterate_assoc_items<T>(
1768 self,
1769 db: &dyn HirDatabase,
1770 krate: Crate,
1771 mut callback: impl FnMut(AssocItem) -> Option<T>,
1772 ) -> Option<T> {
1773 for krate in self.ty.value.def_crates(db, krate.id)? {
1774 let impls = db.inherent_impls_in_crate(krate);
1775
1776 for impl_def in impls.for_self_ty(&self.ty.value) {
1777 for &item in db.impl_data(*impl_def).items.iter() {
1778 if let Some(result) = callback(item.into()) {
1779 return Some(result);
1780 }
1781 }
1782 }
1783 }
1784 None
1785 }
1786
1787 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ {
1788 self.ty
1789 .value
1790 .strip_references()
1791 .substs()
1792 .into_iter()
1793 .flat_map(|substs| substs.iter())
1794 .map(move |ty| self.derived(ty.clone()))
1795 }
1796
1797 pub fn iterate_method_candidates<T>(
1798 &self,
1799 db: &dyn HirDatabase,
1800 krate: Crate,
1801 traits_in_scope: &FxHashSet<TraitId>,
1802 name: Option<&Name>,
1803 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
1804 ) -> Option<T> {
1805 // There should be no inference vars in types passed here
1806 // FIXME check that?
1807 // FIXME replace Unknown by bound vars here
1808 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1809
1810 let env = self.ty.environment.clone();
1811 let krate = krate.id;
1812
1813 method_resolution::iterate_method_candidates(
1814 &canonical,
1815 db,
1816 env,
1817 krate,
1818 traits_in_scope,
1819 name,
1820 method_resolution::LookupMode::MethodCall,
1821 |ty, it| match it {
1822 AssocItemId::FunctionId(f) => callback(ty, f.into()),
1823 _ => None,
1824 },
1825 )
1826 }
1827
1828 pub fn iterate_path_candidates<T>(
1829 &self,
1830 db: &dyn HirDatabase,
1831 krate: Crate,
1832 traits_in_scope: &FxHashSet<TraitId>,
1833 name: Option<&Name>,
1834 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
1835 ) -> Option<T> {
1836 // There should be no inference vars in types passed here
1837 // FIXME check that?
1838 // FIXME replace Unknown by bound vars here
1839 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1840
1841 let env = self.ty.environment.clone();
1842 let krate = krate.id;
1843
1844 method_resolution::iterate_method_candidates(
1845 &canonical,
1846 db,
1847 env,
1848 krate,
1849 traits_in_scope,
1850 name,
1851 method_resolution::LookupMode::Path,
1852 |ty, it| callback(ty, it.into()),
1853 )
1854 }
1855
1856 pub fn as_adt(&self) -> Option<Adt> {
1857 let (adt, _subst) = self.ty.value.as_adt()?;
1858 Some(adt.into())
1859 }
1860
1861 pub fn as_dyn_trait(&self) -> Option<Trait> {
1862 self.ty.value.dyn_trait().map(Into::into)
1863 }
1864
1865 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
1866 self.ty.value.impl_trait_bounds(db).map(|it| {
1867 it.into_iter()
1868 .filter_map(|pred| match pred {
1869 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1870 Some(Trait::from(trait_ref.trait_))
1871 }
1872 _ => None,
1873 })
1874 .collect()
1875 })
1876 }
1877
1878 pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1879 self.ty.value.associated_type_parent_trait(db).map(Into::into)
1880 }
1881
1882 // FIXME: provide required accessors such that it becomes implementable from outside.
1883 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1884 let rref = other.remove_ref();
1885 self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value))
1886 }
1887
1888 fn derived(&self, ty: Ty) -> Type {
1889 Type {
1890 krate: self.krate,
1891 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1892 }
1893 }
1894
1895 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1896 // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
1897 // We need a different order here.
1898
1899 fn walk_substs(
1900 db: &dyn HirDatabase,
1901 type_: &Type,
1902 substs: &Substs,
1903 cb: &mut impl FnMut(Type),
1904 ) {
1905 for ty in substs.iter() {
1906 walk_type(db, &type_.derived(ty.clone()), cb);
1907 }
1908 }
1909
1910 fn walk_bounds(
1911 db: &dyn HirDatabase,
1912 type_: &Type,
1913 bounds: &[GenericPredicate],
1914 cb: &mut impl FnMut(Type),
1915 ) {
1916 for pred in bounds {
1917 match pred {
1918 GenericPredicate::Implemented(trait_ref) => {
1919 cb(type_.clone());
1920 walk_substs(db, type_, &trait_ref.substs, cb);
1921 }
1922 _ => (),
1923 }
1924 }
1925 }
1926
1927 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
1928 let ty = type_.ty.value.strip_references();
1929 match ty {
1930 Ty::Adt(..) => {
1931 cb(type_.derived(ty.clone()));
1932 }
1933 Ty::AssociatedType(..) => {
1934 if let Some(_) = ty.associated_type_parent_trait(db) {
1935 cb(type_.derived(ty.clone()));
1936 }
1937 }
1938 Ty::OpaqueType(..) => {
1939 if let Some(bounds) = ty.impl_trait_bounds(db) {
1940 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1941 }
1942 }
1943 Ty::Alias(AliasTy::Opaque(opaque_ty)) => {
1944 if let Some(bounds) = ty.impl_trait_bounds(db) {
1945 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1946 }
1947
1948 walk_substs(db, type_, &opaque_ty.parameters, cb);
1949 }
1950 Ty::Placeholder(_) => {
1951 if let Some(bounds) = ty.impl_trait_bounds(db) {
1952 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1953 }
1954 }
1955 Ty::Dyn(bounds) => {
1956 walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb);
1957 }
1958
1959 _ => {}
1960 }
1961 if let Some(substs) = ty.substs() {
1962 walk_substs(db, type_, &substs, cb);
1963 }
1964 }
1965
1966 walk_type(db, self, &mut cb);
1967 }
1968}
1969
1970impl HirDisplay for Type {
1971 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1972 self.ty.value.hir_fmt(f)
1973 }
1974}
1975
1976// FIXME: closures
1977#[derive(Debug)]
1978pub struct Callable {
1979 ty: Type,
1980 sig: CallableSig,
1981 def: Option<CallableDefId>,
1982 pub(crate) is_bound_method: bool,
1983}
1984
1985pub enum CallableKind {
1986 Function(Function),
1987 TupleStruct(Struct),
1988 TupleEnumVariant(Variant),
1989 Closure,
1990}
1991
1992impl Callable {
1993 pub fn kind(&self) -> CallableKind {
1994 match self.def {
1995 Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
1996 Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
1997 Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
1998 None => CallableKind::Closure,
1999 }
2000 }
2001 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
2002 let func = match self.def {
2003 Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
2004 _ => return None,
2005 };
2006 let src = func.lookup(db.upcast()).source(db.upcast());
2007 let param_list = src.value.param_list()?;
2008 param_list.self_param()
2009 }
2010 pub fn n_params(&self) -> usize {
2011 self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
2012 }
2013 pub fn params(
2014 &self,
2015 db: &dyn HirDatabase,
2016 ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
2017 let types = self
2018 .sig
2019 .params()
2020 .iter()
2021 .skip(if self.is_bound_method { 1 } else { 0 })
2022 .map(|ty| self.ty.derived(ty.clone()));
2023 let patterns = match self.def {
2024 Some(CallableDefId::FunctionId(func)) => {
2025 let src = func.lookup(db.upcast()).source(db.upcast());
2026 src.value.param_list().map(|param_list| {
2027 param_list
2028 .self_param()
2029 .map(|it| Some(Either::Left(it)))
2030 .filter(|_| !self.is_bound_method)
2031 .into_iter()
2032 .chain(param_list.params().map(|it| it.pat().map(Either::Right)))
2033 })
2034 }
2035 _ => None,
2036 };
2037 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
2038 }
2039 pub fn return_type(&self) -> Type {
2040 self.ty.derived(self.sig.ret().clone())
2041 }
2042}
2043
2044/// For IDE only
2045#[derive(Debug, PartialEq, Eq, Hash)]
2046pub enum ScopeDef {
2047 ModuleDef(ModuleDef),
2048 MacroDef(MacroDef),
2049 GenericParam(GenericParam),
2050 ImplSelfType(Impl),
2051 AdtSelfType(Adt),
2052 Local(Local),
2053 Unknown,
2054}
2055
2056impl ScopeDef {
2057 pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> {
2058 let mut items = ArrayVec::new();
2059
2060 match (def.take_types(), def.take_values()) {
2061 (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
2062 (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
2063 (Some(m1), Some(m2)) => {
2064 // Some items, like unit structs and enum variants, are
2065 // returned as both a type and a value. Here we want
2066 // to de-duplicate them.
2067 if m1 != m2 {
2068 items.push(ScopeDef::ModuleDef(m1.into()));
2069 items.push(ScopeDef::ModuleDef(m2.into()));
2070 } else {
2071 items.push(ScopeDef::ModuleDef(m1.into()));
2072 }
2073 }
2074 (None, None) => {}
2075 };
2076
2077 if let Some(macro_def_id) = def.take_macros() {
2078 items.push(ScopeDef::MacroDef(macro_def_id.into()));
2079 }
2080
2081 if items.is_empty() {
2082 items.push(ScopeDef::Unknown);
2083 }
2084
2085 items
2086 }
2087}
2088
2089pub trait HasVisibility {
2090 fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
2091 fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
2092 let vis = self.visibility(db);
2093 vis.is_visible_from(db.upcast(), module.id)
2094 }
2095}
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index b5814da11..179b9d51e 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -11,9 +11,8 @@ use hir_def::{
11}; 11};
12 12
13use crate::{ 13use crate::{
14 code_model::{BuiltinType, GenericParam}, 14 Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, Label, Local,
15 Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, 15 MacroDef, ModuleDef, Variant, VariantDef,
16 VariantDef,
17}; 16};
18 17
19macro_rules! from_id { 18macro_rules! from_id {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 69fcdab07..d5a3d9034 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -20,49 +20,2137 @@
20#![recursion_limit = "512"] 20#![recursion_limit = "512"]
21 21
22mod semantics; 22mod semantics;
23pub mod db;
24mod source_analyzer; 23mod source_analyzer;
25 24
26pub mod diagnostics;
27
28mod from_id; 25mod from_id;
29mod code_model;
30mod attrs; 26mod attrs;
31mod has_source; 27mod has_source;
32 28
29pub mod diagnostics;
30pub mod db;
31
32use std::{iter, sync::Arc};
33
34use arrayvec::ArrayVec;
35use base_db::{CrateDisplayName, CrateId, Edition, FileId};
36use either::Either;
37use hir_def::{
38 adt::{ReprKind, VariantData},
39 expr::{BindingAnnotation, LabelId, Pat, PatId},
40 item_tree::ItemTreeNode,
41 lang_item::LangItemTarget,
42 per_ns::PerNs,
43 resolver::{HasResolver, Resolver},
44 src::HasSource as _,
45 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
46 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
47 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
48 TypeParamId, UnionId,
49};
50use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
51use hir_ty::{
52 autoderef,
53 display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
54 method_resolution,
55 traits::{FnTrait, Solution, SolutionVariables},
56 AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
57 InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, TraitEnvironment,
58 Ty, TyDefId, TyVariableKind,
59};
60use rustc_hash::FxHashSet;
61use stdx::{format_to, impl_from};
62use syntax::{
63 ast::{self, AttrsOwner, NameOwner},
64 AstNode, SmolStr,
65};
66use tt::{Ident, Leaf, Literal, TokenTree};
67
68use crate::db::{DefDatabase, HirDatabase};
69
33pub use crate::{ 70pub use crate::{
34 attrs::{HasAttrs, Namespace}, 71 attrs::{HasAttrs, Namespace},
35 code_model::{
36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, BuiltinType, Callable,
37 CallableKind, Const, ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field,
38 FieldSource, Function, GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam,
39 Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
40 TypeParam, Union, Variant, VariantDef,
41 },
42 has_source::HasSource, 72 has_source::HasSource,
43 semantics::{PathResolution, Semantics, SemanticsScope}, 73 semantics::{PathResolution, Semantics, SemanticsScope},
44}; 74};
45 75
46pub use hir_def::{ 76// Be careful with these re-exports.
47 adt::StructKind, 77//
48 attr::{Attrs, Documentation}, 78// `hir` is the boundary between the compiler and the IDE. It should try hard to
49 body::scope::ExprScopes, 79// isolate the compiler from the ide, to allow the two to be refactored
50 find_path::PrefixKind, 80// independently. Re-exporting something from the compiler is the sure way to
51 import_map, 81// breach the boundary.
52 item_scope::ItemInNs, 82//
53 nameres::ModuleSource, 83// Generally, a refactoring which *removes* a name from this list is a good
54 path::{ModPath, PathKind}, 84// idea!
55 type_ref::{Mutability, TypeRef}, 85pub use {
56 visibility::Visibility, 86 hir_def::{
57}; 87 adt::StructKind,
58pub use hir_expand::{ 88 attr::{Attrs, Documentation},
59 name::{known, AsName, Name}, 89 body::scope::ExprScopes,
60 ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, 90 find_path::PrefixKind,
61 MacroFile, Origin, 91 import_map,
92 item_scope::ItemInNs,
93 nameres::ModuleSource,
94 path::{ModPath, PathKind},
95 type_ref::{Mutability, TypeRef},
96 visibility::Visibility,
97 },
98 hir_expand::{
99 name::{known, Name},
100 ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId,
101 MacroFile, Origin,
102 },
103 hir_ty::display::HirDisplay,
62}; 104};
63pub use hir_ty::display::HirDisplay;
64 105
65// These are negative re-exports: pub using these names is forbidden, they 106// These are negative re-exports: pub using these names is forbidden, they
66// should remain private to hir internals. 107// should remain private to hir internals.
67#[allow(unused)] 108#[allow(unused)]
68use {hir_def::path::Path, hir_expand::hygiene::Hygiene}; 109use {
110 hir_def::path::Path,
111 hir_expand::{hygiene::Hygiene, name::AsName},
112};
113
114/// hir::Crate describes a single crate. It's the main interface with which
115/// a crate's dependencies interact. Mostly, it should be just a proxy for the
116/// root module.
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118pub struct Crate {
119 pub(crate) id: CrateId,
120}
121
122#[derive(Debug)]
123pub struct CrateDependency {
124 pub krate: Crate,
125 pub name: Name,
126}
127
128impl Crate {
129 pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
130 db.crate_graph()[self.id]
131 .dependencies
132 .iter()
133 .map(|dep| {
134 let krate = Crate { id: dep.crate_id };
135 let name = dep.as_name();
136 CrateDependency { krate, name }
137 })
138 .collect()
139 }
140
141 // FIXME: add `transitive_reverse_dependencies`.
142 pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
143 let crate_graph = db.crate_graph();
144 crate_graph
145 .iter()
146 .filter(|&krate| {
147 crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
148 })
149 .map(|id| Crate { id })
150 .collect()
151 }
152
153 pub fn root_module(self, db: &dyn HirDatabase) -> Module {
154 let def_map = db.crate_def_map(self.id);
155 Module { id: def_map.module_id(def_map.root()) }
156 }
157
158 pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
159 db.crate_graph()[self.id].root_file_id
160 }
161
162 pub fn edition(self, db: &dyn HirDatabase) -> Edition {
163 db.crate_graph()[self.id].edition
164 }
165
166 pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
167 db.crate_graph()[self.id].display_name.clone()
168 }
169
170 pub fn query_external_importables(
171 self,
172 db: &dyn DefDatabase,
173 query: import_map::Query,
174 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
175 import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item {
176 ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()),
177 ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()),
178 })
179 }
180
181 pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
182 db.crate_graph().iter().map(|id| Crate { id }).collect()
183 }
184
185 /// Try to get the root URL of the documentation of a crate.
186 pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
187 // Look for #![doc(html_root_url = "...")]
188 let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
189 let doc_attr_q = attrs.by_key("doc");
190
191 if !doc_attr_q.exists() {
192 return None;
193 }
194
195 let doc_url = doc_attr_q.tt_values().map(|tt| {
196 let name = tt.token_trees.iter()
197 .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url"))
198 .skip(2)
199 .next();
200
201 match name {
202 Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text),
203 _ => None
204 }
205 }).flat_map(|t| t).next();
206
207 doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
208 }
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
212pub struct Module {
213 pub(crate) id: ModuleId,
214}
215
216/// The defs which can be visible in the module.
217#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
218pub enum ModuleDef {
219 Module(Module),
220 Function(Function),
221 Adt(Adt),
222 // Can't be directly declared, but can be imported.
223 Variant(Variant),
224 Const(Const),
225 Static(Static),
226 Trait(Trait),
227 TypeAlias(TypeAlias),
228 BuiltinType(BuiltinType),
229}
230impl_from!(
231 Module,
232 Function,
233 Adt(Struct, Enum, Union),
234 Variant,
235 Const,
236 Static,
237 Trait,
238 TypeAlias,
239 BuiltinType
240 for ModuleDef
241);
242
243impl From<VariantDef> for ModuleDef {
244 fn from(var: VariantDef) -> Self {
245 match var {
246 VariantDef::Struct(t) => Adt::from(t).into(),
247 VariantDef::Union(t) => Adt::from(t).into(),
248 VariantDef::Variant(t) => t.into(),
249 }
250 }
251}
252
253impl ModuleDef {
254 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
255 match self {
256 ModuleDef::Module(it) => it.parent(db),
257 ModuleDef::Function(it) => Some(it.module(db)),
258 ModuleDef::Adt(it) => Some(it.module(db)),
259 ModuleDef::Variant(it) => Some(it.module(db)),
260 ModuleDef::Const(it) => Some(it.module(db)),
261 ModuleDef::Static(it) => Some(it.module(db)),
262 ModuleDef::Trait(it) => Some(it.module(db)),
263 ModuleDef::TypeAlias(it) => Some(it.module(db)),
264 ModuleDef::BuiltinType(_) => None,
265 }
266 }
267
268 pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
269 let mut segments = Vec::new();
270 segments.push(self.name(db)?.to_string());
271 for m in self.module(db)?.path_to_root(db) {
272 segments.extend(m.name(db).map(|it| it.to_string()))
273 }
274 segments.reverse();
275 Some(segments.join("::"))
276 }
277
278 pub fn definition_visibility(&self, db: &dyn HirDatabase) -> Option<Visibility> {
279 let module = match self {
280 ModuleDef::Module(it) => it.parent(db)?,
281 ModuleDef::Function(it) => return Some(it.visibility(db)),
282 ModuleDef::Adt(it) => it.module(db),
283 ModuleDef::Variant(it) => {
284 let parent = it.parent_enum(db);
285 let module = it.module(db);
286 return module.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent)));
287 }
288 ModuleDef::Const(it) => return Some(it.visibility(db)),
289 ModuleDef::Static(it) => it.module(db),
290 ModuleDef::Trait(it) => it.module(db),
291 ModuleDef::TypeAlias(it) => return Some(it.visibility(db)),
292 ModuleDef::BuiltinType(_) => return None,
293 };
294
295 module.visibility_of(db, self)
296 }
297
298 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
299 match self {
300 ModuleDef::Adt(it) => Some(it.name(db)),
301 ModuleDef::Trait(it) => Some(it.name(db)),
302 ModuleDef::Function(it) => Some(it.name(db)),
303 ModuleDef::Variant(it) => Some(it.name(db)),
304 ModuleDef::TypeAlias(it) => Some(it.name(db)),
305 ModuleDef::Module(it) => it.name(db),
306 ModuleDef::Const(it) => it.name(db),
307 ModuleDef::Static(it) => it.name(db),
308
309 ModuleDef::BuiltinType(it) => Some(it.name()),
310 }
311 }
312
313 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
314 let id = match self {
315 ModuleDef::Adt(it) => match it {
316 Adt::Struct(it) => it.id.into(),
317 Adt::Enum(it) => it.id.into(),
318 Adt::Union(it) => it.id.into(),
319 },
320 ModuleDef::Trait(it) => it.id.into(),
321 ModuleDef::Function(it) => it.id.into(),
322 ModuleDef::TypeAlias(it) => it.id.into(),
323 ModuleDef::Module(it) => it.id.into(),
324 ModuleDef::Const(it) => it.id.into(),
325 ModuleDef::Static(it) => it.id.into(),
326 _ => return,
327 };
328
329 let module = match self.module(db) {
330 Some(it) => it,
331 None => return,
332 };
333
334 hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink)
335 }
336}
337
338impl Module {
339 /// Name of this module.
340 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
341 let def_map = self.id.def_map(db.upcast());
342 let parent = def_map[self.id.local_id].parent?;
343 def_map[parent].children.iter().find_map(|(name, module_id)| {
344 if *module_id == self.id.local_id {
345 Some(name.clone())
346 } else {
347 None
348 }
349 })
350 }
351
352 /// Returns the crate this module is part of.
353 pub fn krate(self) -> Crate {
354 Crate { id: self.id.krate() }
355 }
356
357 /// Topmost parent of this module. Every module has a `crate_root`, but some
358 /// might be missing `krate`. This can happen if a module's file is not included
359 /// in the module tree of any target in `Cargo.toml`.
360 pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
361 let def_map = db.crate_def_map(self.id.krate());
362 Module { id: def_map.module_id(def_map.root()) }
363 }
364
365 /// Iterates over all child modules.
366 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
367 let def_map = self.id.def_map(db.upcast());
368 let children = def_map[self.id.local_id]
369 .children
370 .iter()
371 .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
372 .collect::<Vec<_>>();
373 children.into_iter()
374 }
375
376 /// Finds a parent module.
377 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
378 // FIXME: handle block expressions as modules (their parent is in a different DefMap)
379 let def_map = self.id.def_map(db.upcast());
380 let parent_id = def_map[self.id.local_id].parent?;
381 Some(Module { id: def_map.module_id(parent_id) })
382 }
383
384 pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
385 let mut res = vec![self];
386 let mut curr = self;
387 while let Some(next) = curr.parent(db) {
388 res.push(next);
389 curr = next
390 }
391 res
392 }
393
394 /// Returns a `ModuleScope`: a set of items, visible in this module.
395 pub fn scope(
396 self,
397 db: &dyn HirDatabase,
398 visible_from: Option<Module>,
399 ) -> Vec<(Name, ScopeDef)> {
400 self.id.def_map(db.upcast())[self.id.local_id]
401 .scope
402 .entries()
403 .filter_map(|(name, def)| {
404 if let Some(m) = visible_from {
405 let filtered =
406 def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
407 if filtered.is_none() && !def.is_none() {
408 None
409 } else {
410 Some((name, filtered))
411 }
412 } else {
413 Some((name, def))
414 }
415 })
416 .flat_map(|(name, def)| {
417 ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
418 })
419 .collect()
420 }
421
422 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> {
423 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into())
424 }
425
426 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
427 let _p = profile::span("Module::diagnostics").detail(|| {
428 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
429 });
430 let def_map = self.id.def_map(db.upcast());
431 def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
432 for decl in self.declarations(db) {
433 match decl {
434 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
435 crate::ModuleDef::Module(m) => {
436 // Only add diagnostics from inline modules
437 if def_map[m.id.local_id].origin.is_inline() {
438 m.diagnostics(db, sink)
439 }
440 }
441 _ => {
442 decl.diagnostics(db, sink);
443 }
444 }
445 }
446
447 for impl_def in self.impl_defs(db) {
448 for item in impl_def.items(db) {
449 if let AssocItem::Function(f) = item {
450 f.diagnostics(db, sink);
451 }
452 }
453 }
454 }
455
456 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
457 let def_map = self.id.def_map(db.upcast());
458 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect()
459 }
460
461 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
462 let def_map = self.id.def_map(db.upcast());
463 def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
464 }
465
466 /// Finds a path that can be used to refer to the given item from within
467 /// this module, if possible.
468 pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> {
469 hir_def::find_path::find_path(db, item.into(), self.into())
470 }
471
472 /// Finds a path that can be used to refer to the given item from within
473 /// this module, if possible. This is used for returning import paths for use-statements.
474 pub fn find_use_path_prefixed(
475 self,
476 db: &dyn DefDatabase,
477 item: impl Into<ItemInNs>,
478 prefix_kind: PrefixKind,
479 ) -> Option<ModPath> {
480 hir_def::find_path::find_path_prefixed(db, item.into(), self.into(), prefix_kind)
481 }
482}
483
484#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
485pub struct Field {
486 pub(crate) parent: VariantDef,
487 pub(crate) id: LocalFieldId,
488}
489
490#[derive(Debug, PartialEq, Eq)]
491pub enum FieldSource {
492 Named(ast::RecordField),
493 Pos(ast::TupleField),
494}
495
496impl Field {
497 pub fn name(&self, db: &dyn HirDatabase) -> Name {
498 self.parent.variant_data(db).fields()[self.id].name.clone()
499 }
500
501 /// Returns the type as in the signature of the struct (i.e., with
502 /// placeholder types for type parameters). This is good for showing
503 /// signature help, but not so good to actually get the type of the field
504 /// when you actually have a variable of the struct.
505 pub fn signature_ty(&self, db: &dyn HirDatabase) -> Type {
506 let var_id = self.parent.into();
507 let generic_def_id: GenericDefId = match self.parent {
508 VariantDef::Struct(it) => it.id.into(),
509 VariantDef::Union(it) => it.id.into(),
510 VariantDef::Variant(it) => it.parent.id.into(),
511 };
512 let substs = Substs::type_params(db, generic_def_id);
513 let ty = db.field_types(var_id)[self.id].clone().subst(&substs);
514 Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
515 }
516
517 pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
518 self.parent
519 }
520}
521
522impl HasVisibility for Field {
523 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
524 let variant_data = self.parent.variant_data(db);
525 let visibility = &variant_data.fields()[self.id].visibility;
526 let parent_id: hir_def::VariantId = self.parent.into();
527 visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
528 }
529}
530
531#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
532pub struct Struct {
533 pub(crate) id: StructId,
534}
535
536impl Struct {
537 pub fn module(self, db: &dyn HirDatabase) -> Module {
538 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
539 }
540
541 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
542 Some(self.module(db).krate())
543 }
544
545 pub fn name(self, db: &dyn HirDatabase) -> Name {
546 db.struct_data(self.id).name.clone()
547 }
548
549 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
550 db.struct_data(self.id)
551 .variant_data
552 .fields()
553 .iter()
554 .map(|(id, _)| Field { parent: self.into(), id })
555 .collect()
556 }
557
558 pub fn ty(self, db: &dyn HirDatabase) -> Type {
559 Type::from_def(
560 db,
561 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
562 self.id,
563 )
564 }
565
566 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
567 db.struct_data(self.id).repr.clone()
568 }
569
570 pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
571 self.variant_data(db).kind()
572 }
573
574 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
575 db.struct_data(self.id).variant_data.clone()
576 }
577}
578
579#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
580pub struct Union {
581 pub(crate) id: UnionId,
582}
583
584impl Union {
585 pub fn name(self, db: &dyn HirDatabase) -> Name {
586 db.union_data(self.id).name.clone()
587 }
588
589 pub fn module(self, db: &dyn HirDatabase) -> Module {
590 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
591 }
592
593 pub fn ty(self, db: &dyn HirDatabase) -> Type {
594 Type::from_def(
595 db,
596 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
597 self.id,
598 )
599 }
600
601 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
602 db.union_data(self.id)
603 .variant_data
604 .fields()
605 .iter()
606 .map(|(id, _)| Field { parent: self.into(), id })
607 .collect()
608 }
609
610 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
611 db.union_data(self.id).variant_data.clone()
612 }
613}
614
615#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
616pub struct Enum {
617 pub(crate) id: EnumId,
618}
619
620impl Enum {
621 pub fn module(self, db: &dyn HirDatabase) -> Module {
622 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
623 }
624
625 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
626 Some(self.module(db).krate())
627 }
628
629 pub fn name(self, db: &dyn HirDatabase) -> Name {
630 db.enum_data(self.id).name.clone()
631 }
632
633 pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
634 db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
635 }
636
637 pub fn ty(self, db: &dyn HirDatabase) -> Type {
638 Type::from_def(
639 db,
640 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
641 self.id,
642 )
643 }
644}
645
646#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
647pub struct Variant {
648 pub(crate) parent: Enum,
649 pub(crate) id: LocalEnumVariantId,
650}
651
652impl Variant {
653 pub fn module(self, db: &dyn HirDatabase) -> Module {
654 self.parent.module(db)
655 }
656 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
657 self.parent
658 }
659
660 pub fn name(self, db: &dyn HirDatabase) -> Name {
661 db.enum_data(self.parent.id).variants[self.id].name.clone()
662 }
663
664 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
665 self.variant_data(db)
666 .fields()
667 .iter()
668 .map(|(id, _)| Field { parent: self.into(), id })
669 .collect()
670 }
671
672 pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
673 self.variant_data(db).kind()
674 }
675
676 pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
677 db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
678 }
679}
680
681/// A Data Type
682#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
683pub enum Adt {
684 Struct(Struct),
685 Union(Union),
686 Enum(Enum),
687}
688impl_from!(Struct, Union, Enum for Adt);
689
690impl Adt {
691 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
692 let subst = db.generic_defaults(self.into());
693 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
694 }
695
696 /// Turns this ADT into a type. Any type parameters of the ADT will be
697 /// turned into unknown types, which is good for e.g. finding the most
698 /// general set of completions, but will not look very nice when printed.
699 pub fn ty(self, db: &dyn HirDatabase) -> Type {
700 let id = AdtId::from(self);
701 Type::from_def(db, id.module(db.upcast()).krate(), id)
702 }
703
704 pub fn module(self, db: &dyn HirDatabase) -> Module {
705 match self {
706 Adt::Struct(s) => s.module(db),
707 Adt::Union(s) => s.module(db),
708 Adt::Enum(e) => e.module(db),
709 }
710 }
711
712 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
713 Some(self.module(db).krate())
714 }
715
716 pub fn name(self, db: &dyn HirDatabase) -> Name {
717 match self {
718 Adt::Struct(s) => s.name(db),
719 Adt::Union(u) => u.name(db),
720 Adt::Enum(e) => e.name(db),
721 }
722 }
723}
724
725#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
726pub enum VariantDef {
727 Struct(Struct),
728 Union(Union),
729 Variant(Variant),
730}
731impl_from!(Struct, Union, Variant for VariantDef);
732
733impl VariantDef {
734 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
735 match self {
736 VariantDef::Struct(it) => it.fields(db),
737 VariantDef::Union(it) => it.fields(db),
738 VariantDef::Variant(it) => it.fields(db),
739 }
740 }
741
742 pub fn module(self, db: &dyn HirDatabase) -> Module {
743 match self {
744 VariantDef::Struct(it) => it.module(db),
745 VariantDef::Union(it) => it.module(db),
746 VariantDef::Variant(it) => it.module(db),
747 }
748 }
749
750 pub fn name(&self, db: &dyn HirDatabase) -> Name {
751 match self {
752 VariantDef::Struct(s) => s.name(db),
753 VariantDef::Union(u) => u.name(db),
754 VariantDef::Variant(e) => e.name(db),
755 }
756 }
757
758 pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
759 match self {
760 VariantDef::Struct(it) => it.variant_data(db),
761 VariantDef::Union(it) => it.variant_data(db),
762 VariantDef::Variant(it) => it.variant_data(db),
763 }
764 }
765}
766
767/// The defs which have a body.
768#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
769pub enum DefWithBody {
770 Function(Function),
771 Static(Static),
772 Const(Const),
773}
774impl_from!(Function, Const, Static for DefWithBody);
775
776impl DefWithBody {
777 pub fn module(self, db: &dyn HirDatabase) -> Module {
778 match self {
779 DefWithBody::Const(c) => c.module(db),
780 DefWithBody::Function(f) => f.module(db),
781 DefWithBody::Static(s) => s.module(db),
782 }
783 }
784
785 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
786 match self {
787 DefWithBody::Function(f) => Some(f.name(db)),
788 DefWithBody::Static(s) => s.name(db),
789 DefWithBody::Const(c) => c.name(db),
790 }
791 }
792}
793
794#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
795pub struct Function {
796 pub(crate) id: FunctionId,
797}
798
799impl Function {
800 pub fn module(self, db: &dyn HirDatabase) -> Module {
801 self.id.lookup(db.upcast()).module(db.upcast()).into()
802 }
803
804 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
805 Some(self.module(db).krate())
806 }
807
808 pub fn name(self, db: &dyn HirDatabase) -> Name {
809 db.function_data(self.id).name.clone()
810 }
811
812 /// Get this function's return type
813 pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
814 let resolver = self.id.resolver(db.upcast());
815 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
816 let ret_type = &db.function_data(self.id).ret_type;
817 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
818 let ty = Ty::from_hir_ext(&ctx, ret_type).0;
819 Type::new_with_resolver_inner(db, krate, &resolver, ty)
820 }
821
822 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
823 if !db.function_data(self.id).has_self_param {
824 return None;
825 }
826 Some(SelfParam { func: self.id })
827 }
828
829 pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
830 let resolver = self.id.resolver(db.upcast());
831 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
832 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
833 let environment = TraitEnvironment::lower(db, &resolver);
834 db.function_data(self.id)
835 .params
836 .iter()
837 .map(|type_ref| {
838 let ty = Type {
839 krate,
840 ty: InEnvironment {
841 value: Ty::from_hir_ext(&ctx, type_ref).0,
842 environment: environment.clone(),
843 },
844 };
845 Param { ty }
846 })
847 .collect()
848 }
849 pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
850 if self.self_param(db).is_none() {
851 return None;
852 }
853 let mut res = self.assoc_fn_params(db);
854 res.remove(0);
855 Some(res)
856 }
857
858 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
859 db.function_data(self.id).is_unsafe
860 }
861
862 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
863 let krate = self.module(db).id.krate();
864 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink);
865 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
866 hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
867 }
868
869 /// Whether this function declaration has a definition.
870 ///
871 /// This is false in the case of required (not provided) trait methods.
872 pub fn has_body(self, db: &dyn HirDatabase) -> bool {
873 db.function_data(self.id).has_body
874 }
875
876 /// A textual representation of the HIR of this function for debugging purposes.
877 pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
878 let body = db.body(self.id.into());
879
880 let mut result = String::new();
881 format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
882 for (id, expr) in body.exprs.iter() {
883 format_to!(result, "{:?}: {:?}\n", id, expr);
884 }
885
886 result
887 }
888}
889
890// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
891pub enum Access {
892 Shared,
893 Exclusive,
894 Owned,
895}
896
897impl From<hir_ty::Mutability> for Access {
898 fn from(mutability: hir_ty::Mutability) -> Access {
899 match mutability {
900 hir_ty::Mutability::Not => Access::Shared,
901 hir_ty::Mutability::Mut => Access::Exclusive,
902 }
903 }
904}
905
906#[derive(Debug)]
907pub struct Param {
908 ty: Type,
909}
910
911impl Param {
912 pub fn ty(&self) -> &Type {
913 &self.ty
914 }
915}
916
917#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
918pub struct SelfParam {
919 func: FunctionId,
920}
921
922impl SelfParam {
923 pub fn access(self, db: &dyn HirDatabase) -> Access {
924 let func_data = db.function_data(self.func);
925 func_data
926 .params
927 .first()
928 .map(|param| match *param {
929 TypeRef::Reference(.., mutability) => match mutability {
930 hir_def::type_ref::Mutability::Shared => Access::Shared,
931 hir_def::type_ref::Mutability::Mut => Access::Exclusive,
932 },
933 _ => Access::Owned,
934 })
935 .unwrap_or(Access::Owned)
936 }
937}
938
939impl HasVisibility for Function {
940 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
941 let function_data = db.function_data(self.id);
942 let visibility = &function_data.visibility;
943 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
944 }
945}
946
947#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
948pub struct Const {
949 pub(crate) id: ConstId,
950}
951
952impl Const {
953 pub fn module(self, db: &dyn HirDatabase) -> Module {
954 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
955 }
956
957 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
958 Some(self.module(db).krate())
959 }
960
961 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
962 db.const_data(self.id).name.clone()
963 }
964}
965
966impl HasVisibility for Const {
967 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
968 let function_data = db.const_data(self.id);
969 let visibility = &function_data.visibility;
970 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
971 }
972}
973
974#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
975pub struct Static {
976 pub(crate) id: StaticId,
977}
978
979impl Static {
980 pub fn module(self, db: &dyn HirDatabase) -> Module {
981 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
982 }
983
984 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
985 Some(self.module(db).krate())
986 }
987
988 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
989 db.static_data(self.id).name.clone()
990 }
991
992 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
993 db.static_data(self.id).mutable
994 }
995}
996
997#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
998pub struct Trait {
999 pub(crate) id: TraitId,
1000}
1001
1002impl Trait {
1003 pub fn module(self, db: &dyn HirDatabase) -> Module {
1004 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
1005 }
1006
1007 pub fn name(self, db: &dyn HirDatabase) -> Name {
1008 db.trait_data(self.id).name.clone()
1009 }
1010
1011 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
1012 db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
1013 }
1014
1015 pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
1016 db.trait_data(self.id).auto
1017 }
1018}
1019
1020#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1021pub struct TypeAlias {
1022 pub(crate) id: TypeAliasId,
1023}
1024
1025impl TypeAlias {
1026 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
1027 let subst = db.generic_defaults(self.id.into());
1028 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
1029 }
1030
1031 pub fn module(self, db: &dyn HirDatabase) -> Module {
1032 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1033 }
1034
1035 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
1036 Some(self.module(db).krate())
1037 }
1038
1039 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1040 db.type_alias_data(self.id).type_ref.clone()
1041 }
1042
1043 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1044 Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate(), self.id)
1045 }
1046
1047 pub fn name(self, db: &dyn HirDatabase) -> Name {
1048 db.type_alias_data(self.id).name.clone()
1049 }
1050}
1051
1052impl HasVisibility for TypeAlias {
1053 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
1054 let function_data = db.type_alias_data(self.id);
1055 let visibility = &function_data.visibility;
1056 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
1057 }
1058}
1059
1060#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1061pub struct BuiltinType {
1062 pub(crate) inner: hir_def::builtin_type::BuiltinType,
1063}
1064
1065impl BuiltinType {
1066 pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type {
1067 let resolver = module.id.resolver(db.upcast());
1068 Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner))
1069 .expect("crate not present in resolver")
1070 }
1071
1072 pub fn name(self) -> Name {
1073 self.inner.as_name()
1074 }
1075}
1076
1077#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1078pub struct MacroDef {
1079 pub(crate) id: MacroDefId,
1080}
1081
1082impl MacroDef {
1083 /// FIXME: right now, this just returns the root module of the crate that
1084 /// defines this macro. The reasons for this is that macros are expanded
1085 /// early, in `hir_expand`, where modules simply do not exist yet.
1086 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
1087 let krate = self.id.krate;
1088 let def_map = db.crate_def_map(krate);
1089 let module_id = def_map.root();
1090 Some(Module { id: def_map.module_id(module_id) })
1091 }
1092
1093 /// XXX: this parses the file
1094 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1095 self.source(db)?.value.name().map(|it| it.as_name())
1096 }
1097
1098 /// Indicate it is a proc-macro
1099 pub fn is_proc_macro(&self) -> bool {
1100 matches!(self.id.kind, MacroDefKind::ProcMacro(_))
1101 }
1102
1103 /// Indicate it is a derive macro
1104 pub fn is_derive_macro(&self) -> bool {
1105 matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_))
1106 }
1107}
1108
1109/// Invariant: `inner.as_assoc_item(db).is_some()`
1110/// We do not actively enforce this invariant.
1111#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1112pub enum AssocItem {
1113 Function(Function),
1114 Const(Const),
1115 TypeAlias(TypeAlias),
1116}
1117#[derive(Debug)]
1118pub enum AssocItemContainer {
1119 Trait(Trait),
1120 Impl(Impl),
1121}
1122pub trait AsAssocItem {
1123 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
1124}
1125
1126impl AsAssocItem for Function {
1127 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1128 as_assoc_item(db, AssocItem::Function, self.id)
1129 }
1130}
1131impl AsAssocItem for Const {
1132 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1133 as_assoc_item(db, AssocItem::Const, self.id)
1134 }
1135}
1136impl AsAssocItem for TypeAlias {
1137 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1138 as_assoc_item(db, AssocItem::TypeAlias, self.id)
1139 }
1140}
1141impl AsAssocItem for ModuleDef {
1142 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1143 match self {
1144 ModuleDef::Function(it) => it.as_assoc_item(db),
1145 ModuleDef::Const(it) => it.as_assoc_item(db),
1146 ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
1147 _ => None,
1148 }
1149 }
1150}
1151fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
1152where
1153 ID: Lookup<Data = AssocItemLoc<AST>>,
1154 DEF: From<ID>,
1155 CTOR: FnOnce(DEF) -> AssocItem,
1156 AST: ItemTreeNode,
1157{
1158 match id.lookup(db.upcast()).container {
1159 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
1160 AssocContainerId::ContainerId(_) => None,
1161 }
1162}
1163
1164impl AssocItem {
1165 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1166 match self {
1167 AssocItem::Function(it) => Some(it.name(db)),
1168 AssocItem::Const(it) => it.name(db),
1169 AssocItem::TypeAlias(it) => Some(it.name(db)),
1170 }
1171 }
1172 pub fn module(self, db: &dyn HirDatabase) -> Module {
1173 match self {
1174 AssocItem::Function(f) => f.module(db),
1175 AssocItem::Const(c) => c.module(db),
1176 AssocItem::TypeAlias(t) => t.module(db),
1177 }
1178 }
1179 pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
1180 let container = match self {
1181 AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
1182 AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
1183 AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
1184 };
1185 match container {
1186 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
1187 AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
1188 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"),
1189 }
1190 }
1191
1192 pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
1193 match self.container(db) {
1194 AssocItemContainer::Trait(t) => Some(t),
1195 _ => None,
1196 }
1197 }
1198}
1199
1200impl HasVisibility for AssocItem {
1201 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
1202 match self {
1203 AssocItem::Function(f) => f.visibility(db),
1204 AssocItem::Const(c) => c.visibility(db),
1205 AssocItem::TypeAlias(t) => t.visibility(db),
1206 }
1207 }
1208}
1209
1210#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1211pub enum GenericDef {
1212 Function(Function),
1213 Adt(Adt),
1214 Trait(Trait),
1215 TypeAlias(TypeAlias),
1216 Impl(Impl),
1217 // enum variants cannot have generics themselves, but their parent enums
1218 // can, and this makes some code easier to write
1219 Variant(Variant),
1220 // consts can have type parameters from their parents (i.e. associated consts of traits)
1221 Const(Const),
1222}
1223impl_from!(
1224 Function,
1225 Adt(Struct, Enum, Union),
1226 Trait,
1227 TypeAlias,
1228 Impl,
1229 Variant,
1230 Const
1231 for GenericDef
1232);
1233
1234impl GenericDef {
1235 pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
1236 let generics = db.generic_params(self.into());
1237 let ty_params = generics
1238 .types
1239 .iter()
1240 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
1241 .map(GenericParam::TypeParam);
1242 let lt_params = generics
1243 .lifetimes
1244 .iter()
1245 .map(|(local_id, _)| LifetimeParam {
1246 id: LifetimeParamId { parent: self.into(), local_id },
1247 })
1248 .map(GenericParam::LifetimeParam);
1249 let const_params = generics
1250 .consts
1251 .iter()
1252 .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } })
1253 .map(GenericParam::ConstParam);
1254 ty_params.chain(lt_params).chain(const_params).collect()
1255 }
1256
1257 pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
1258 let generics = db.generic_params(self.into());
1259 generics
1260 .types
1261 .iter()
1262 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
1263 .collect()
1264 }
1265}
1266
1267#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1268pub struct Local {
1269 pub(crate) parent: DefWithBodyId,
1270 pub(crate) pat_id: PatId,
1271}
1272
1273impl Local {
1274 pub fn is_param(self, db: &dyn HirDatabase) -> bool {
1275 let src = self.source(db);
1276 match src.value {
1277 Either::Left(bind_pat) => {
1278 bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind()))
1279 }
1280 Either::Right(_self_param) => true,
1281 }
1282 }
1283
1284 // FIXME: why is this an option? It shouldn't be?
1285 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1286 let body = db.body(self.parent.into());
1287 match &body[self.pat_id] {
1288 Pat::Bind { name, .. } => Some(name.clone()),
1289 _ => None,
1290 }
1291 }
1292
1293 pub fn is_self(self, db: &dyn HirDatabase) -> bool {
1294 self.name(db) == Some(name![self])
1295 }
1296
1297 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
1298 let body = db.body(self.parent.into());
1299 match &body[self.pat_id] {
1300 Pat::Bind { mode, .. } => match mode {
1301 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
1302 _ => false,
1303 },
1304 _ => false,
1305 }
1306 }
1307
1308 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
1309 self.parent.into()
1310 }
1311
1312 pub fn module(self, db: &dyn HirDatabase) -> Module {
1313 self.parent(db).module(db)
1314 }
1315
1316 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1317 let def = DefWithBodyId::from(self.parent);
1318 let infer = db.infer(def);
1319 let ty = infer[self.pat_id].clone();
1320 let krate = def.module(db.upcast()).krate();
1321 Type::new(db, krate, def, ty)
1322 }
1323
1324 pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> {
1325 let (_body, source_map) = db.body_with_source_map(self.parent.into());
1326 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
1327 let root = src.file_syntax(db.upcast());
1328 src.map(|ast| {
1329 ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root))
1330 })
1331 }
1332}
1333
1334#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1335pub struct Label {
1336 pub(crate) parent: DefWithBodyId,
1337 pub(crate) label_id: LabelId,
1338}
1339
1340impl Label {
1341 pub fn module(self, db: &dyn HirDatabase) -> Module {
1342 self.parent(db).module(db)
1343 }
1344
1345 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
1346 self.parent.into()
1347 }
1348
1349 pub fn name(self, db: &dyn HirDatabase) -> Name {
1350 let body = db.body(self.parent.into());
1351 body[self.label_id].name.clone()
1352 }
1353
1354 pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
1355 let (_body, source_map) = db.body_with_source_map(self.parent.into());
1356 let src = source_map.label_syntax(self.label_id);
1357 let root = src.file_syntax(db.upcast());
1358 src.map(|ast| ast.to_node(&root))
1359 }
1360}
1361
1362#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1363pub enum GenericParam {
1364 TypeParam(TypeParam),
1365 LifetimeParam(LifetimeParam),
1366 ConstParam(ConstParam),
1367}
1368impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
1369
1370impl GenericParam {
1371 pub fn module(self, db: &dyn HirDatabase) -> Module {
1372 match self {
1373 GenericParam::TypeParam(it) => it.module(db),
1374 GenericParam::LifetimeParam(it) => it.module(db),
1375 GenericParam::ConstParam(it) => it.module(db),
1376 }
1377 }
1378
1379 pub fn name(self, db: &dyn HirDatabase) -> Name {
1380 match self {
1381 GenericParam::TypeParam(it) => it.name(db),
1382 GenericParam::LifetimeParam(it) => it.name(db),
1383 GenericParam::ConstParam(it) => it.name(db),
1384 }
1385 }
1386}
1387
1388#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1389pub struct TypeParam {
1390 pub(crate) id: TypeParamId,
1391}
1392
1393impl TypeParam {
1394 pub fn name(self, db: &dyn HirDatabase) -> Name {
1395 let params = db.generic_params(self.id.parent);
1396 params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
1397 }
1398
1399 pub fn module(self, db: &dyn HirDatabase) -> Module {
1400 self.id.parent.module(db.upcast()).into()
1401 }
1402
1403 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1404 let resolver = self.id.parent.resolver(db.upcast());
1405 let krate = self.id.parent.module(db.upcast()).krate();
1406 let ty = Ty::Placeholder(self.id);
1407 Type::new_with_resolver_inner(db, krate, &resolver, ty)
1408 }
1409
1410 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
1411 db.generic_predicates_for_param(self.id)
1412 .into_iter()
1413 .filter_map(|pred| match &pred.value {
1414 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1415 Some(Trait::from(trait_ref.trait_))
1416 }
1417 _ => None,
1418 })
1419 .collect()
1420 }
1421
1422 pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
1423 let params = db.generic_defaults(self.id.parent);
1424 let local_idx = hir_ty::param_idx(db, self.id)?;
1425 let resolver = self.id.parent.resolver(db.upcast());
1426 let krate = self.id.parent.module(db.upcast()).krate();
1427 let ty = params.get(local_idx)?.clone();
1428 let subst = Substs::type_params(db, self.id.parent);
1429 let ty = ty.subst(&subst.prefix(local_idx));
1430 Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
1431 }
1432}
1433
1434impl HirDisplay for TypeParam {
1435 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1436 write!(f, "{}", self.name(f.db))?;
1437 let bounds = f.db.generic_predicates_for_param(self.id);
1438 let substs = Substs::type_params(f.db, self.id.parent);
1439 let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
1440 if !(predicates.is_empty() || f.omit_verbose_types()) {
1441 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
1442 }
1443 Ok(())
1444 }
1445}
1446
1447#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1448pub struct LifetimeParam {
1449 pub(crate) id: LifetimeParamId,
1450}
1451
1452impl LifetimeParam {
1453 pub fn name(self, db: &dyn HirDatabase) -> Name {
1454 let params = db.generic_params(self.id.parent);
1455 params.lifetimes[self.id.local_id].name.clone()
1456 }
1457
1458 pub fn module(self, db: &dyn HirDatabase) -> Module {
1459 self.id.parent.module(db.upcast()).into()
1460 }
1461
1462 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
1463 self.id.parent.into()
1464 }
1465}
1466
1467#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1468pub struct ConstParam {
1469 pub(crate) id: ConstParamId,
1470}
1471
1472impl ConstParam {
1473 pub fn name(self, db: &dyn HirDatabase) -> Name {
1474 let params = db.generic_params(self.id.parent);
1475 params.consts[self.id.local_id].name.clone()
1476 }
1477
1478 pub fn module(self, db: &dyn HirDatabase) -> Module {
1479 self.id.parent.module(db.upcast()).into()
1480 }
1481
1482 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
1483 self.id.parent.into()
1484 }
1485
1486 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1487 let def = self.id.parent;
1488 let krate = def.module(db.upcast()).krate();
1489 Type::new(db, krate, def, db.const_param_ty(self.id))
1490 }
1491}
1492
1493#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1494pub struct Impl {
1495 pub(crate) id: ImplId,
1496}
1497
1498impl Impl {
1499 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
1500 let inherent = db.inherent_impls_in_crate(krate.id);
1501 let trait_ = db.trait_impls_in_crate(krate.id);
1502
1503 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1504 }
1505 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> {
1506 let impls = db.trait_impls_in_crate(krate.id);
1507 impls.for_trait(trait_.id).map(Self::from).collect()
1508 }
1509
1510 // FIXME: the return type is wrong. This should be a hir version of
1511 // `TraitRef` (ie, resolved `TypeRef`).
1512 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1513 db.impl_data(self.id).target_trait.clone()
1514 }
1515
1516 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1517 let impl_data = db.impl_data(self.id);
1518 let resolver = self.id.resolver(db.upcast());
1519 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
1520 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
1521 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
1522 Type::new_with_resolver_inner(db, krate, &resolver, ty)
1523 }
1524
1525 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
1526 db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
1527 }
1528
1529 pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
1530 db.impl_data(self.id).is_negative
1531 }
1532
1533 pub fn module(self, db: &dyn HirDatabase) -> Module {
1534 self.id.lookup(db.upcast()).container.module(db.upcast()).into()
1535 }
1536
1537 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1538 Crate { id: self.module(db).id.krate() }
1539 }
1540
1541 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1542 let src = self.source(db)?;
1543 let item = src.file_id.is_builtin_derive(db.upcast())?;
1544 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
1545
1546 // FIXME: handle `cfg_attr`
1547 let attr = item
1548 .value
1549 .attrs()
1550 .filter_map(|it| {
1551 let path = ModPath::from_src(it.path()?, &hygenic)?;
1552 if path.as_ident()?.to_string() == "derive" {
1553 Some(it)
1554 } else {
1555 None
1556 }
1557 })
1558 .last()?;
1559
1560 Some(item.with_value(attr))
1561 }
1562}
1563
1564#[derive(Clone, PartialEq, Eq, Debug)]
1565pub struct Type {
1566 krate: CrateId,
1567 ty: InEnvironment<Ty>,
1568}
1569
1570impl Type {
1571 pub(crate) fn new_with_resolver(
1572 db: &dyn HirDatabase,
1573 resolver: &Resolver,
1574 ty: Ty,
1575 ) -> Option<Type> {
1576 let krate = resolver.krate()?;
1577 Some(Type::new_with_resolver_inner(db, krate, resolver, ty))
1578 }
1579 pub(crate) fn new_with_resolver_inner(
1580 db: &dyn HirDatabase,
1581 krate: CrateId,
1582 resolver: &Resolver,
1583 ty: Ty,
1584 ) -> Type {
1585 let environment = TraitEnvironment::lower(db, &resolver);
1586 Type { krate, ty: InEnvironment { value: ty, environment } }
1587 }
1588
1589 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1590 let resolver = lexical_env.resolver(db.upcast());
1591 let environment = TraitEnvironment::lower(db, &resolver);
1592 Type { krate, ty: InEnvironment { value: ty, environment } }
1593 }
1594
1595 fn from_def(
1596 db: &dyn HirDatabase,
1597 krate: CrateId,
1598 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
1599 ) -> Type {
1600 let substs = Substs::build_for_def(db, def).fill_with_unknown().build();
1601 let ty = db.ty(def.into()).subst(&substs);
1602 Type::new(db, krate, def, ty)
1603 }
1604
1605 pub fn is_unit(&self) -> bool {
1606 matches!(self.ty.value, Ty::Tuple(0, ..))
1607 }
1608 pub fn is_bool(&self) -> bool {
1609 matches!(self.ty.value, Ty::Scalar(Scalar::Bool))
1610 }
1611
1612 pub fn is_mutable_reference(&self) -> bool {
1613 matches!(self.ty.value, Ty::Ref(hir_ty::Mutability::Mut, ..))
1614 }
1615
1616 pub fn remove_ref(&self) -> Option<Type> {
1617 if let Ty::Ref(.., substs) = &self.ty.value {
1618 Some(self.derived(substs[0].clone()))
1619 } else {
1620 None
1621 }
1622 }
1623
1624 pub fn is_unknown(&self) -> bool {
1625 matches!(self.ty.value, Ty::Unknown)
1626 }
1627
1628 /// Checks that particular type `ty` implements `std::future::Future`.
1629 /// This function is used in `.await` syntax completion.
1630 pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
1631 // No special case for the type of async block, since Chalk can figure it out.
1632
1633 let krate = self.krate;
1634
1635 let std_future_trait =
1636 db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait());
1637 let std_future_trait = match std_future_trait {
1638 Some(it) => it,
1639 None => return false,
1640 };
1641
1642 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1643 method_resolution::implements_trait(
1644 &canonical_ty,
1645 db,
1646 self.ty.environment.clone(),
1647 krate,
1648 std_future_trait,
1649 )
1650 }
1651
1652 /// Checks that particular type `ty` implements `std::ops::FnOnce`.
1653 ///
1654 /// This function can be used to check if a particular type is callable, since FnOnce is a
1655 /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
1656 pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
1657 let krate = self.krate;
1658
1659 let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) {
1660 Some(it) => it,
1661 None => return false,
1662 };
1663
1664 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1665 method_resolution::implements_trait_unique(
1666 &canonical_ty,
1667 db,
1668 self.ty.environment.clone(),
1669 krate,
1670 fnonce_trait,
1671 )
1672 }
1673
1674 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1675 let trait_ref = hir_ty::TraitRef {
1676 trait_: trait_.id,
1677 substs: Substs::build_for_def(db, trait_.id)
1678 .push(self.ty.value.clone())
1679 .fill(args.iter().map(|t| t.ty.value.clone()))
1680 .build(),
1681 };
1682
1683 let goal = Canonical {
1684 value: hir_ty::InEnvironment::new(
1685 self.ty.environment.clone(),
1686 hir_ty::Obligation::Trait(trait_ref),
1687 ),
1688 kinds: Arc::new([]),
1689 };
1690
1691 db.trait_solve(self.krate, goal).is_some()
1692 }
1693
1694 pub fn normalize_trait_assoc_type(
1695 &self,
1696 db: &dyn HirDatabase,
1697 trait_: Trait,
1698 args: &[Type],
1699 alias: TypeAlias,
1700 ) -> Option<Type> {
1701 let subst = Substs::build_for_def(db, trait_.id)
1702 .push(self.ty.value.clone())
1703 .fill(args.iter().map(|t| t.ty.value.clone()))
1704 .build();
1705 let predicate = ProjectionPredicate {
1706 projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst },
1707 ty: Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)),
1708 };
1709 let goal = Canonical {
1710 value: InEnvironment::new(
1711 self.ty.environment.clone(),
1712 Obligation::Projection(predicate),
1713 ),
1714 kinds: Arc::new([TyVariableKind::General]),
1715 };
1716
1717 match db.trait_solve(self.krate, goal)? {
1718 Solution::Unique(SolutionVariables(subst)) => {
1719 subst.value.first().map(|ty| self.derived(ty.clone()))
1720 }
1721 Solution::Ambig(_) => None,
1722 }
1723 }
1724
1725 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
1726 let lang_item = db.lang_item(self.krate, SmolStr::new("copy"));
1727 let copy_trait = match lang_item {
1728 Some(LangItemTarget::TraitId(it)) => it,
1729 _ => return false,
1730 };
1731 self.impls_trait(db, copy_trait.into(), &[])
1732 }
1733
1734 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1735 let def = match self.ty.value {
1736 Ty::FnDef(def, _) => Some(def),
1737 _ => None,
1738 };
1739
1740 let sig = self.ty.value.callable_sig(db)?;
1741 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
1742 }
1743
1744 pub fn is_closure(&self) -> bool {
1745 matches!(&self.ty.value, Ty::Closure { .. })
1746 }
1747
1748 pub fn is_fn(&self) -> bool {
1749 matches!(&self.ty.value, Ty::FnDef(..) | Ty::Function { .. })
1750 }
1751
1752 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1753 let adt_id = match self.ty.value {
1754 Ty::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
1755 _ => return false,
1756 };
1757
1758 let adt = adt_id.into();
1759 match adt {
1760 Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
1761 _ => false,
1762 }
1763 }
1764
1765 pub fn is_raw_ptr(&self) -> bool {
1766 matches!(&self.ty.value, Ty::Raw(..))
1767 }
1768
1769 pub fn contains_unknown(&self) -> bool {
1770 return go(&self.ty.value);
1771
1772 fn go(ty: &Ty) -> bool {
1773 match ty {
1774 Ty::Unknown => true,
1775 _ => ty.substs().map_or(false, |substs| substs.iter().any(go)),
1776 }
1777 }
1778 }
1779
1780 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1781 let (variant_id, substs) = match self.ty.value {
1782 Ty::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs),
1783 Ty::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs),
1784 _ => return Vec::new(),
1785 };
1786
1787 db.field_types(variant_id)
1788 .iter()
1789 .map(|(local_id, ty)| {
1790 let def = Field { parent: variant_id.into(), id: local_id };
1791 let ty = ty.clone().subst(substs);
1792 (def, self.derived(ty))
1793 })
1794 .collect()
1795 }
1796
1797 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
1798 if let Ty::Tuple(_, substs) = &self.ty.value {
1799 substs.iter().map(|ty| self.derived(ty.clone())).collect()
1800 } else {
1801 Vec::new()
1802 }
1803 }
1804
1805 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1806 // There should be no inference vars in types passed here
1807 // FIXME check that?
1808 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1809 let environment = self.ty.environment.clone();
1810 let ty = InEnvironment { value: canonical, environment };
1811 autoderef(db, Some(self.krate), ty)
1812 .map(|canonical| canonical.value)
1813 .map(move |ty| self.derived(ty))
1814 }
1815
1816 // This would be nicer if it just returned an iterator, but that runs into
1817 // lifetime problems, because we need to borrow temp `CrateImplDefs`.
1818 pub fn iterate_assoc_items<T>(
1819 self,
1820 db: &dyn HirDatabase,
1821 krate: Crate,
1822 mut callback: impl FnMut(AssocItem) -> Option<T>,
1823 ) -> Option<T> {
1824 for krate in self.ty.value.def_crates(db, krate.id)? {
1825 let impls = db.inherent_impls_in_crate(krate);
1826
1827 for impl_def in impls.for_self_ty(&self.ty.value) {
1828 for &item in db.impl_data(*impl_def).items.iter() {
1829 if let Some(result) = callback(item.into()) {
1830 return Some(result);
1831 }
1832 }
1833 }
1834 }
1835 None
1836 }
1837
1838 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ {
1839 self.ty
1840 .value
1841 .strip_references()
1842 .substs()
1843 .into_iter()
1844 .flat_map(|substs| substs.iter())
1845 .map(move |ty| self.derived(ty.clone()))
1846 }
1847
1848 pub fn iterate_method_candidates<T>(
1849 &self,
1850 db: &dyn HirDatabase,
1851 krate: Crate,
1852 traits_in_scope: &FxHashSet<TraitId>,
1853 name: Option<&Name>,
1854 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
1855 ) -> Option<T> {
1856 // There should be no inference vars in types passed here
1857 // FIXME check that?
1858 // FIXME replace Unknown by bound vars here
1859 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1860
1861 let env = self.ty.environment.clone();
1862 let krate = krate.id;
1863
1864 method_resolution::iterate_method_candidates(
1865 &canonical,
1866 db,
1867 env,
1868 krate,
1869 traits_in_scope,
1870 name,
1871 method_resolution::LookupMode::MethodCall,
1872 |ty, it| match it {
1873 AssocItemId::FunctionId(f) => callback(ty, f.into()),
1874 _ => None,
1875 },
1876 )
1877 }
1878
1879 pub fn iterate_path_candidates<T>(
1880 &self,
1881 db: &dyn HirDatabase,
1882 krate: Crate,
1883 traits_in_scope: &FxHashSet<TraitId>,
1884 name: Option<&Name>,
1885 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
1886 ) -> Option<T> {
1887 // There should be no inference vars in types passed here
1888 // FIXME check that?
1889 // FIXME replace Unknown by bound vars here
1890 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1891
1892 let env = self.ty.environment.clone();
1893 let krate = krate.id;
1894
1895 method_resolution::iterate_method_candidates(
1896 &canonical,
1897 db,
1898 env,
1899 krate,
1900 traits_in_scope,
1901 name,
1902 method_resolution::LookupMode::Path,
1903 |ty, it| callback(ty, it.into()),
1904 )
1905 }
1906
1907 pub fn as_adt(&self) -> Option<Adt> {
1908 let (adt, _subst) = self.ty.value.as_adt()?;
1909 Some(adt.into())
1910 }
1911
1912 pub fn as_dyn_trait(&self) -> Option<Trait> {
1913 self.ty.value.dyn_trait().map(Into::into)
1914 }
1915
1916 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
1917 self.ty.value.impl_trait_bounds(db).map(|it| {
1918 it.into_iter()
1919 .filter_map(|pred| match pred {
1920 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1921 Some(Trait::from(trait_ref.trait_))
1922 }
1923 _ => None,
1924 })
1925 .collect()
1926 })
1927 }
1928
1929 pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1930 self.ty.value.associated_type_parent_trait(db).map(Into::into)
1931 }
1932
1933 // FIXME: provide required accessors such that it becomes implementable from outside.
1934 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1935 let rref = other.remove_ref();
1936 self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value))
1937 }
1938
1939 fn derived(&self, ty: Ty) -> Type {
1940 Type {
1941 krate: self.krate,
1942 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1943 }
1944 }
1945
1946 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1947 // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
1948 // We need a different order here.
1949
1950 fn walk_substs(
1951 db: &dyn HirDatabase,
1952 type_: &Type,
1953 substs: &Substs,
1954 cb: &mut impl FnMut(Type),
1955 ) {
1956 for ty in substs.iter() {
1957 walk_type(db, &type_.derived(ty.clone()), cb);
1958 }
1959 }
1960
1961 fn walk_bounds(
1962 db: &dyn HirDatabase,
1963 type_: &Type,
1964 bounds: &[GenericPredicate],
1965 cb: &mut impl FnMut(Type),
1966 ) {
1967 for pred in bounds {
1968 match pred {
1969 GenericPredicate::Implemented(trait_ref) => {
1970 cb(type_.clone());
1971 walk_substs(db, type_, &trait_ref.substs, cb);
1972 }
1973 _ => (),
1974 }
1975 }
1976 }
1977
1978 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
1979 let ty = type_.ty.value.strip_references();
1980 match ty {
1981 Ty::Adt(..) => {
1982 cb(type_.derived(ty.clone()));
1983 }
1984 Ty::AssociatedType(..) => {
1985 if let Some(_) = ty.associated_type_parent_trait(db) {
1986 cb(type_.derived(ty.clone()));
1987 }
1988 }
1989 Ty::OpaqueType(..) => {
1990 if let Some(bounds) = ty.impl_trait_bounds(db) {
1991 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1992 }
1993 }
1994 Ty::Alias(AliasTy::Opaque(opaque_ty)) => {
1995 if let Some(bounds) = ty.impl_trait_bounds(db) {
1996 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1997 }
1998
1999 walk_substs(db, type_, &opaque_ty.parameters, cb);
2000 }
2001 Ty::Placeholder(_) => {
2002 if let Some(bounds) = ty.impl_trait_bounds(db) {
2003 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
2004 }
2005 }
2006 Ty::Dyn(bounds) => {
2007 walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb);
2008 }
2009
2010 _ => {}
2011 }
2012 if let Some(substs) = ty.substs() {
2013 walk_substs(db, type_, &substs, cb);
2014 }
2015 }
2016
2017 walk_type(db, self, &mut cb);
2018 }
2019}
2020
2021impl HirDisplay for Type {
2022 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
2023 self.ty.value.hir_fmt(f)
2024 }
2025}
2026
2027// FIXME: closures
2028#[derive(Debug)]
2029pub struct Callable {
2030 ty: Type,
2031 sig: CallableSig,
2032 def: Option<CallableDefId>,
2033 pub(crate) is_bound_method: bool,
2034}
2035
2036pub enum CallableKind {
2037 Function(Function),
2038 TupleStruct(Struct),
2039 TupleEnumVariant(Variant),
2040 Closure,
2041}
2042
2043impl Callable {
2044 pub fn kind(&self) -> CallableKind {
2045 match self.def {
2046 Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
2047 Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
2048 Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
2049 None => CallableKind::Closure,
2050 }
2051 }
2052 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
2053 let func = match self.def {
2054 Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
2055 _ => return None,
2056 };
2057 let src = func.lookup(db.upcast()).source(db.upcast());
2058 let param_list = src.value.param_list()?;
2059 param_list.self_param()
2060 }
2061 pub fn n_params(&self) -> usize {
2062 self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
2063 }
2064 pub fn params(
2065 &self,
2066 db: &dyn HirDatabase,
2067 ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
2068 let types = self
2069 .sig
2070 .params()
2071 .iter()
2072 .skip(if self.is_bound_method { 1 } else { 0 })
2073 .map(|ty| self.ty.derived(ty.clone()));
2074 let patterns = match self.def {
2075 Some(CallableDefId::FunctionId(func)) => {
2076 let src = func.lookup(db.upcast()).source(db.upcast());
2077 src.value.param_list().map(|param_list| {
2078 param_list
2079 .self_param()
2080 .map(|it| Some(Either::Left(it)))
2081 .filter(|_| !self.is_bound_method)
2082 .into_iter()
2083 .chain(param_list.params().map(|it| it.pat().map(Either::Right)))
2084 })
2085 }
2086 _ => None,
2087 };
2088 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
2089 }
2090 pub fn return_type(&self) -> Type {
2091 self.ty.derived(self.sig.ret().clone())
2092 }
2093}
2094
2095/// For IDE only
2096#[derive(Debug, PartialEq, Eq, Hash)]
2097pub enum ScopeDef {
2098 ModuleDef(ModuleDef),
2099 MacroDef(MacroDef),
2100 GenericParam(GenericParam),
2101 ImplSelfType(Impl),
2102 AdtSelfType(Adt),
2103 Local(Local),
2104 Unknown,
2105}
2106
2107impl ScopeDef {
2108 pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> {
2109 let mut items = ArrayVec::new();
2110
2111 match (def.take_types(), def.take_values()) {
2112 (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
2113 (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
2114 (Some(m1), Some(m2)) => {
2115 // Some items, like unit structs and enum variants, are
2116 // returned as both a type and a value. Here we want
2117 // to de-duplicate them.
2118 if m1 != m2 {
2119 items.push(ScopeDef::ModuleDef(m1.into()));
2120 items.push(ScopeDef::ModuleDef(m2.into()));
2121 } else {
2122 items.push(ScopeDef::ModuleDef(m1.into()));
2123 }
2124 }
2125 (None, None) => {}
2126 };
2127
2128 if let Some(macro_def_id) = def.take_macros() {
2129 items.push(ScopeDef::MacroDef(macro_def_id.into()));
2130 }
2131
2132 if items.is_empty() {
2133 items.push(ScopeDef::Unknown);
2134 }
2135
2136 items
2137 }
2138}
2139
2140impl From<ItemInNs> for ScopeDef {
2141 fn from(item: ItemInNs) -> Self {
2142 match item {
2143 ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
2144 ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
2145 ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
2146 }
2147 }
2148}
2149
2150pub trait HasVisibility {
2151 fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
2152 fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
2153 let vis = self.visibility(db);
2154 vis.is_visible_from(db.upcast(), module.id)
2155 }
2156}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 144851f83..945638cc5 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -20,12 +20,11 @@ use syntax::{
20}; 20};
21 21
22use crate::{ 22use crate::{
23 code_model::Access,
24 db::HirDatabase, 23 db::HirDatabase,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 24 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 25 source_analyzer::{resolve_hir_path, SourceAnalyzer},
27 AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label, 26 Access, AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile,
28 LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, 27 Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type,
29 TypeAlias, TypeParam, VariantDef, 28 TypeAlias, TypeParam, VariantDef,
30}; 29};
31 30
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 64ce4add1..d546512cb 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -28,9 +28,8 @@ use syntax::{
28}; 28};
29 29
30use crate::{ 30use crate::{
31 code_model::BuiltinType, db::HirDatabase, semantics::PathResolution, Adt, Const, Field, 31 db::HirDatabase, semantics::PathResolution, Adt, BuiltinType, Const, Field, Function, Local,
32 Function, Local, MacroDef, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, 32 MacroDef, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Variant,
33 Variant,
34}; 33};
35use base_db::CrateId; 34use base_db::CrateId;
36 35
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 535221294..2f07b6d01 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1"
13log = "0.4.8" 14log = "0.4.8"
14once_cell = "1.3.1" 15once_cell = "1.3.1"
15rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 24ffa6c3a..b716d5f6e 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -13,7 +13,6 @@ use syntax::{
13 ast::{self, AstNode, AttrsOwner}, 13 ast::{self, AstNode, AttrsOwner},
14 match_ast, AstToken, SmolStr, SyntaxNode, 14 match_ast, AstToken, SmolStr, SyntaxNode,
15}; 15};
16use test_utils::mark;
17use tt::Subtree; 16use tt::Subtree;
18 17
19use crate::{ 18use crate::{
@@ -177,7 +176,7 @@ impl RawAttrs {
177 if cfg_options.check(&cfg) == Some(false) { 176 if cfg_options.check(&cfg) == Some(false) {
178 None 177 None
179 } else { 178 } else {
180 mark::hit!(cfg_attr_active); 179 cov_mark::hit!(cfg_attr_active);
181 180
182 let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?; 181 let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?;
183 let hygiene = Hygiene::new_unhygienic(); // FIXME 182 let hygiene = Hygiene::new_unhygienic(); // FIXME
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 16e1bac40..b1a3fe1cb 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -20,7 +20,6 @@ use la_arena::{Arena, ArenaMap};
20use profile::Count; 20use profile::Count;
21use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 22use syntax::{ast, AstNode, AstPtr};
23use test_utils::mark;
24 23
25pub(crate) use lower::LowerCtx; 24pub(crate) use lower::LowerCtx;
26 25
@@ -105,7 +104,7 @@ impl Expander {
105 macro_call: ast::MacroCall, 104 macro_call: ast::MacroCall,
106 ) -> ExpandResult<Option<(Mark, T)>> { 105 ) -> ExpandResult<Option<(Mark, T)>> {
107 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT { 106 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
108 mark::hit!(your_stack_belongs_to_me); 107 cov_mark::hit!(your_stack_belongs_to_me);
109 return ExpandResult::str_err("reached recursion limit during macro expansion".into()); 108 return ExpandResult::str_err("reached recursion limit during macro expansion".into());
110 } 109 }
111 110
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 40beb2f7a..d4abe819d 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -19,7 +19,6 @@ use syntax::{
19 }, 19 },
20 AstNode, AstPtr, SyntaxNodePtr, 20 AstNode, AstPtr, SyntaxNodePtr,
21}; 21};
22use test_utils::mark;
23 22
24use crate::{ 23use crate::{
25 adt::StructKind, 24 adt::StructKind,
@@ -286,7 +285,7 @@ impl ExprCollector<'_> {
286 None => self.collect_expr_opt(condition.expr()), 285 None => self.collect_expr_opt(condition.expr()),
287 // if let -- desugar to match 286 // if let -- desugar to match
288 Some(pat) => { 287 Some(pat) => {
289 mark::hit!(infer_resolve_while_let); 288 cov_mark::hit!(infer_resolve_while_let);
290 let pat = self.collect_pat(pat); 289 let pat = self.collect_pat(pat);
291 let match_expr = self.collect_expr_opt(condition.expr()); 290 let match_expr = self.collect_expr_opt(condition.expr());
292 let placeholder_pat = self.missing_pat(); 291 let placeholder_pat = self.missing_pat();
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs
index 210b4a617..1bbb54fc6 100644
--- a/crates/hir_def/src/body/scope.rs
+++ b/crates/hir_def/src/body/scope.rs
@@ -186,7 +186,7 @@ mod tests {
186 use base_db::{fixture::WithFixture, FileId, SourceDatabase}; 186 use base_db::{fixture::WithFixture, FileId, SourceDatabase};
187 use hir_expand::{name::AsName, InFile}; 187 use hir_expand::{name::AsName, InFile};
188 use syntax::{algo::find_node_at_offset, ast, AstNode}; 188 use syntax::{algo::find_node_at_offset, ast, AstNode};
189 use test_utils::{assert_eq_text, extract_offset, mark}; 189 use test_utils::{assert_eq_text, extract_offset};
190 190
191 use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; 191 use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId};
192 192
@@ -454,7 +454,7 @@ fn foo() {
454 454
455 #[test] 455 #[test]
456 fn while_let_desugaring() { 456 fn while_let_desugaring() {
457 mark::check!(infer_resolve_while_let); 457 cov_mark::check!(infer_resolve_while_let);
458 do_check_local_name( 458 do_check_local_name(
459 r#" 459 r#"
460fn test() { 460fn test() {
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index bb43569d7..991a32b15 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -2,7 +2,6 @@ mod block;
2 2
3use base_db::{fixture::WithFixture, SourceDatabase}; 3use base_db::{fixture::WithFixture, SourceDatabase};
4use expect_test::Expect; 4use expect_test::Expect;
5use test_utils::mark;
6 5
7use crate::{test_db::TestDB, ModuleDefId}; 6use crate::{test_db::TestDB, ModuleDefId};
8 7
@@ -48,7 +47,7 @@ fn check_at(ra_fixture: &str, expect: Expect) {
48 47
49#[test] 48#[test]
50fn your_stack_belongs_to_me() { 49fn your_stack_belongs_to_me() {
51 mark::check!(your_stack_belongs_to_me); 50 cov_mark::check!(your_stack_belongs_to_me);
52 lower( 51 lower(
53 " 52 "
54macro_rules! n_nuple { 53macro_rules! n_nuple {
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
index 8bca72a17..3b6ba4cde 100644
--- a/crates/hir_def/src/body/tests/block.rs
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -165,16 +165,16 @@ fn macro_resolve() {
165 check_at( 165 check_at(
166 r#" 166 r#"
167//- /lib.rs crate:lib deps:core 167//- /lib.rs crate:lib deps:core
168use core::mark; 168use core::cov_mark;
169 169
170fn f() { 170fn f() {
171 fn nested() { 171 fn nested() {
172 mark::hit!(Hit); 172 cov_mark::hit!(Hit);
173 $0 173 $0
174 } 174 }
175} 175}
176//- /core.rs crate:core 176//- /core.rs crate:core
177pub mod mark { 177pub mod cov_mark {
178 #[macro_export] 178 #[macro_export]
179 macro_rules! _hit { 179 macro_rules! _hit {
180 ($name:ident) => { 180 ($name:ident) => {
@@ -193,8 +193,8 @@ pub mod mark {
193 nested: v 193 nested: v
194 194
195 crate 195 crate
196 cov_mark: t
196 f: v 197 f: v
197 mark: t
198 "#]], 198 "#]],
199 ); 199 );
200} 200}
@@ -264,7 +264,7 @@ fn main() {
264fn underscore_import() { 264fn underscore_import() {
265 // This used to panic, because the default (private) visibility inside block expressions would 265 // This used to panic, because the default (private) visibility inside block expressions would
266 // point into the containing `DefMap`, which visibilities should never be able to do. 266 // point into the containing `DefMap`, which visibilities should never be able to do.
267 mark::check!(adjust_vis_in_block_def_map); 267 cov_mark::check!(adjust_vis_in_block_def_map);
268 check_at( 268 check_at(
269 r#" 269 r#"
270mod m { 270mod m {
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 3a98ffbaa..de08e2737 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -4,7 +4,6 @@ use std::iter;
4 4
5use hir_expand::name::{known, AsName, Name}; 5use hir_expand::name::{known, AsName, Name};
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7use test_utils::mark;
8 7
9use crate::nameres::DefMap; 8use crate::nameres::DefMap;
10use crate::{ 9use crate::{
@@ -215,7 +214,7 @@ fn find_path_inner(
215 best_path_len - 1, 214 best_path_len - 1,
216 prefixed, 215 prefixed,
217 )?; 216 )?;
218 mark::hit!(partially_imported); 217 cov_mark::hit!(partially_imported);
219 path.push_segment(info.path.segments.last().unwrap().clone()); 218 path.push_segment(info.path.segments.last().unwrap().clone());
220 Some(path) 219 Some(path)
221 }) 220 })
@@ -235,7 +234,7 @@ fn find_path_inner(
235 // that correctly (FIXME). 234 // that correctly (FIXME).
236 if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) { 235 if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
237 if item_module.def_map(db).block_id().is_some() && prefixed.is_some() { 236 if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
238 mark::hit!(prefixed_in_block_expression); 237 cov_mark::hit!(prefixed_in_block_expression);
239 prefixed = Some(PrefixKind::Plain); 238 prefixed = Some(PrefixKind::Plain);
240 } 239 }
241 } 240 }
@@ -252,18 +251,18 @@ fn find_path_inner(
252fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { 251fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
253 if old_path.starts_with_std() && new_path.can_start_with_std() { 252 if old_path.starts_with_std() && new_path.can_start_with_std() {
254 if prefer_no_std { 253 if prefer_no_std {
255 mark::hit!(prefer_no_std_paths); 254 cov_mark::hit!(prefer_no_std_paths);
256 new_path 255 new_path
257 } else { 256 } else {
258 mark::hit!(prefer_std_paths); 257 cov_mark::hit!(prefer_std_paths);
259 old_path 258 old_path
260 } 259 }
261 } else if new_path.starts_with_std() && old_path.can_start_with_std() { 260 } else if new_path.starts_with_std() && old_path.can_start_with_std() {
262 if prefer_no_std { 261 if prefer_no_std {
263 mark::hit!(prefer_no_std_paths); 262 cov_mark::hit!(prefer_no_std_paths);
264 old_path 263 old_path
265 } else { 264 } else {
266 mark::hit!(prefer_std_paths); 265 cov_mark::hit!(prefer_std_paths);
267 new_path 266 new_path
268 } 267 }
269 } else if new_path.len() < old_path.len() { 268 } else if new_path.len() < old_path.len() {
@@ -364,7 +363,6 @@ mod tests {
364 use base_db::fixture::WithFixture; 363 use base_db::fixture::WithFixture;
365 use hir_expand::hygiene::Hygiene; 364 use hir_expand::hygiene::Hygiene;
366 use syntax::ast::AstNode; 365 use syntax::ast::AstNode;
367 use test_utils::mark;
368 366
369 use crate::test_db::TestDB; 367 use crate::test_db::TestDB;
370 368
@@ -522,7 +520,7 @@ mod tests {
522 520
523 #[test] 521 #[test]
524 fn partially_imported() { 522 fn partially_imported() {
525 mark::check!(partially_imported); 523 cov_mark::check!(partially_imported);
526 // Tests that short paths are used even for external items, when parts of the path are 524 // Tests that short paths are used even for external items, when parts of the path are
527 // already in scope. 525 // already in scope.
528 let code = r#" 526 let code = r#"
@@ -686,7 +684,7 @@ mod tests {
686 684
687 #[test] 685 #[test]
688 fn prefer_std_paths_over_alloc() { 686 fn prefer_std_paths_over_alloc() {
689 mark::check!(prefer_std_paths); 687 cov_mark::check!(prefer_std_paths);
690 let code = r#" 688 let code = r#"
691 //- /main.rs crate:main deps:alloc,std 689 //- /main.rs crate:main deps:alloc,std
692 $0 690 $0
@@ -712,7 +710,7 @@ mod tests {
712 710
713 #[test] 711 #[test]
714 fn prefer_core_paths_over_std() { 712 fn prefer_core_paths_over_std() {
715 mark::check!(prefer_no_std_paths); 713 cov_mark::check!(prefer_no_std_paths);
716 let code = r#" 714 let code = r#"
717 //- /main.rs crate:main deps:core,std 715 //- /main.rs crate:main deps:core,std
718 #![no_std] 716 #![no_std]
@@ -842,7 +840,7 @@ mod tests {
842 840
843 #[test] 841 #[test]
844 fn inner_items_from_inner_module() { 842 fn inner_items_from_inner_module() {
845 mark::check!(prefixed_in_block_expression); 843 cov_mark::check!(prefixed_in_block_expression);
846 check_found_path( 844 check_found_path(
847 r#" 845 r#"
848 fn main() { 846 fn main() {
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 0a3dc7956..369bc3350 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -8,7 +8,6 @@ use hir_expand::name::Name;
8use indexmap::{map::Entry, IndexMap}; 8use indexmap::{map::Entry, IndexMap};
9use itertools::Itertools; 9use itertools::Itertools;
10use rustc_hash::{FxHashSet, FxHasher}; 10use rustc_hash::{FxHashSet, FxHasher};
11use test_utils::mark;
12 11
13use crate::{ 12use crate::{
14 db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, 13 db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId,
@@ -193,7 +192,7 @@ impl ImportMap {
193 // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias` 192 // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias`
194 // qualifier, ergo no need to store it for imports in import_map 193 // qualifier, ergo no need to store it for imports in import_map
195 AssocItemId::TypeAliasId(_) => { 194 AssocItemId::TypeAliasId(_) => {
196 mark::hit!(type_aliases_ignored); 195 cov_mark::hit!(type_aliases_ignored);
197 continue; 196 continue;
198 } 197 }
199 }; 198 };
@@ -388,7 +387,7 @@ pub fn search_dependencies<'a>(
388 db: &'a dyn DefDatabase, 387 db: &'a dyn DefDatabase,
389 krate: CrateId, 388 krate: CrateId,
390 query: Query, 389 query: Query,
391) -> Vec<ItemInNs> { 390) -> FxHashSet<ItemInNs> {
392 let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query)); 391 let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query));
393 392
394 let graph = db.crate_graph(); 393 let graph = db.crate_graph();
@@ -403,41 +402,42 @@ pub fn search_dependencies<'a>(
403 } 402 }
404 403
405 let mut stream = op.union(); 404 let mut stream = op.union();
406 let mut res = Vec::new(); 405
406 let mut all_indexed_values = FxHashSet::default();
407 while let Some((_, indexed_values)) = stream.next() { 407 while let Some((_, indexed_values)) = stream.next() {
408 for indexed_value in indexed_values { 408 all_indexed_values.extend(indexed_values.iter().copied());
409 let import_map = &import_maps[indexed_value.index]; 409 }
410 let importables = &import_map.importables[indexed_value.value as usize..];
411 410
412 let common_importable_data = &import_map.map[&importables[0]]; 411 let mut res = FxHashSet::default();
413 if !query.import_matches(common_importable_data, true) { 412 for indexed_value in all_indexed_values {
414 continue; 413 let import_map = &import_maps[indexed_value.index];
415 } 414 let importables = &import_map.importables[indexed_value.value as usize..];
416 415
417 // Path shared by the importable items in this group. 416 let common_importable_data = &import_map.map[&importables[0]];
418 let common_importables_path_fst = fst_path(&common_importable_data.path); 417 if !query.import_matches(common_importable_data, true) {
419 // Add the items from this `ModPath` group. Those are all subsequent items in 418 continue;
420 // `importables` whose paths match `path`. 419 }
421 let iter = importables 420
422 .iter() 421 // Path shared by the importable items in this group.
423 .copied() 422 let common_importables_path_fst = fst_path(&common_importable_data.path);
424 .take_while(|item| { 423 // Add the items from this `ModPath` group. Those are all subsequent items in
425 common_importables_path_fst == fst_path(&import_map.map[item].path) 424 // `importables` whose paths match `path`.
426 }) 425 let iter = importables
427 .filter(|&item| match item_import_kind(item) { 426 .iter()
428 Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), 427 .copied()
429 None => true, 428 .take_while(|item| common_importables_path_fst == fst_path(&import_map.map[item].path))
430 }) 429 .filter(|&item| match item_import_kind(item) {
431 .filter(|item| { 430 Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
432 !query.case_sensitive // we've already checked the common importables path case-insensitively 431 None => true,
432 })
433 .filter(|item| {
434 !query.case_sensitive // we've already checked the common importables path case-insensitively
433 || query.import_matches(&import_map.map[item], false) 435 || query.import_matches(&import_map.map[item], false)
434 }); 436 });
435 res.extend(iter); 437 res.extend(iter);
436 438
437 if res.len() >= query.limit { 439 if res.len() >= query.limit {
438 res.truncate(query.limit); 440 return res;
439 return res;
440 }
441 } 441 }
442 } 442 }
443 443
@@ -462,7 +462,6 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> {
462mod tests { 462mod tests {
463 use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; 463 use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
464 use expect_test::{expect, Expect}; 464 use expect_test::{expect, Expect};
465 use test_utils::mark;
466 465
467 use crate::{test_db::TestDB, AssocContainerId, Lookup}; 466 use crate::{test_db::TestDB, AssocContainerId, Lookup};
468 467
@@ -800,7 +799,7 @@ mod tests {
800 799
801 #[test] 800 #[test]
802 fn fuzzy_import_trait_and_assoc_items() { 801 fn fuzzy_import_trait_and_assoc_items() {
803 mark::check!(type_aliases_ignored); 802 cov_mark::check!(type_aliases_ignored);
804 let ra_fixture = r#" 803 let ra_fixture = r#"
805 //- /main.rs crate:main deps:dep 804 //- /main.rs crate:main deps:dep
806 //- /dep.rs crate:dep 805 //- /dep.rs crate:dep
@@ -821,10 +820,10 @@ mod tests {
821 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), 820 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
822 expect![[r#" 821 expect![[r#"
823 dep::fmt (t) 822 dep::fmt (t)
823 dep::fmt::Display::format_method (a)
824 dep::fmt::Display (t) 824 dep::fmt::Display (t)
825 dep::fmt::Display::FMT_CONST (a) 825 dep::fmt::Display::FMT_CONST (a)
826 dep::fmt::Display::format_function (a) 826 dep::fmt::Display::format_function (a)
827 dep::fmt::Display::format_method (a)
828 "#]], 827 "#]],
829 ); 828 );
830 } 829 }
@@ -850,9 +849,9 @@ mod tests {
850 "main", 849 "main",
851 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(), 850 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(),
852 expect![[r#" 851 expect![[r#"
852 dep::fmt::Display::format_method (a)
853 dep::fmt::Display::FMT_CONST (a) 853 dep::fmt::Display::FMT_CONST (a)
854 dep::fmt::Display::format_function (a) 854 dep::fmt::Display::format_function (a)
855 dep::fmt::Display::format_method (a)
856 "#]], 855 "#]],
857 ); 856 );
858 857
@@ -911,12 +910,12 @@ mod tests {
911 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), 910 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
912 expect![[r#" 911 expect![[r#"
913 dep::fmt (t) 912 dep::fmt (t)
914 dep::Fmt (t) 913 dep::format (f)
915 dep::Fmt (v) 914 dep::Fmt (v)
916 dep::Fmt (m)
917 dep::fmt::Display (t) 915 dep::fmt::Display (t)
916 dep::Fmt (t)
918 dep::fmt::Display::fmt (a) 917 dep::fmt::Display::fmt (a)
919 dep::format (f) 918 dep::Fmt (m)
920 "#]], 919 "#]],
921 ); 920 );
922 921
@@ -926,10 +925,10 @@ mod tests {
926 Query::new("fmt".to_string()).search_mode(SearchMode::Equals), 925 Query::new("fmt".to_string()).search_mode(SearchMode::Equals),
927 expect![[r#" 926 expect![[r#"
928 dep::fmt (t) 927 dep::fmt (t)
929 dep::Fmt (t)
930 dep::Fmt (v) 928 dep::Fmt (v)
931 dep::Fmt (m) 929 dep::Fmt (t)
932 dep::fmt::Display::fmt (a) 930 dep::fmt::Display::fmt (a)
931 dep::Fmt (m)
933 "#]], 932 "#]],
934 ); 933 );
935 934
@@ -939,11 +938,11 @@ mod tests {
939 Query::new("fmt".to_string()).search_mode(SearchMode::Contains), 938 Query::new("fmt".to_string()).search_mode(SearchMode::Contains),
940 expect![[r#" 939 expect![[r#"
941 dep::fmt (t) 940 dep::fmt (t)
942 dep::Fmt (t)
943 dep::Fmt (v) 941 dep::Fmt (v)
944 dep::Fmt (m)
945 dep::fmt::Display (t) 942 dep::fmt::Display (t)
943 dep::Fmt (t)
946 dep::fmt::Display::fmt (a) 944 dep::fmt::Display::fmt (a)
945 dep::Fmt (m)
947 "#]], 946 "#]],
948 ); 947 );
949 } 948 }
@@ -980,11 +979,11 @@ mod tests {
980 Query::new("fmt".to_string()), 979 Query::new("fmt".to_string()),
981 expect![[r#" 980 expect![[r#"
982 dep::fmt (t) 981 dep::fmt (t)
983 dep::Fmt (t)
984 dep::Fmt (v) 982 dep::Fmt (v)
985 dep::Fmt (m)
986 dep::fmt::Display (t) 983 dep::fmt::Display (t)
984 dep::Fmt (t)
987 dep::fmt::Display::fmt (a) 985 dep::fmt::Display::fmt (a)
986 dep::Fmt (m)
988 "#]], 987 "#]],
989 ); 988 );
990 989
@@ -994,10 +993,10 @@ mod tests {
994 Query::new("fmt".to_string()).name_only(), 993 Query::new("fmt".to_string()).name_only(),
995 expect![[r#" 994 expect![[r#"
996 dep::fmt (t) 995 dep::fmt (t)
997 dep::Fmt (t)
998 dep::Fmt (v) 996 dep::Fmt (v)
999 dep::Fmt (m) 997 dep::Fmt (t)
1000 dep::fmt::Display::fmt (a) 998 dep::fmt::Display::fmt (a)
999 dep::Fmt (m)
1001 "#]], 1000 "#]],
1002 ); 1001 );
1003 } 1002 }
@@ -1018,9 +1017,9 @@ mod tests {
1018 Query::new("FMT".to_string()), 1017 Query::new("FMT".to_string()),
1019 expect![[r#" 1018 expect![[r#"
1020 dep::fmt (t) 1019 dep::fmt (t)
1020 dep::FMT (v)
1021 dep::fmt (v) 1021 dep::fmt (v)
1022 dep::FMT (t) 1022 dep::FMT (t)
1023 dep::FMT (v)
1024 "#]], 1023 "#]],
1025 ); 1024 );
1026 1025
@@ -1060,6 +1059,8 @@ mod tests {
1060 expect![[r#" 1059 expect![[r#"
1061 dep::fmt (t) 1060 dep::fmt (t)
1062 dep::Fmt (t) 1061 dep::Fmt (t)
1062 dep::Fmt (m)
1063 dep::Fmt (v)
1063 "#]], 1064 "#]],
1064 ); 1065 );
1065 } 1066 }
@@ -1080,9 +1081,9 @@ mod tests {
1080 Query::new("FMT".to_string()), 1081 Query::new("FMT".to_string()),
1081 expect![[r#" 1082 expect![[r#"
1082 dep::fmt (t) 1083 dep::fmt (t)
1084 dep::FMT (v)
1083 dep::fmt (v) 1085 dep::fmt (v)
1084 dep::FMT (t) 1086 dep::FMT (t)
1085 dep::FMT (v)
1086 "#]], 1087 "#]],
1087 ); 1088 );
1088 1089
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 4e5daa2ff..919933813 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -9,7 +9,6 @@ use hir_expand::MacroDefKind;
9use once_cell::sync::Lazy; 9use once_cell::sync::Lazy;
10use rustc_hash::{FxHashMap, FxHashSet}; 10use rustc_hash::{FxHashMap, FxHashSet};
11use stdx::format_to; 11use stdx::format_to;
12use test_utils::mark;
13 12
14use crate::{ 13use crate::{
15 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, 14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId,
@@ -237,7 +236,7 @@ impl ItemScope {
237 if $glob_imports.$field.contains(&$lookup) 236 if $glob_imports.$field.contains(&$lookup)
238 && matches!($def_import_type, ImportType::Named) => 237 && matches!($def_import_type, ImportType::Named) =>
239 { 238 {
240 mark::hit!(import_shadowed); 239 cov_mark::hit!(import_shadowed);
241 $glob_imports.$field.remove(&$lookup); 240 $glob_imports.$field.remove(&$lookup);
242 if let Some(fld) = $def.$field { 241 if let Some(fld) = $def.$field {
243 entry.insert(fld); 242 entry.insert(fld);
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 3233b1957..6bb334573 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -25,7 +25,6 @@ use profile::Count;
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use smallvec::SmallVec; 26use smallvec::SmallVec;
27use syntax::{ast, match_ast, SyntaxKind}; 27use syntax::{ast, match_ast, SyntaxKind};
28use test_utils::mark;
29 28
30use crate::{ 29use crate::{
31 attr::{Attrs, RawAttrs}, 30 attr::{Attrs, RawAttrs},
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 8f2f0b340..240fdacf9 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -466,7 +466,7 @@ impl Ctx {
466 .collect() 466 .collect()
467 }) 467 })
468 .unwrap_or_else(|| { 468 .unwrap_or_else(|| {
469 mark::hit!(name_res_works_for_broken_modules); 469 cov_mark::hit!(name_res_works_for_broken_modules);
470 Box::new([]) as Box<[_]> 470 Box::new([]) as Box<[_]>
471 }), 471 }),
472 } 472 }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index e51d89b43..3bb69d935 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -18,7 +18,6 @@ use hir_expand::{
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
20use syntax::ast; 20use syntax::ast;
21use test_utils::mark;
22use tt::{Leaf, TokenTree}; 21use tt::{Leaf, TokenTree};
23 22
24use crate::{ 23use crate::{
@@ -462,7 +461,7 @@ impl DefCollector<'_> {
462 let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); 461 let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name);
463 462
464 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { 463 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
465 mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); 464 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
466 self.import_all_macros_exported(current_module_id, m.krate); 465 self.import_all_macros_exported(current_module_id, m.krate);
467 } 466 }
468 } 467 }
@@ -571,10 +570,10 @@ impl DefCollector<'_> {
571 match def.take_types() { 570 match def.take_types() {
572 Some(ModuleDefId::ModuleId(m)) => { 571 Some(ModuleDefId::ModuleId(m)) => {
573 if import.is_prelude { 572 if import.is_prelude {
574 mark::hit!(std_prelude); 573 cov_mark::hit!(std_prelude);
575 self.def_map.prelude = Some(m); 574 self.def_map.prelude = Some(m);
576 } else if m.krate != self.def_map.krate { 575 } else if m.krate != self.def_map.krate {
577 mark::hit!(glob_across_crates); 576 cov_mark::hit!(glob_across_crates);
578 // glob import from other crate => we can just import everything once 577 // glob import from other crate => we can just import everything once
579 let item_map = m.def_map(self.db); 578 let item_map = m.def_map(self.db);
580 let scope = &item_map[m.local_id].scope; 579 let scope = &item_map[m.local_id].scope;
@@ -626,7 +625,7 @@ impl DefCollector<'_> {
626 } 625 }
627 } 626 }
628 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { 627 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
629 mark::hit!(glob_enum); 628 cov_mark::hit!(glob_enum);
630 // glob import from enum => just import all the variants 629 // glob import from enum => just import all the variants
631 630
632 // XXX: urgh, so this works by accident! Here, we look at 631 // XXX: urgh, so this works by accident! Here, we look at
@@ -675,7 +674,7 @@ impl DefCollector<'_> {
675 674
676 self.update(module_id, &[(name, def)], vis, ImportType::Named); 675 self.update(module_id, &[(name, def)], vis, ImportType::Named);
677 } 676 }
678 None => mark::hit!(bogus_paths), 677 None => cov_mark::hit!(bogus_paths),
679 } 678 }
680 } 679 }
681 } 680 }
@@ -738,7 +737,7 @@ impl DefCollector<'_> {
738 if max_vis == old_vis { 737 if max_vis == old_vis {
739 false 738 false
740 } else { 739 } else {
741 mark::hit!(upgrade_underscore_visibility); 740 cov_mark::hit!(upgrade_underscore_visibility);
742 true 741 true
743 } 742 }
744 } 743 }
@@ -866,7 +865,7 @@ impl DefCollector<'_> {
866 depth: usize, 865 depth: usize,
867 ) { 866 ) {
868 if depth > EXPANSION_DEPTH_LIMIT { 867 if depth > EXPANSION_DEPTH_LIMIT {
869 mark::hit!(macro_expansion_overflow); 868 cov_mark::hit!(macro_expansion_overflow);
870 log::warn!("macro expansion is too deep"); 869 log::warn!("macro expansion is too deep");
871 return; 870 return;
872 } 871 }
@@ -1009,7 +1008,7 @@ impl ModCollector<'_, '_> {
1009 // Prelude module is always considered to be `#[macro_use]`. 1008 // Prelude module is always considered to be `#[macro_use]`.
1010 if let Some(prelude_module) = self.def_collector.def_map.prelude { 1009 if let Some(prelude_module) = self.def_collector.def_map.prelude {
1011 if prelude_module.krate != self.def_collector.def_map.krate { 1010 if prelude_module.krate != self.def_collector.def_map.krate {
1012 mark::hit!(prelude_is_macro_use); 1011 cov_mark::hit!(prelude_is_macro_use);
1013 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); 1012 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
1014 } 1013 }
1015 } 1014 }
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs
index af3262439..d5de9899c 100644
--- a/crates/hir_def/src/nameres/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/mod_resolution.rs
@@ -2,7 +2,6 @@
2use base_db::{AnchoredPath, FileId}; 2use base_db::{AnchoredPath, FileId};
3use hir_expand::name::Name; 3use hir_expand::name::Name;
4use syntax::SmolStr; 4use syntax::SmolStr;
5use test_utils::mark;
6 5
7use crate::{db::DefDatabase, HirFileId}; 6use crate::{db::DefDatabase, HirFileId};
8 7
@@ -28,7 +27,7 @@ impl ModDir {
28 let depth = self.depth + 1; 27 let depth = self.depth + 1;
29 if depth > MOD_DEPTH_LIMIT { 28 if depth > MOD_DEPTH_LIMIT {
30 log::error!("MOD_DEPTH_LIMIT exceeded"); 29 log::error!("MOD_DEPTH_LIMIT exceeded");
31 mark::hit!(circular_mods); 30 cov_mark::hit!(circular_mods);
32 return None; 31 return None;
33 } 32 }
34 Some(ModDir { dir_path, root_non_dir_owner, depth }) 33 Some(ModDir { dir_path, root_non_dir_owner, depth })
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index dd1db0094..8258dcffb 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -13,7 +13,6 @@
13use base_db::Edition; 13use base_db::Edition;
14use hir_expand::name; 14use hir_expand::name;
15use hir_expand::name::Name; 15use hir_expand::name::Name;
16use test_utils::mark;
17 16
18use crate::{ 17use crate::{
19 db::DefDatabase, 18 db::DefDatabase,
@@ -63,7 +62,7 @@ impl ResolvePathResult {
63impl DefMap { 62impl DefMap {
64 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 63 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
65 if name == &name!(self) { 64 if name == &name!(self) {
66 mark::hit!(extern_crate_self_as); 65 cov_mark::hit!(extern_crate_self_as);
67 return PerNs::types(self.module_id(self.root).into(), Visibility::Public); 66 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
68 } 67 }
69 self.extern_prelude 68 self.extern_prelude
@@ -101,7 +100,7 @@ impl DefMap {
101 // DefMap they're written in, so we restrict them when that happens. 100 // DefMap they're written in, so we restrict them when that happens.
102 if let Visibility::Module(m) = vis { 101 if let Visibility::Module(m) = vis {
103 if self.block_id() != m.block { 102 if self.block_id() != m.block {
104 mark::hit!(adjust_vis_in_block_def_map); 103 cov_mark::hit!(adjust_vis_in_block_def_map);
105 vis = Visibility::Module(self.module_id(self.root())); 104 vis = Visibility::Module(self.module_id(self.root()));
106 log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); 105 log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
107 } 106 }
@@ -169,12 +168,12 @@ impl DefMap {
169 let mut curr_per_ns: PerNs = match path.kind { 168 let mut curr_per_ns: PerNs = match path.kind {
170 PathKind::DollarCrate(krate) => { 169 PathKind::DollarCrate(krate) => {
171 if krate == self.krate { 170 if krate == self.krate {
172 mark::hit!(macro_dollar_crate_self); 171 cov_mark::hit!(macro_dollar_crate_self);
173 PerNs::types(self.crate_root(db).into(), Visibility::Public) 172 PerNs::types(self.crate_root(db).into(), Visibility::Public)
174 } else { 173 } else {
175 let def_map = db.crate_def_map(krate); 174 let def_map = db.crate_def_map(krate);
176 let module = def_map.module_id(def_map.root); 175 let module = def_map.module_id(def_map.root);
177 mark::hit!(macro_dollar_crate_other); 176 cov_mark::hit!(macro_dollar_crate_other);
178 PerNs::types(module.into(), Visibility::Public) 177 PerNs::types(module.into(), Visibility::Public)
179 } 178 }
180 } 179 }
@@ -310,7 +309,7 @@ impl DefMap {
310 } 309 }
311 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 310 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
312 // enum variant 311 // enum variant
313 mark::hit!(can_import_enum_variant); 312 cov_mark::hit!(can_import_enum_variant);
314 let enum_data = db.enum_data(e); 313 let enum_data = db.enum_data(e);
315 match enum_data.variant(&segment) { 314 match enum_data.variant(&segment) {
316 Some(local_id) => { 315 Some(local_id) => {
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index bd3e2701b..de3aa4f9a 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -9,7 +9,6 @@ use std::sync::Arc;
9 9
10use base_db::{fixture::WithFixture, SourceDatabase}; 10use base_db::{fixture::WithFixture, SourceDatabase};
11use expect_test::{expect, Expect}; 11use expect_test::{expect, Expect};
12use test_utils::mark;
13 12
14use crate::{db::DefDatabase, test_db::TestDB}; 13use crate::{db::DefDatabase, test_db::TestDB};
15 14
@@ -136,7 +135,7 @@ mod m {
136 135
137#[test] 136#[test]
138fn bogus_paths() { 137fn bogus_paths() {
139 mark::check!(bogus_paths); 138 cov_mark::check!(bogus_paths);
140 check( 139 check(
141 r#" 140 r#"
142//- /lib.rs 141//- /lib.rs
@@ -243,7 +242,7 @@ pub struct Baz;
243 242
244#[test] 243#[test]
245fn std_prelude() { 244fn std_prelude() {
246 mark::check!(std_prelude); 245 cov_mark::check!(std_prelude);
247 check( 246 check(
248 r#" 247 r#"
249//- /main.rs crate:main deps:test_crate 248//- /main.rs crate:main deps:test_crate
@@ -267,7 +266,7 @@ pub enum Foo { Bar, Baz };
267 266
268#[test] 267#[test]
269fn can_import_enum_variant() { 268fn can_import_enum_variant() {
270 mark::check!(can_import_enum_variant); 269 cov_mark::check!(can_import_enum_variant);
271 check( 270 check(
272 r#" 271 r#"
273enum E { V } 272enum E { V }
@@ -628,7 +627,7 @@ use crate::reex::*;
628 627
629#[test] 628#[test]
630fn underscore_pub_crate_reexport() { 629fn underscore_pub_crate_reexport() {
631 mark::check!(upgrade_underscore_visibility); 630 cov_mark::check!(upgrade_underscore_visibility);
632 check( 631 check(
633 r#" 632 r#"
634//- /main.rs crate:main deps:lib 633//- /main.rs crate:main deps:lib
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index e8e72e5ef..d5ef8ceb5 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -1,5 +1,4 @@
1use base_db::fixture::WithFixture; 1use base_db::fixture::WithFixture;
2use test_utils::mark;
3 2
4use crate::test_db::TestDB; 3use crate::test_db::TestDB;
5 4
@@ -63,7 +62,7 @@ fn unresolved_extern_crate() {
63 62
64#[test] 63#[test]
65fn extern_crate_self_as() { 64fn extern_crate_self_as() {
66 mark::check!(extern_crate_self_as); 65 cov_mark::check!(extern_crate_self_as);
67 check_diagnostics( 66 check_diagnostics(
68 r" 67 r"
69 //- /lib.rs 68 //- /lib.rs
@@ -140,7 +139,7 @@ fn inactive_item() {
140/// Tests that `cfg` attributes behind `cfg_attr` is handled properly. 139/// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
141#[test] 140#[test]
142fn inactive_via_cfg_attr() { 141fn inactive_via_cfg_attr() {
143 mark::check!(cfg_attr_active); 142 cov_mark::check!(cfg_attr_active);
144 check_diagnostics( 143 check_diagnostics(
145 r#" 144 r#"
146 //- /lib.rs 145 //- /lib.rs
diff --git a/crates/hir_def/src/nameres/tests/globs.rs b/crates/hir_def/src/nameres/tests/globs.rs
index 2ae836e3c..17426d54d 100644
--- a/crates/hir_def/src/nameres/tests/globs.rs
+++ b/crates/hir_def/src/nameres/tests/globs.rs
@@ -148,7 +148,7 @@ pub(crate) struct PubCrateStruct;
148 148
149#[test] 149#[test]
150fn glob_across_crates() { 150fn glob_across_crates() {
151 mark::check!(glob_across_crates); 151 cov_mark::check!(glob_across_crates);
152 check( 152 check(
153 r#" 153 r#"
154//- /main.rs crate:main deps:test_crate 154//- /main.rs crate:main deps:test_crate
@@ -184,7 +184,7 @@ struct Foo;
184 184
185#[test] 185#[test]
186fn glob_enum() { 186fn glob_enum() {
187 mark::check!(glob_enum); 187 cov_mark::check!(glob_enum);
188 check( 188 check(
189 r#" 189 r#"
190enum Foo { Bar, Baz } 190enum Foo { Bar, Baz }
@@ -201,7 +201,7 @@ use self::Foo::*;
201 201
202#[test] 202#[test]
203fn glob_enum_group() { 203fn glob_enum_group() {
204 mark::check!(glob_enum_group); 204 cov_mark::check!(glob_enum_group);
205 check( 205 check(
206 r#" 206 r#"
207enum Foo { Bar, Baz } 207enum Foo { Bar, Baz }
@@ -218,7 +218,7 @@ use self::Foo::{*};
218 218
219#[test] 219#[test]
220fn glob_shadowed_def() { 220fn glob_shadowed_def() {
221 mark::check!(import_shadowed); 221 cov_mark::check!(import_shadowed);
222 check( 222 check(
223 r#" 223 r#"
224//- /lib.rs 224//- /lib.rs
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 36ed5e8ce..f65a655bf 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -210,7 +210,7 @@ macro_rules! bar {
210 210
211#[test] 211#[test]
212fn macro_rules_from_other_crates_are_visible_with_macro_use() { 212fn macro_rules_from_other_crates_are_visible_with_macro_use() {
213 mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); 213 cov_mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use);
214 check( 214 check(
215 r#" 215 r#"
216//- /main.rs crate:main deps:foo 216//- /main.rs crate:main deps:foo
@@ -260,7 +260,7 @@ mod priv_mod {
260 260
261#[test] 261#[test]
262fn prelude_is_macro_use() { 262fn prelude_is_macro_use() {
263 mark::check!(prelude_is_macro_use); 263 cov_mark::check!(prelude_is_macro_use);
264 check( 264 check(
265 r#" 265 r#"
266//- /main.rs crate:main deps:foo 266//- /main.rs crate:main deps:foo
@@ -550,7 +550,7 @@ mod m {
550 550
551#[test] 551#[test]
552fn macro_dollar_crate_is_correct_in_item() { 552fn macro_dollar_crate_is_correct_in_item() {
553 mark::check!(macro_dollar_crate_self); 553 cov_mark::check!(macro_dollar_crate_self);
554 check( 554 check(
555 r#" 555 r#"
556//- /main.rs crate:main deps:foo 556//- /main.rs crate:main deps:foo
@@ -608,7 +608,7 @@ struct Baz;
608 608
609#[test] 609#[test]
610fn macro_dollar_crate_is_correct_in_indirect_deps() { 610fn macro_dollar_crate_is_correct_in_indirect_deps() {
611 mark::check!(macro_dollar_crate_other); 611 cov_mark::check!(macro_dollar_crate_other);
612 // From std 612 // From std
613 check( 613 check(
614 r#" 614 r#"
@@ -686,7 +686,7 @@ pub trait Clone {}
686 686
687#[test] 687#[test]
688fn macro_expansion_overflow() { 688fn macro_expansion_overflow() {
689 mark::check!(macro_expansion_overflow); 689 cov_mark::check!(macro_expansion_overflow);
690 check( 690 check(
691 r#" 691 r#"
692macro_rules! a { 692macro_rules! a {
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs
index e80b593aa..dfbbad1f9 100644
--- a/crates/hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3#[test] 3#[test]
4fn name_res_works_for_broken_modules() { 4fn name_res_works_for_broken_modules() {
5 mark::check!(name_res_works_for_broken_modules); 5 cov_mark::check!(name_res_works_for_broken_modules);
6 check( 6 check(
7 r" 7 r"
8//- /lib.rs 8//- /lib.rs
@@ -774,7 +774,7 @@ struct X;
774 774
775#[test] 775#[test]
776fn circular_mods() { 776fn circular_mods() {
777 mark::check!(circular_mods); 777 cov_mark::check!(circular_mods);
778 compute_crate_def_map( 778 compute_crate_def_map(
779 r#" 779 r#"
780//- /lib.rs 780//- /lib.rs
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs
index d584b0b70..e2965b033 100644
--- a/crates/hir_def/src/path/lower/lower_use.rs
+++ b/crates/hir_def/src/path/lower/lower_use.rs
@@ -6,7 +6,6 @@ use std::iter;
6use either::Either; 6use either::Either;
7use hir_expand::{hygiene::Hygiene, name::AsName}; 7use hir_expand::{hygiene::Hygiene, name::AsName};
8use syntax::ast::{self, NameOwner}; 8use syntax::ast::{self, NameOwner};
9use test_utils::mark;
10 9
11use crate::path::{ImportAlias, ModPath, PathKind}; 10use crate::path::{ImportAlias, ModPath, PathKind};
12 11
@@ -54,7 +53,7 @@ pub(crate) fn lower_use_tree(
54 // FIXME: report errors somewhere 53 // FIXME: report errors somewhere
55 // We get here if we do 54 // We get here if we do
56 } else if is_glob { 55 } else if is_glob {
57 mark::hit!(glob_enum_group); 56 cov_mark::hit!(glob_enum_group);
58 if let Some(prefix) = prefix { 57 if let Some(prefix) = prefix {
59 cb(prefix, &tree, is_glob, None) 58 cb(prefix, &tree, is_glob, None)
60 } 59 }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index d1302d749..6131ebee8 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1"
13itertools = "0.10.0" 14itertools = "0.10.0"
14arrayvec = "0.5.1" 15arrayvec = "0.5.1"
15smallvec = "1.2.0" 16smallvec = "1.2.0"
@@ -17,9 +18,9 @@ ena = "0.14.0"
17log = "0.4.8" 18log = "0.4.8"
18rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
19scoped-tls = "1" 20scoped-tls = "1"
20chalk-solve = { version = "0.59", default-features = false } 21chalk-solve = { version = "0.60", default-features = false }
21chalk-ir = "0.59" 22chalk-ir = "0.60"
22chalk-recursive = "0.59" 23chalk-recursive = "0.60"
23la-arena = { version = "0.2.0", path = "../../lib/arena" } 24la-arena = { version = "0.2.0", path = "../../lib/arena" }
24 25
25stdx = { path = "../stdx", version = "0.0.0" } 26stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 6773ddea3..e230f9765 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -28,7 +28,6 @@ use syntax::{
28 ast::{self, NameOwner}, 28 ast::{self, NameOwner},
29 AstNode, AstPtr, 29 AstNode, AstPtr,
30}; 30};
31use test_utils::mark;
32 31
33use crate::{ 32use crate::{
34 db::HirDatabase, 33 db::HirDatabase,
@@ -93,7 +92,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
93 fn validate_func(&mut self, func: FunctionId) { 92 fn validate_func(&mut self, func: FunctionId) {
94 let data = self.db.function_data(func); 93 let data = self.db.function_data(func);
95 if data.is_extern { 94 if data.is_extern {
96 mark::hit!(extern_func_incorrect_case_ignored); 95 cov_mark::hit!(extern_func_incorrect_case_ignored);
97 return; 96 return;
98 } 97 }
99 98
@@ -625,7 +624,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
625 fn validate_static(&mut self, static_id: StaticId) { 624 fn validate_static(&mut self, static_id: StaticId) {
626 let data = self.db.static_data(static_id); 625 let data = self.db.static_data(static_id);
627 if data.is_extern { 626 if data.is_extern {
628 mark::hit!(extern_static_incorrect_case_ignored); 627 cov_mark::hit!(extern_static_incorrect_case_ignored);
629 return; 628 return;
630 } 629 }
631 630
@@ -673,8 +672,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
673 672
674#[cfg(test)] 673#[cfg(test)]
675mod tests { 674mod tests {
676 use test_utils::mark;
677
678 use crate::diagnostics::tests::check_diagnostics; 675 use crate::diagnostics::tests::check_diagnostics;
679 676
680 #[test] 677 #[test]
@@ -889,8 +886,8 @@ fn main() {
889 886
890 #[test] 887 #[test]
891 fn ignores_extern_items() { 888 fn ignores_extern_items() {
892 mark::check!(extern_func_incorrect_case_ignored); 889 cov_mark::check!(extern_func_incorrect_case_ignored);
893 mark::check!(extern_static_incorrect_case_ignored); 890 cov_mark::check!(extern_static_incorrect_case_ignored);
894 check_diagnostics( 891 check_diagnostics(
895 r#" 892 r#"
896extern { 893extern {
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index cf0a3add4..7e8846f27 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -6,7 +6,6 @@
6 6
7use chalk_ir::{Mutability, TyVariableKind}; 7use chalk_ir::{Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9use test_utils::mark;
10 9
11use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty}; 10use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty};
12 11
@@ -35,7 +34,7 @@ impl<'a> InferenceContext<'a> {
35 ty1.clone() 34 ty1.clone()
36 } else { 35 } else {
37 if let (Ty::FnDef(..), Ty::FnDef(..)) = (ty1, ty2) { 36 if let (Ty::FnDef(..), Ty::FnDef(..)) = (ty1, ty2) {
38 mark::hit!(coerce_fn_reification); 37 cov_mark::hit!(coerce_fn_reification);
39 // Special case: two function types. Try to coerce both to 38 // Special case: two function types. Try to coerce both to
40 // pointers to have a chance at getting a match. See 39 // pointers to have a chance at getting a match. See
41 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 40 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
@@ -45,7 +44,7 @@ impl<'a> InferenceContext<'a> {
45 let ptr_ty2 = Ty::fn_ptr(sig2); 44 let ptr_ty2 = Ty::fn_ptr(sig2);
46 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) 45 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
47 } else { 46 } else {
48 mark::hit!(coerce_merge_fail_fallback); 47 cov_mark::hit!(coerce_merge_fail_fallback);
49 ty1.clone() 48 ty1.clone()
50 } 49 }
51 } 50 }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index ec2c13154..262177ffb 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -12,7 +12,6 @@ use hir_def::{
12}; 12};
13use hir_expand::name::{name, Name}; 13use hir_expand::name::{name, Name};
14use syntax::ast::RangeOp; 14use syntax::ast::RangeOp;
15use test_utils::mark;
16 15
17use crate::{ 16use crate::{
18 autoderef, 17 autoderef,
@@ -565,7 +564,7 @@ impl<'a> InferenceContext<'a> {
565 let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone()); 564 let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone());
566 565
567 if ret == Ty::Unknown { 566 if ret == Ty::Unknown {
568 mark::hit!(infer_expr_inner_binary_operator_overload); 567 cov_mark::hit!(infer_expr_inner_binary_operator_overload);
569 568
570 self.resolve_associated_type_with_params( 569 self.resolve_associated_type_with_params(
571 lhs_ty, 570 lhs_ty,
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 987793e2e..a0ac8d80f 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -10,7 +10,6 @@ use hir_def::{
10 FieldId, 10 FieldId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use test_utils::mark;
14 13
15use super::{BindingMode, Expectation, InferenceContext}; 14use super::{BindingMode, Expectation, InferenceContext};
16use crate::{lower::lower_to_chalk_mutability, utils::variant_data, Substs, Ty}; 15use crate::{lower::lower_to_chalk_mutability, utils::variant_data, Substs, Ty};
@@ -108,7 +107,7 @@ impl<'a> InferenceContext<'a> {
108 } 107 }
109 } 108 }
110 } else if let Pat::Ref { .. } = &body[pat] { 109 } else if let Pat::Ref { .. } = &body[pat] {
111 mark::hit!(match_ergonomics_ref); 110 cov_mark::hit!(match_ergonomics_ref);
112 // When you encounter a `&pat` pattern, reset to Move. 111 // When you encounter a `&pat` pattern, reset to Move.
113 // This is so that `w` is by value: `let (_, &w) = &(1, &2);` 112 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
114 default_bm = BindingMode::Move; 113 default_bm = BindingMode::Move;
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 99a89a7f3..54fcfed10 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -5,8 +5,6 @@ use std::borrow::Cow;
5use chalk_ir::{FloatTy, IntTy, TyVariableKind}; 5use chalk_ir::{FloatTy, IntTy, TyVariableKind};
6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 7
8use test_utils::mark;
9
10use super::{InferenceContext, Obligation}; 8use super::{InferenceContext, Obligation};
11use crate::{ 9use crate::{
12 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferenceVar, Scalar, 10 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferenceVar, Scalar,
@@ -387,7 +385,7 @@ impl InferenceTable {
387 // more than once 385 // more than once
388 for i in 0..3 { 386 for i in 0..3 {
389 if i > 0 { 387 if i > 0 {
390 mark::hit!(type_var_resolves_to_int_var); 388 cov_mark::hit!(type_var_resolves_to_int_var);
391 } 389 }
392 match &*ty { 390 match &*ty {
393 Ty::InferenceVar(tv, _) => { 391 Ty::InferenceVar(tv, _) => {
@@ -416,7 +414,7 @@ impl InferenceTable {
416 Ty::InferenceVar(tv, kind) => { 414 Ty::InferenceVar(tv, kind) => {
417 let inner = tv.to_inner(); 415 let inner = tv.to_inner();
418 if tv_stack.contains(&inner) { 416 if tv_stack.contains(&inner) {
419 mark::hit!(type_var_cycles_resolve_as_possible); 417 cov_mark::hit!(type_var_cycles_resolve_as_possible);
420 // recursive type 418 // recursive type
421 return self.type_variable_table.fallback_value(tv, kind); 419 return self.type_variable_table.fallback_value(tv, kind);
422 } 420 }
@@ -443,7 +441,7 @@ impl InferenceTable {
443 Ty::InferenceVar(tv, kind) => { 441 Ty::InferenceVar(tv, kind) => {
444 let inner = tv.to_inner(); 442 let inner = tv.to_inner();
445 if tv_stack.contains(&inner) { 443 if tv_stack.contains(&inner) {
446 mark::hit!(type_var_cycles_resolve_completely); 444 cov_mark::hit!(type_var_cycles_resolve_completely);
447 // recursive type 445 // recursive type
448 return self.type_variable_table.fallback_value(tv, kind); 446 return self.type_variable_table.fallback_value(tv, kind);
449 } 447 }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 5fe5b8ad1..b90fdc382 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -24,7 +24,6 @@ use hir_expand::name::Name;
24use la_arena::ArenaMap; 24use la_arena::ArenaMap;
25use smallvec::SmallVec; 25use smallvec::SmallVec;
26use stdx::impl_from; 26use stdx::impl_from;
27use test_utils::mark;
28 27
29use crate::{ 28use crate::{
30 db::HirDatabase, 29 db::HirDatabase,
@@ -760,7 +759,7 @@ fn assoc_type_bindings_from_type_bound<'a>(
760 759
761impl ReturnTypeImplTrait { 760impl ReturnTypeImplTrait {
762 fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { 761 fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self {
763 mark::hit!(lower_rpit); 762 cov_mark::hit!(lower_rpit);
764 let self_ty = Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 763 let self_ty = Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0));
765 let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { 764 let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
766 bounds 765 bounds
@@ -935,7 +934,7 @@ impl TraitEnvironment {
935 // add `Self: Trait<T1, T2, ...>` to the environment in trait 934 // add `Self: Trait<T1, T2, ...>` to the environment in trait
936 // function default implementations (and hypothetical code 935 // function default implementations (and hypothetical code
937 // inside consts or type aliases) 936 // inside consts or type aliases)
938 test_utils::mark::hit!(trait_self_implements_self); 937 cov_mark::hit!(trait_self_implements_self);
939 let substs = Substs::type_params(db, trait_id); 938 let substs = Substs::type_params(db, trait_id);
940 let trait_ref = TraitRef { trait_: trait_id, substs }; 939 let trait_ref = TraitRef { trait_: trait_id, substs };
941 let pred = GenericPredicate::Implemented(trait_ref); 940 let pred = GenericPredicate::Implemented(trait_ref);
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index dfcf346fb..24db33c49 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -588,7 +588,7 @@ fn iterate_inherent_methods(
588 // already happens in `is_valid_candidate` above; if not, we 588 // already happens in `is_valid_candidate` above; if not, we
589 // check it here 589 // check it here
590 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { 590 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() {
591 test_utils::mark::hit!(impl_self_type_match_without_receiver); 591 cov_mark::hit!(impl_self_type_match_without_receiver);
592 continue; 592 continue;
593 } 593 }
594 if callback(&self_ty.value, item) { 594 if callback(&self_ty.value, item) {
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 7bc6c79f3..63d9d4e0b 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,5 +1,4 @@
1use expect_test::expect; 1use expect_test::expect;
2use test_utils::mark;
3 2
4use super::{check_infer, check_infer_with_mismatches}; 3use super::{check_infer, check_infer_with_mismatches};
5 4
@@ -381,7 +380,7 @@ fn infer_match_second_coerce() {
381 380
382#[test] 381#[test]
383fn coerce_merge_one_by_one1() { 382fn coerce_merge_one_by_one1() {
384 mark::check!(coerce_merge_fail_fallback); 383 cov_mark::check!(coerce_merge_fail_fallback);
385 384
386 check_infer( 385 check_infer(
387 r" 386 r"
@@ -589,7 +588,7 @@ fn coerce_fn_item_to_fn_ptr() {
589 588
590#[test] 589#[test]
591fn coerce_fn_items_in_match_arms() { 590fn coerce_fn_items_in_match_arms() {
592 mark::check!(coerce_fn_reification); 591 cov_mark::check!(coerce_fn_reification);
593 592
594 check_infer_with_mismatches( 593 check_infer_with_mismatches(
595 r" 594 r"
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index a9901d7b8..4e3f9a9b6 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -913,7 +913,7 @@ fn test() { S2.into(); }
913 913
914#[test] 914#[test]
915fn method_resolution_overloaded_method() { 915fn method_resolution_overloaded_method() {
916 test_utils::mark::check!(impl_self_type_match_without_receiver); 916 cov_mark::check!(impl_self_type_match_without_receiver);
917 check_types( 917 check_types(
918 r#" 918 r#"
919struct Wrapper<T>(T); 919struct Wrapper<T>(T);
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 2053d8f56..5da19ba5f 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,5 +1,4 @@
1use expect_test::expect; 1use expect_test::expect;
2use test_utils::mark;
3 2
4use super::{check_infer, check_infer_with_mismatches}; 3use super::{check_infer, check_infer_with_mismatches};
5 4
@@ -197,7 +196,7 @@ fn infer_pattern_match_ergonomics() {
197 196
198#[test] 197#[test]
199fn infer_pattern_match_ergonomics_ref() { 198fn infer_pattern_match_ergonomics_ref() {
200 mark::check!(match_ergonomics_ref); 199 cov_mark::check!(match_ergonomics_ref);
201 check_infer( 200 check_infer(
202 r#" 201 r#"
203 fn test() { 202 fn test() {
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index cffe8630b..69314e245 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1,5 +1,4 @@
1use expect_test::expect; 1use expect_test::expect;
2use test_utils::mark;
3 2
4use super::{check_infer, check_types}; 3use super::{check_infer, check_types};
5 4
@@ -87,8 +86,8 @@ fn bug_651() {
87 86
88#[test] 87#[test]
89fn recursive_vars() { 88fn recursive_vars() {
90 mark::check!(type_var_cycles_resolve_completely); 89 cov_mark::check!(type_var_cycles_resolve_completely);
91 mark::check!(type_var_cycles_resolve_as_possible); 90 cov_mark::check!(type_var_cycles_resolve_as_possible);
92 check_infer( 91 check_infer(
93 r#" 92 r#"
94 fn test() { 93 fn test() {
@@ -166,7 +165,7 @@ fn infer_std_crash_1() {
166 165
167#[test] 166#[test]
168fn infer_std_crash_2() { 167fn infer_std_crash_2() {
169 mark::check!(type_var_resolves_to_int_var); 168 cov_mark::check!(type_var_resolves_to_int_var);
170 // caused "equating two type variables, ...", taken from std 169 // caused "equating two type variables, ...", taken from std
171 check_infer( 170 check_infer(
172 r#" 171 r#"
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 2947857a5..f5069eba5 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1,5 +1,4 @@
1use expect_test::expect; 1use expect_test::expect;
2use test_utils::mark;
3 2
4use super::{check_infer, check_types}; 3use super::{check_infer, check_types};
5 4
@@ -2314,7 +2313,7 @@ fn generic_default_depending_on_other_type_arg_forward() {
2314 2313
2315#[test] 2314#[test]
2316fn infer_operator_overload() { 2315fn infer_operator_overload() {
2317 mark::check!(infer_expr_inner_binary_operator_overload); 2316 cov_mark::check!(infer_expr_inner_binary_operator_overload);
2318 2317
2319 check_infer( 2318 check_infer(
2320 r#" 2319 r#"
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 1298e5a88..528092082 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1,5 +1,4 @@
1use expect_test::expect; 1use expect_test::expect;
2use test_utils::mark;
3 2
4use super::{check_infer, check_infer_with_mismatches, check_types}; 3use super::{check_infer, check_infer_with_mismatches, check_types};
5 4
@@ -319,7 +318,7 @@ fn infer_from_bound_2() {
319 318
320#[test] 319#[test]
321fn trait_default_method_self_bound_implements_trait() { 320fn trait_default_method_self_bound_implements_trait() {
322 mark::check!(trait_self_implements_self); 321 cov_mark::check!(trait_self_implements_self);
323 check_infer( 322 check_infer(
324 r#" 323 r#"
325 trait Trait { 324 trait Trait {
@@ -1189,7 +1188,7 @@ fn impl_trait() {
1189 1188
1190#[test] 1189#[test]
1191fn simple_return_pos_impl_trait() { 1190fn simple_return_pos_impl_trait() {
1192 mark::check!(lower_rpit); 1191 cov_mark::check!(lower_rpit);
1193 check_infer( 1192 check_infer(
1194 r#" 1193 r#"
1195 trait Trait<T> { 1194 trait Trait<T> {
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index f6aaaeda4..f7c5efaf3 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1"
13either = "1.5.3" 14either = "1.5.3"
14indexmap = "1.4.0" 15indexmap = "1.4.0"
15itertools = "0.10.0" 16itertools = "0.10.0"
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index a9454cfa3..5d1cc2052 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -11,7 +11,6 @@ use ide_db::{
11use itertools::Itertools; 11use itertools::Itertools;
12use stdx::format_to; 12use stdx::format_to;
13use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 13use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
14use test_utils::mark;
15 14
16use crate::{ 15use crate::{
17 display::{macro_label, ShortLabel, TryToNav}, 16 display::{macro_label, ShortLabel, TryToNav},
@@ -193,8 +192,8 @@ fn runnable_action(
193 ModuleDef::Function(func) => { 192 ModuleDef::Function(func) => {
194 let src = func.source(sema.db)?; 193 let src = func.source(sema.db)?;
195 if src.file_id != file_id.into() { 194 if src.file_id != file_id.into() {
196 mark::hit!(hover_macro_generated_struct_fn_doc_comment); 195 cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
197 mark::hit!(hover_macro_generated_struct_fn_doc_attr); 196 cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
198 return None; 197 return None;
199 } 198 }
200 199
@@ -2101,7 +2100,7 @@ pub fn fo$0o() {}
2101 2100
2102 #[test] 2101 #[test]
2103 fn test_hover_macro_generated_struct_fn_doc_comment() { 2102 fn test_hover_macro_generated_struct_fn_doc_comment() {
2104 mark::check!(hover_macro_generated_struct_fn_doc_comment); 2103 cov_mark::check!(hover_macro_generated_struct_fn_doc_comment);
2105 2104
2106 check( 2105 check(
2107 r#" 2106 r#"
@@ -2139,7 +2138,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); }
2139 2138
2140 #[test] 2139 #[test]
2141 fn test_hover_macro_generated_struct_fn_doc_attr() { 2140 fn test_hover_macro_generated_struct_fn_doc_attr() {
2142 mark::check!(hover_macro_generated_struct_fn_doc_attr); 2141 cov_mark::check!(hover_macro_generated_struct_fn_doc_attr);
2143 2142
2144 check( 2143 check(
2145 r#" 2144 r#"
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 7fcae13e0..20a920ddb 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -7,7 +7,7 @@ use syntax::{
7 SyntaxKind::{self, USE_TREE, WHITESPACE}, 7 SyntaxKind::{self, USE_TREE, WHITESPACE},
8 SyntaxNode, SyntaxToken, TextRange, TextSize, T, 8 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
9}; 9};
10use test_utils::mark; 10
11use text_edit::{TextEdit, TextEditBuilder}; 11use text_edit::{TextEdit, TextEditBuilder};
12 12
13// Feature: Join Lines 13// Feature: Join Lines
@@ -60,7 +60,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
60 let mut string_open_quote = false; 60 let mut string_open_quote = false;
61 if let Some(string) = ast::String::cast(token.clone()) { 61 if let Some(string) = ast::String::cast(token.clone()) {
62 if let Some(range) = string.open_quote_text_range() { 62 if let Some(range) = string.open_quote_text_range() {
63 mark::hit!(join_string_literal); 63 cov_mark::hit!(join_string_literal);
64 string_open_quote = range.end() == offset; 64 string_open_quote = range.end() == offset;
65 } 65 }
66 } 66 }
@@ -206,7 +206,7 @@ fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
206#[cfg(test)] 206#[cfg(test)]
207mod tests { 207mod tests {
208 use syntax::SourceFile; 208 use syntax::SourceFile;
209 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range, mark}; 209 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
210 210
211 use super::*; 211 use super::*;
212 212
@@ -786,7 +786,7 @@ fn foo() {
786 786
787 #[test] 787 #[test]
788 fn join_string_literal() { 788 fn join_string_literal() {
789 mark::check!(join_string_literal); 789 cov_mark::check!(join_string_literal);
790 check_join_lines( 790 check_join_lines(
791 r#" 791 r#"
792fn main() { 792fn main() {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b600178ee..f83ed65d5 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -478,7 +478,6 @@ impl Analysis {
478 position: FilePosition, 478 position: FilePosition,
479 full_import_path: &str, 479 full_import_path: &str,
480 imported_name: String, 480 imported_name: String,
481 import_for_trait_assoc_item: bool,
482 ) -> Cancelable<Vec<TextEdit>> { 481 ) -> Cancelable<Vec<TextEdit>> {
483 Ok(self 482 Ok(self
484 .with_db(|db| { 483 .with_db(|db| {
@@ -488,7 +487,6 @@ impl Analysis {
488 position, 487 position,
489 full_import_path, 488 full_import_path,
490 imported_name, 489 imported_name,
491 import_for_trait_assoc_item,
492 ) 490 )
493 })? 491 })?
494 .unwrap_or_default()) 492 .unwrap_or_default())
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs
index 1bfa1439d..000c412d9 100644
--- a/crates/ide/src/matching_brace.rs
+++ b/crates/ide/src/matching_brace.rs
@@ -2,7 +2,6 @@ use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 SourceFile, SyntaxKind, TextSize, T, 3 SourceFile, SyntaxKind, TextSize, T,
4}; 4};
5use test_utils::mark;
6 5
7// Feature: Matching Brace 6// Feature: Matching Brace
8// 7//
@@ -28,7 +27,7 @@ pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<Text
28 .next()?; 27 .next()?;
29 let parent = brace_token.parent(); 28 let parent = brace_token.parent();
30 if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) { 29 if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) {
31 mark::hit!(pipes_not_braces); 30 cov_mark::hit!(pipes_not_braces);
32 return None; 31 return None;
33 } 32 }
34 let matching_kind = BRACES[brace_idx ^ 1]; 33 let matching_kind = BRACES[brace_idx ^ 1];
@@ -63,7 +62,7 @@ mod tests {
63 do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}"); 62 do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}");
64 63
65 { 64 {
66 mark::check!(pipes_not_braces); 65 cov_mark::check!(pipes_not_braces);
67 do_check( 66 do_check(
68 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", 67 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }",
69 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", 68 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }",
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index ddbaf22b7..03d71b380 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -5,7 +5,6 @@ use syntax::{
5 algo::find_node_at_offset, 5 algo::find_node_at_offset,
6 ast::{self, AstNode}, 6 ast::{self, AstNode},
7}; 7};
8use test_utils::mark;
9 8
10use crate::NavigationTarget; 9use crate::NavigationTarget;
11 10
@@ -33,7 +32,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
33 .item_list() 32 .item_list()
34 .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) 33 .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset))
35 { 34 {
36 mark::hit!(test_resolve_parent_module_on_module_decl); 35 cov_mark::hit!(test_resolve_parent_module_on_module_decl);
37 module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); 36 module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast);
38 } 37 }
39 } 38 }
@@ -64,7 +63,6 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
64#[cfg(test)] 63#[cfg(test)]
65mod tests { 64mod tests {
66 use ide_db::base_db::FileRange; 65 use ide_db::base_db::FileRange;
67 use test_utils::mark;
68 66
69 use crate::fixture; 67 use crate::fixture;
70 68
@@ -92,7 +90,7 @@ $0// empty
92 90
93 #[test] 91 #[test]
94 fn test_resolve_parent_module_on_module_decl() { 92 fn test_resolve_parent_module_on_module_decl() {
95 mark::check!(test_resolve_parent_module_on_module_decl); 93 cov_mark::check!(test_resolve_parent_module_on_module_decl);
96 check( 94 check(
97 r#" 95 r#"
98//- /lib.rs 96//- /lib.rs
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 1919639a3..05c73de88 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -14,7 +14,7 @@ use syntax::{
14 ast::{self, NameOwner}, 14 ast::{self, NameOwner},
15 lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, 15 lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T,
16}; 16};
17use test_utils::mark; 17
18use text_edit::TextEdit; 18use text_edit::TextEdit;
19 19
20use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange}; 20use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange};
@@ -226,34 +226,36 @@ fn rename_reference(
226 | (IdentifierKind::Ident, _) 226 | (IdentifierKind::Ident, _)
227 if def_is_lbl_or_lt => 227 if def_is_lbl_or_lt =>
228 { 228 {
229 mark::hit!(rename_not_a_lifetime_ident_ref); 229 cov_mark::hit!(rename_not_a_lifetime_ident_ref);
230 bail!("Invalid name `{}`: not a lifetime identifier", new_name) 230 bail!("Invalid name `{}`: not a lifetime identifier", new_name)
231 } 231 }
232 (IdentifierKind::Lifetime, _) if def_is_lbl_or_lt => mark::hit!(rename_lifetime), 232 (IdentifierKind::Lifetime, _) if def_is_lbl_or_lt => cov_mark::hit!(rename_lifetime),
233 (IdentifierKind::Lifetime, _) => { 233 (IdentifierKind::Lifetime, _) => {
234 mark::hit!(rename_not_an_ident_ref); 234 cov_mark::hit!(rename_not_an_ident_ref);
235 bail!("Invalid name `{}`: not an identifier", new_name) 235 bail!("Invalid name `{}`: not an identifier", new_name)
236 } 236 }
237 (IdentifierKind::ToSelf, Definition::Local(local)) if local.is_self(sema.db) => { 237 (IdentifierKind::ToSelf, Definition::Local(local)) if local.is_self(sema.db) => {
238 // no-op 238 // no-op
239 mark::hit!(rename_self_to_self); 239 cov_mark::hit!(rename_self_to_self);
240 return Ok(SourceChange::default()); 240 return Ok(SourceChange::default());
241 } 241 }
242 (ident_kind, Definition::Local(local)) if local.is_self(sema.db) => { 242 (ident_kind, Definition::Local(local)) if local.is_self(sema.db) => {
243 mark::hit!(rename_self_to_param); 243 cov_mark::hit!(rename_self_to_param);
244 return rename_self_to_param(sema, local, new_name, ident_kind); 244 return rename_self_to_param(sema, local, new_name, ident_kind);
245 } 245 }
246 (IdentifierKind::ToSelf, Definition::Local(local)) => { 246 (IdentifierKind::ToSelf, Definition::Local(local)) => {
247 mark::hit!(rename_to_self); 247 cov_mark::hit!(rename_to_self);
248 return rename_to_self(sema, local); 248 return rename_to_self(sema, local);
249 } 249 }
250 (IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name), 250 (IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name),
251 (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident), 251 (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => {
252 cov_mark::hit!(rename_ident)
253 }
252 } 254 }
253 255
254 let usages = def.usages(sema).all(); 256 let usages = def.usages(sema).all();
255 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { 257 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
256 mark::hit!(rename_underscore_multiple); 258 cov_mark::hit!(rename_underscore_multiple);
257 bail!("Cannot rename reference to `_` as it is being referenced multiple times"); 259 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
258 } 260 }
259 let mut source_change = SourceChange::default(); 261 let mut source_change = SourceChange::default();
@@ -444,7 +446,7 @@ fn source_edit_from_name_ref(
444 (Some(field_name), Some(init)) => { 446 (Some(field_name), Some(init)) => {
445 if field_name == *name_ref { 447 if field_name == *name_ref {
446 if init.text() == new_name { 448 if init.text() == new_name {
447 mark::hit!(test_rename_field_put_init_shorthand); 449 cov_mark::hit!(test_rename_field_put_init_shorthand);
448 // same names, we can use a shorthand here instead. 450 // same names, we can use a shorthand here instead.
449 // we do not want to erase attributes hence this range start 451 // we do not want to erase attributes hence this range start
450 let s = field_name.syntax().text_range().start(); 452 let s = field_name.syntax().text_range().start();
@@ -453,7 +455,7 @@ fn source_edit_from_name_ref(
453 } 455 }
454 } else if init == *name_ref { 456 } else if init == *name_ref {
455 if field_name.text() == new_name { 457 if field_name.text() == new_name {
456 mark::hit!(test_rename_local_put_init_shorthand); 458 cov_mark::hit!(test_rename_local_put_init_shorthand);
457 // same names, we can use a shorthand here instead. 459 // same names, we can use a shorthand here instead.
458 // we do not want to erase attributes hence this range start 460 // we do not want to erase attributes hence this range start
459 let s = field_name.syntax().text_range().start(); 461 let s = field_name.syntax().text_range().start();
@@ -467,12 +469,12 @@ fn source_edit_from_name_ref(
467 // FIXME: instead of splitting the shorthand, recursively trigger a rename of the 469 // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
468 // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 470 // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
469 (None, Some(_)) if matches!(def, Definition::Field(_)) => { 471 (None, Some(_)) if matches!(def, Definition::Field(_)) => {
470 mark::hit!(test_rename_field_in_field_shorthand); 472 cov_mark::hit!(test_rename_field_in_field_shorthand);
471 let s = name_ref.syntax().text_range().start(); 473 let s = name_ref.syntax().text_range().start();
472 Some((TextRange::empty(s), format!("{}: ", new_name))) 474 Some((TextRange::empty(s), format!("{}: ", new_name)))
473 } 475 }
474 (None, Some(_)) if matches!(def, Definition::Local(_)) => { 476 (None, Some(_)) if matches!(def, Definition::Local(_)) => {
475 mark::hit!(test_rename_local_in_field_shorthand); 477 cov_mark::hit!(test_rename_local_in_field_shorthand);
476 let s = name_ref.syntax().text_range().end(); 478 let s = name_ref.syntax().text_range().end();
477 Some((TextRange::empty(s), format!(": {}", new_name))) 479 Some((TextRange::empty(s), format!(": {}", new_name)))
478 } 480 }
@@ -486,7 +488,7 @@ fn source_edit_from_name_ref(
486 (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { 488 (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => {
487 // field name is being renamed 489 // field name is being renamed
488 if pat.name().map_or(false, |it| it.text() == new_name) { 490 if pat.name().map_or(false, |it| it.text() == new_name) {
489 mark::hit!(test_rename_field_put_init_shorthand_pat); 491 cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
490 // same names, we can use a shorthand here instead/ 492 // same names, we can use a shorthand here instead/
491 // we do not want to erase attributes hence this range start 493 // we do not want to erase attributes hence this range start
492 let s = field_name.syntax().text_range().start(); 494 let s = field_name.syntax().text_range().start();
@@ -538,7 +540,7 @@ fn source_edit_from_def(
538mod tests { 540mod tests {
539 use expect_test::{expect, Expect}; 541 use expect_test::{expect, Expect};
540 use stdx::trim_indent; 542 use stdx::trim_indent;
541 use test_utils::{assert_eq_text, mark}; 543 use test_utils::assert_eq_text;
542 use text_edit::TextEdit; 544 use text_edit::TextEdit;
543 545
544 use crate::{fixture, FileId}; 546 use crate::{fixture, FileId};
@@ -627,7 +629,7 @@ mod tests {
627 629
628 #[test] 630 #[test]
629 fn test_rename_to_invalid_identifier_lifetime() { 631 fn test_rename_to_invalid_identifier_lifetime() {
630 mark::check!(rename_not_an_ident_ref); 632 cov_mark::check!(rename_not_an_ident_ref);
631 check( 633 check(
632 "'foo", 634 "'foo",
633 r#"fn main() { let i$0 = 1; }"#, 635 r#"fn main() { let i$0 = 1; }"#,
@@ -637,7 +639,7 @@ mod tests {
637 639
638 #[test] 640 #[test]
639 fn test_rename_to_invalid_identifier_lifetime2() { 641 fn test_rename_to_invalid_identifier_lifetime2() {
640 mark::check!(rename_not_a_lifetime_ident_ref); 642 cov_mark::check!(rename_not_a_lifetime_ident_ref);
641 check( 643 check(
642 "foo", 644 "foo",
643 r#"fn main<'a>(_: &'a$0 ()) {}"#, 645 r#"fn main<'a>(_: &'a$0 ()) {}"#,
@@ -647,7 +649,7 @@ mod tests {
647 649
648 #[test] 650 #[test]
649 fn test_rename_to_underscore_invalid() { 651 fn test_rename_to_underscore_invalid() {
650 mark::check!(rename_underscore_multiple); 652 cov_mark::check!(rename_underscore_multiple);
651 check( 653 check(
652 "_", 654 "_",
653 r#"fn main(foo$0: ()) {foo;}"#, 655 r#"fn main(foo$0: ()) {foo;}"#,
@@ -666,7 +668,7 @@ mod tests {
666 668
667 #[test] 669 #[test]
668 fn test_rename_for_local() { 670 fn test_rename_for_local() {
669 mark::check!(rename_ident); 671 cov_mark::check!(rename_ident);
670 check( 672 check(
671 "k", 673 "k",
672 r#" 674 r#"
@@ -829,7 +831,7 @@ impl Foo {
829 831
830 #[test] 832 #[test]
831 fn test_rename_field_in_field_shorthand() { 833 fn test_rename_field_in_field_shorthand() {
832 mark::check!(test_rename_field_in_field_shorthand); 834 cov_mark::check!(test_rename_field_in_field_shorthand);
833 check( 835 check(
834 "j", 836 "j",
835 r#" 837 r#"
@@ -855,7 +857,7 @@ impl Foo {
855 857
856 #[test] 858 #[test]
857 fn test_rename_local_in_field_shorthand() { 859 fn test_rename_local_in_field_shorthand() {
858 mark::check!(test_rename_local_in_field_shorthand); 860 cov_mark::check!(test_rename_local_in_field_shorthand);
859 check( 861 check(
860 "j", 862 "j",
861 r#" 863 r#"
@@ -1261,7 +1263,7 @@ fn foo(f: foo::Foo) {
1261 1263
1262 #[test] 1264 #[test]
1263 fn test_parameter_to_self() { 1265 fn test_parameter_to_self() {
1264 mark::check!(rename_to_self); 1266 cov_mark::check!(rename_to_self);
1265 check( 1267 check(
1266 "self", 1268 "self",
1267 r#" 1269 r#"
@@ -1401,7 +1403,7 @@ impl Foo {
1401 1403
1402 #[test] 1404 #[test]
1403 fn test_owned_self_to_parameter() { 1405 fn test_owned_self_to_parameter() {
1404 mark::check!(rename_self_to_param); 1406 cov_mark::check!(rename_self_to_param);
1405 check( 1407 check(
1406 "foo", 1408 "foo",
1407 r#" 1409 r#"
@@ -1454,7 +1456,7 @@ impl Foo {
1454 1456
1455 #[test] 1457 #[test]
1456 fn test_rename_field_put_init_shorthand() { 1458 fn test_rename_field_put_init_shorthand() {
1457 mark::check!(test_rename_field_put_init_shorthand); 1459 cov_mark::check!(test_rename_field_put_init_shorthand);
1458 check( 1460 check(
1459 "bar", 1461 "bar",
1460 r#" 1462 r#"
@@ -1476,7 +1478,7 @@ fn foo(bar: i32) -> Foo {
1476 1478
1477 #[test] 1479 #[test]
1478 fn test_rename_local_put_init_shorthand() { 1480 fn test_rename_local_put_init_shorthand() {
1479 mark::check!(test_rename_local_put_init_shorthand); 1481 cov_mark::check!(test_rename_local_put_init_shorthand);
1480 check( 1482 check(
1481 "i", 1483 "i",
1482 r#" 1484 r#"
@@ -1498,7 +1500,7 @@ fn foo(i: i32) -> Foo {
1498 1500
1499 #[test] 1501 #[test]
1500 fn test_struct_field_pat_into_shorthand() { 1502 fn test_struct_field_pat_into_shorthand() {
1501 mark::check!(test_rename_field_put_init_shorthand_pat); 1503 cov_mark::check!(test_rename_field_put_init_shorthand_pat);
1502 check( 1504 check(
1503 "baz", 1505 "baz",
1504 r#" 1506 r#"
@@ -1610,7 +1612,7 @@ fn foo(foo: Foo) {
1610 1612
1611 #[test] 1613 #[test]
1612 fn test_rename_lifetimes() { 1614 fn test_rename_lifetimes() {
1613 mark::check!(rename_lifetime); 1615 cov_mark::check!(rename_lifetime);
1614 check( 1616 check(
1615 "'yeeee", 1617 "'yeeee",
1616 r#" 1618 r#"
@@ -1698,7 +1700,7 @@ fn foo<'a>() -> &'a () {
1698 1700
1699 #[test] 1701 #[test]
1700 fn test_self_to_self() { 1702 fn test_self_to_self() {
1701 mark::check!(rename_self_to_self); 1703 cov_mark::check!(rename_self_to_self);
1702 check( 1704 check(
1703 "self", 1705 "self",
1704 r#" 1706 r#"
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 65f60891e..280565563 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -9,7 +9,6 @@ use syntax::{
9 ast::{self, AstNode, AttrsOwner}, 9 ast::{self, AstNode, AttrsOwner},
10 match_ast, SyntaxNode, 10 match_ast, SyntaxNode,
11}; 11};
12use test_utils::mark;
13 12
14use crate::{ 13use crate::{
15 display::{ToNav, TryToNav}, 14 display::{ToNav, TryToNav},
@@ -130,7 +129,9 @@ fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module
130 if let hir::ModuleDef::Module(submodule) = def { 129 if let hir::ModuleDef::Module(submodule) = def {
131 match submodule.definition_source(sema.db).value { 130 match submodule.definition_source(sema.db).value {
132 hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule), 131 hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule),
133 hir::ModuleSource::SourceFile(_) => mark::hit!(dont_recurse_in_outline_submodules), 132 hir::ModuleSource::SourceFile(_) => {
133 cov_mark::hit!(dont_recurse_in_outline_submodules)
134 }
134 hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable 135 hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable
135 } 136 }
136 } 137 }
@@ -328,7 +329,6 @@ fn has_test_function_or_multiple_test_submodules(
328#[cfg(test)] 329#[cfg(test)]
329mod tests { 330mod tests {
330 use expect_test::{expect, Expect}; 331 use expect_test::{expect, Expect};
331 use test_utils::mark;
332 332
333 use crate::fixture; 333 use crate::fixture;
334 334
@@ -1056,7 +1056,7 @@ mod tests {
1056 1056
1057 #[test] 1057 #[test]
1058 fn dont_recurse_in_outline_submodules() { 1058 fn dont_recurse_in_outline_submodules() {
1059 mark::check!(dont_recurse_in_outline_submodules); 1059 cov_mark::check!(dont_recurse_in_outline_submodules);
1060 check( 1060 check(
1061 r#" 1061 r#"
1062//- /lib.rs 1062//- /lib.rs
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 63cd51b69..978c479de 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -9,7 +9,7 @@ use syntax::{
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxToken, TextRange, TextSize, TokenAtOffset, 10 SyntaxToken, TextRange, TextSize, TokenAtOffset,
11}; 11};
12use test_utils::mark; 12
13use text_edit::TextEdit; 13use text_edit::TextEdit;
14 14
15// Feature: On Enter 15// Feature: On Enter
@@ -55,7 +55,7 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
55 // Continuing single-line non-doc comments (like this one :) ) is annoying 55 // Continuing single-line non-doc comments (like this one :) ) is annoying
56 if prefix == "//" && comment_range.end() == position.offset { 56 if prefix == "//" && comment_range.end() == position.offset {
57 if comment.text().ends_with(' ') { 57 if comment.text().ends_with(' ') {
58 mark::hit!(continues_end_of_line_comment_with_space); 58 cov_mark::hit!(continues_end_of_line_comment_with_space);
59 remove_trailing_whitespace = true; 59 remove_trailing_whitespace = true;
60 } else if !followed_by_comment(&comment) { 60 } else if !followed_by_comment(&comment) {
61 return None; 61 return None;
@@ -109,7 +109,7 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> {
109#[cfg(test)] 109#[cfg(test)]
110mod tests { 110mod tests {
111 use stdx::trim_indent; 111 use stdx::trim_indent;
112 use test_utils::{assert_eq_text, mark}; 112 use test_utils::assert_eq_text;
113 113
114 use crate::fixture; 114 use crate::fixture;
115 115
@@ -238,7 +238,7 @@ fn main() {
238 238
239 #[test] 239 #[test]
240 fn continues_end_of_line_comment_with_space() { 240 fn continues_end_of_line_comment_with_space() {
241 mark::check!(continues_end_of_line_comment_with_space); 241 cov_mark::check!(continues_end_of_line_comment_with_space);
242 do_check( 242 do_check(
243 r#" 243 r#"
244fn main() { 244fn main() {
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index a34bdd6c3..3bf0099a9 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1"
13rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
14itertools = "0.10.0" 15itertools = "0.10.0"
15either = "1.6.1" 16either = "1.6.1"
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs
index a08b55ebb..3b6efbab4 100644
--- a/crates/ide_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs
@@ -1,6 +1,5 @@
1use ide_db::defs::{Definition, NameRefClass}; 1use ide_db::defs::{Definition, NameRefClass};
2use syntax::{ast, AstNode, SyntaxKind, T}; 2use syntax::{ast, AstNode, SyntaxKind, T};
3use test_utils::mark;
4 3
5use crate::{ 4use crate::{
6 assist_context::{AssistContext, Assists}, 5 assist_context::{AssistContext, Assists},
@@ -30,13 +29,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
30 if arg_list.args().count() > 0 { 29 if arg_list.args().count() > 0 {
31 return None; 30 return None;
32 } 31 }
33 mark::hit!(add_turbo_fish_after_call); 32 cov_mark::hit!(add_turbo_fish_after_call);
34 mark::hit!(add_type_ascription_after_call); 33 cov_mark::hit!(add_type_ascription_after_call);
35 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) 34 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
36 })?; 35 })?;
37 let next_token = ident.next_token()?; 36 let next_token = ident.next_token()?;
38 if next_token.kind() == T![::] { 37 if next_token.kind() == T![::] {
39 mark::hit!(add_turbo_fish_one_fish_is_enough); 38 cov_mark::hit!(add_turbo_fish_one_fish_is_enough);
40 return None; 39 return None;
41 } 40 }
42 let name_ref = ast::NameRef::cast(ident.parent())?; 41 let name_ref = ast::NameRef::cast(ident.parent())?;
@@ -50,7 +49,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
50 }; 49 };
51 let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); 50 let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
52 if generics.is_empty() { 51 if generics.is_empty() {
53 mark::hit!(add_turbo_fish_non_generic); 52 cov_mark::hit!(add_turbo_fish_non_generic);
54 return None; 53 return None;
55 } 54 }
56 55
@@ -67,7 +66,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
67 }, 66 },
68 )? 67 )?
69 } else { 68 } else {
70 mark::hit!(add_type_ascription_already_typed); 69 cov_mark::hit!(add_type_ascription_already_typed);
71 } 70 }
72 } 71 }
73 72
@@ -87,7 +86,6 @@ mod tests {
87 use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; 86 use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};
88 87
89 use super::*; 88 use super::*;
90 use test_utils::mark;
91 89
92 #[test] 90 #[test]
93 fn add_turbo_fish_function() { 91 fn add_turbo_fish_function() {
@@ -110,7 +108,7 @@ fn main() {
110 108
111 #[test] 109 #[test]
112 fn add_turbo_fish_after_call() { 110 fn add_turbo_fish_after_call() {
113 mark::check!(add_turbo_fish_after_call); 111 cov_mark::check!(add_turbo_fish_after_call);
114 check_assist( 112 check_assist(
115 add_turbo_fish, 113 add_turbo_fish,
116 r#" 114 r#"
@@ -155,7 +153,7 @@ fn main() {
155 153
156 #[test] 154 #[test]
157 fn add_turbo_fish_one_fish_is_enough() { 155 fn add_turbo_fish_one_fish_is_enough() {
158 mark::check!(add_turbo_fish_one_fish_is_enough); 156 cov_mark::check!(add_turbo_fish_one_fish_is_enough);
159 check_assist_not_applicable( 157 check_assist_not_applicable(
160 add_turbo_fish, 158 add_turbo_fish,
161 r#" 159 r#"
@@ -169,7 +167,7 @@ fn main() {
169 167
170 #[test] 168 #[test]
171 fn add_turbo_fish_non_generic() { 169 fn add_turbo_fish_non_generic() {
172 mark::check!(add_turbo_fish_non_generic); 170 cov_mark::check!(add_turbo_fish_non_generic);
173 check_assist_not_applicable( 171 check_assist_not_applicable(
174 add_turbo_fish, 172 add_turbo_fish,
175 r#" 173 r#"
@@ -203,7 +201,7 @@ fn main() {
203 201
204 #[test] 202 #[test]
205 fn add_type_ascription_after_call() { 203 fn add_type_ascription_after_call() {
206 mark::check!(add_type_ascription_after_call); 204 cov_mark::check!(add_type_ascription_after_call);
207 check_assist_by_label( 205 check_assist_by_label(
208 add_turbo_fish, 206 add_turbo_fish,
209 r#" 207 r#"
@@ -250,7 +248,7 @@ fn main() {
250 248
251 #[test] 249 #[test]
252 fn add_type_ascription_already_typed() { 250 fn add_type_ascription_already_typed() {
253 mark::check!(add_type_ascription_already_typed); 251 cov_mark::check!(add_type_ascription_already_typed);
254 check_assist( 252 check_assist(
255 add_turbo_fish, 253 add_turbo_fish,
256 r#" 254 r#"
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs
index 128b1eb56..a1c339603 100644
--- a/crates/ide_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ide_assists/src/handlers/apply_demorgan.rs
@@ -1,5 +1,4 @@
1use syntax::ast::{self, AstNode}; 1use syntax::ast::{self, AstNode};
2use test_utils::mark;
3 2
4use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; 3use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
5 4
@@ -64,10 +63,10 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<(
64 edit.replace(lhs_range, not_lhs.syntax().text()); 63 edit.replace(lhs_range, not_lhs.syntax().text());
65 edit.replace(rhs_range, not_rhs.syntax().text()); 64 edit.replace(rhs_range, not_rhs.syntax().text());
66 if let Some(neg_expr) = neg_expr { 65 if let Some(neg_expr) = neg_expr {
67 mark::hit!(demorgan_double_negation); 66 cov_mark::hit!(demorgan_double_negation);
68 edit.replace(neg_expr.op_token().unwrap().text_range(), ""); 67 edit.replace(neg_expr.op_token().unwrap().text_range(), "");
69 } else { 68 } else {
70 mark::hit!(demorgan_double_parens); 69 cov_mark::hit!(demorgan_double_parens);
71 edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!("); 70 edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!(");
72 } 71 }
73 } else { 72 } else {
@@ -90,7 +89,6 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
90#[cfg(test)] 89#[cfg(test)]
91mod tests { 90mod tests {
92 use ide_db::helpers::FamousDefs; 91 use ide_db::helpers::FamousDefs;
93 use test_utils::mark;
94 92
95 use super::*; 93 use super::*;
96 94
@@ -188,13 +186,13 @@ fn f() {
188 186
189 #[test] 187 #[test]
190 fn demorgan_doesnt_double_negation() { 188 fn demorgan_doesnt_double_negation() {
191 mark::check!(demorgan_double_negation); 189 cov_mark::check!(demorgan_double_negation);
192 check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }") 190 check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }")
193 } 191 }
194 192
195 #[test] 193 #[test]
196 fn demorgan_doesnt_double_parens() { 194 fn demorgan_doesnt_double_parens() {
197 mark::check!(demorgan_double_parens); 195 cov_mark::check!(demorgan_double_parens);
198 check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }") 196 check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
199 } 197 }
200} 198}
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 1422224ac..7caee8df0 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -1,7 +1,7 @@
1use ide_db::helpers::{ 1use ide_db::helpers::{
2 import_assets::{ImportAssets, ImportCandidate}, 2 import_assets::{ImportAssets, ImportCandidate},
3 insert_use::{insert_use, ImportScope}, 3 insert_use::{insert_use, ImportScope},
4 mod_path_to_ast, 4 item_name, mod_path_to_ast,
5}; 5};
6use syntax::{ast, AstNode, SyntaxNode}; 6use syntax::{ast, AstNode, SyntaxNode};
7 7
@@ -92,14 +92,19 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
92 let range = ctx.sema.original_range(&syntax_under_caret).range; 92 let range = ctx.sema.original_range(&syntax_under_caret).range;
93 let group = import_group_message(import_assets.import_candidate()); 93 let group = import_group_message(import_assets.import_candidate());
94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; 94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
95 for (import, _) in proposed_imports { 95 for import in proposed_imports {
96 let name = match item_name(ctx.db(), import.original_item) {
97 Some(name) => name,
98 None => continue,
99 };
96 acc.add_group( 100 acc.add_group(
97 &group, 101 &group,
98 AssistId("auto_import", AssistKind::QuickFix), 102 AssistId("auto_import", AssistKind::QuickFix),
99 format!("Import `{}`", &import), 103 format!("Import `{}`", name),
100 range, 104 range,
101 |builder| { 105 |builder| {
102 let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use); 106 let rewriter =
107 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
103 builder.rewrite(rewriter); 108 builder.rewrite(rewriter);
104 }, 109 },
105 ); 110 );
@@ -125,10 +130,10 @@ fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel {
125 let name = match import_candidate { 130 let name = match import_candidate {
126 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), 131 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
127 ImportCandidate::TraitAssocItem(candidate) => { 132 ImportCandidate::TraitAssocItem(candidate) => {
128 format!("Import a trait for item {}", candidate.name.text()) 133 format!("Import a trait for item {}", candidate.assoc_item_name.text())
129 } 134 }
130 ImportCandidate::TraitMethod(candidate) => { 135 ImportCandidate::TraitMethod(candidate) => {
131 format!("Import a trait for method {}", candidate.name.text()) 136 format!("Import a trait for method {}", candidate.assoc_item_name.text())
132 } 137 }
133 }; 138 };
134 GroupLabel(name) 139 GroupLabel(name)
@@ -221,41 +226,6 @@ mod tests {
221 } 226 }
222 227
223 #[test] 228 #[test]
224 fn auto_imports_are_merged() {
225 check_assist(
226 auto_import,
227 r"
228 use PubMod::PubStruct1;
229
230 struct Test {
231 test: Pub$0Struct2<u8>,
232 }
233
234 pub mod PubMod {
235 pub struct PubStruct1;
236 pub struct PubStruct2<T> {
237 _t: T,
238 }
239 }
240 ",
241 r"
242 use PubMod::{PubStruct1, PubStruct2};
243
244 struct Test {
245 test: PubStruct2<u8>,
246 }
247
248 pub mod PubMod {
249 pub struct PubStruct1;
250 pub struct PubStruct2<T> {
251 _t: T,
252 }
253 }
254 ",
255 );
256 }
257
258 #[test]
259 fn applicable_when_found_multiple_imports() { 229 fn applicable_when_found_multiple_imports() {
260 check_assist( 230 check_assist(
261 auto_import, 231 auto_import,
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs
index ac8c44124..ec99a5505 100644
--- a/crates/ide_assists/src/handlers/change_visibility.rs
+++ b/crates/ide_assists/src/handlers/change_visibility.rs
@@ -4,7 +4,6 @@ use syntax::{
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, 4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY},
5 T, 5 T,
6}; 6};
7use test_utils::mark;
8 7
9use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; 8use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
10 9
@@ -56,7 +55,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
56 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { 55 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
57 let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?; 56 let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?;
58 if field.name()? != field_name { 57 if field.name()? != field_name {
59 mark::hit!(change_visibility_field_false_positive); 58 cov_mark::hit!(change_visibility_field_false_positive);
60 return None; 59 return None;
61 } 60 }
62 if field.visibility().is_some() { 61 if field.visibility().is_some() {
@@ -110,8 +109,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
110 109
111#[cfg(test)] 110#[cfg(test)]
112mod tests { 111mod tests {
113 use test_utils::mark;
114
115 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 112 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
116 113
117 use super::*; 114 use super::*;
@@ -139,7 +136,7 @@ mod tests {
139 136
140 #[test] 137 #[test]
141 fn change_visibility_field_false_positive() { 138 fn change_visibility_field_false_positive() {
142 mark::check!(change_visibility_field_false_positive); 139 cov_mark::check!(change_visibility_field_false_positive);
143 check_assist_not_applicable( 140 check_assist_not_applicable(
144 change_visibility, 141 change_visibility,
145 r"struct S { field: [(); { let $0x = ();}] }", 142 r"struct S { field: [(); { let $0x = ();}] }",
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 8779d8bd1..dd4501709 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -20,7 +20,6 @@ use syntax::{
20 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, 20 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR},
21 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, 21 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
22}; 22};
23use test_utils::mark;
24 23
25use crate::{ 24use crate::{
26 assist_context::{AssistContext, Assists}, 25 assist_context::{AssistContext, Assists},
@@ -59,7 +58,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
59 58
60 let node = ctx.covering_element(); 59 let node = ctx.covering_element();
61 if node.kind() == COMMENT { 60 if node.kind() == COMMENT {
62 mark::hit!(extract_function_in_comment_is_not_applicable); 61 cov_mark::hit!(extract_function_in_comment_is_not_applicable);
63 return None; 62 return None;
64 } 63 }
65 64
@@ -197,14 +196,14 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con
197 if let Some(kind) = expr_err_kind(&expr, ctx) { 196 if let Some(kind) = expr_err_kind(&expr, ctx) {
198 Some(FlowKind::TryReturn { expr, kind }) 197 Some(FlowKind::TryReturn { expr, kind })
199 } else { 198 } else {
200 mark::hit!(external_control_flow_try_and_return_non_err); 199 cov_mark::hit!(external_control_flow_try_and_return_non_err);
201 return None; 200 return None;
202 } 201 }
203 } 202 }
204 None => return None, 203 None => return None,
205 }, 204 },
206 (Some(_), _, _, _) => { 205 (Some(_), _, _, _) => {
207 mark::hit!(external_control_flow_try_and_bc); 206 cov_mark::hit!(external_control_flow_try_and_bc);
208 return None; 207 return None;
209 } 208 }
210 (None, Some(r), None, None) => match r.expr() { 209 (None, Some(r), None, None) => match r.expr() {
@@ -212,11 +211,11 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con
212 None => Some(FlowKind::Return), 211 None => Some(FlowKind::Return),
213 }, 212 },
214 (None, Some(_), _, _) => { 213 (None, Some(_), _, _) => {
215 mark::hit!(external_control_flow_return_and_bc); 214 cov_mark::hit!(external_control_flow_return_and_bc);
216 return None; 215 return None;
217 } 216 }
218 (None, None, Some(_), Some(_)) => { 217 (None, None, Some(_), Some(_)) => {
219 mark::hit!(external_control_flow_break_and_continue); 218 cov_mark::hit!(external_control_flow_break_and_continue);
220 return None; 219 return None;
221 } 220 }
222 (None, None, Some(b), None) => match b.expr() { 221 (None, None, Some(b), None) => match b.expr() {
@@ -1837,7 +1836,7 @@ fn $0fun_name(n: u32) -> u32 {
1837 1836
1838 #[test] 1837 #[test]
1839 fn in_comment_is_not_applicable() { 1838 fn in_comment_is_not_applicable() {
1840 mark::check!(extract_function_in_comment_is_not_applicable); 1839 cov_mark::check!(extract_function_in_comment_is_not_applicable);
1841 check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }"); 1840 check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }");
1842 } 1841 }
1843 1842
@@ -2822,7 +2821,7 @@ fn $0fun_name(n: i32) -> Result<i32, i64> {
2822 2821
2823 #[test] 2822 #[test]
2824 fn break_and_continue() { 2823 fn break_and_continue() {
2825 mark::check!(external_control_flow_break_and_continue); 2824 cov_mark::check!(external_control_flow_break_and_continue);
2826 check_assist_not_applicable( 2825 check_assist_not_applicable(
2827 extract_function, 2826 extract_function,
2828 r##" 2827 r##"
@@ -2842,7 +2841,7 @@ fn foo() {
2842 2841
2843 #[test] 2842 #[test]
2844 fn return_and_break() { 2843 fn return_and_break() {
2845 mark::check!(external_control_flow_return_and_bc); 2844 cov_mark::check!(external_control_flow_return_and_bc);
2846 check_assist_not_applicable( 2845 check_assist_not_applicable(
2847 extract_function, 2846 extract_function,
2848 r##" 2847 r##"
@@ -3341,7 +3340,7 @@ fn $0fun_name() -> Result<i32, i64> {
3341 3340
3342 #[test] 3341 #[test]
3343 fn try_and_break() { 3342 fn try_and_break() {
3344 mark::check!(external_control_flow_try_and_bc); 3343 cov_mark::check!(external_control_flow_try_and_bc);
3345 check_assist_not_applicable( 3344 check_assist_not_applicable(
3346 extract_function, 3345 extract_function,
3347 r##" 3346 r##"
@@ -3363,7 +3362,7 @@ fn foo() -> Option<()> {
3363 3362
3364 #[test] 3363 #[test]
3365 fn try_and_return_ok() { 3364 fn try_and_return_ok() {
3366 mark::check!(external_control_flow_try_and_return_non_err); 3365 cov_mark::check!(external_control_flow_try_and_return_non_err);
3367 check_assist_not_applicable( 3366 check_assist_not_applicable(
3368 extract_function, 3367 extract_function,
3369 r##" 3368 r##"
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 4f0422e96..335e0ed95 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,7 +1,7 @@
1use std::iter; 1use std::iter;
2 2
3use either::Either; 3use either::Either;
4use hir::{AsName, Module, ModuleDef, Name, Variant}; 4use hir::{Module, ModuleDef, Name, Variant};
5use ide_db::{ 5use ide_db::{
6 defs::Definition, 6 defs::Definition,
7 helpers::{ 7 helpers::{
@@ -133,7 +133,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
133 ), 133 ),
134 _ => false, 134 _ => false,
135 }) 135 })
136 .any(|(name, _)| name == variant_name.as_name()) 136 .any(|(name, _)| name.to_string() == variant_name.to_string())
137} 137}
138 138
139fn insert_import( 139fn insert_import(
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs
index 312ac7ac4..7a32483dc 100644
--- a/crates/ide_assists/src/handlers/extract_variable.rs
+++ b/crates/ide_assists/src/handlers/extract_variable.rs
@@ -6,7 +6,6 @@ use syntax::{
6 }, 6 },
7 SyntaxNode, 7 SyntaxNode,
8}; 8};
9use test_utils::mark;
10 9
11use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; 10use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
12 11
@@ -32,7 +31,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
32 } 31 }
33 let node = ctx.covering_element(); 32 let node = ctx.covering_element();
34 if node.kind() == COMMENT { 33 if node.kind() == COMMENT {
35 mark::hit!(extract_var_in_comment_is_not_applicable); 34 cov_mark::hit!(extract_var_in_comment_is_not_applicable);
36 return None; 35 return None;
37 } 36 }
38 let to_extract = node.ancestors().find_map(valid_target_expr)?; 37 let to_extract = node.ancestors().find_map(valid_target_expr)?;
@@ -69,7 +68,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
69 format_to!(buf, "{}", to_extract.syntax()); 68 format_to!(buf, "{}", to_extract.syntax());
70 69
71 if let Anchor::Replace(stmt) = anchor { 70 if let Anchor::Replace(stmt) = anchor {
72 mark::hit!(test_extract_var_expr_stmt); 71 cov_mark::hit!(test_extract_var_expr_stmt);
73 if stmt.semicolon_token().is_none() { 72 if stmt.semicolon_token().is_none() {
74 buf.push_str(";"); 73 buf.push_str(";");
75 } 74 }
@@ -142,7 +141,7 @@ impl Anchor {
142 node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) 141 node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr())
143 { 142 {
144 if expr.syntax() == &node { 143 if expr.syntax() == &node {
145 mark::hit!(test_extract_var_last_expr); 144 cov_mark::hit!(test_extract_var_last_expr);
146 return Some(Anchor::Before(node)); 145 return Some(Anchor::Before(node));
147 } 146 }
148 } 147 }
@@ -175,8 +174,6 @@ impl Anchor {
175 174
176#[cfg(test)] 175#[cfg(test)]
177mod tests { 176mod tests {
178 use test_utils::mark;
179
180 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 177 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
181 178
182 use super::*; 179 use super::*;
@@ -199,13 +196,13 @@ fn foo() {
199 196
200 #[test] 197 #[test]
201 fn extract_var_in_comment_is_not_applicable() { 198 fn extract_var_in_comment_is_not_applicable() {
202 mark::check!(extract_var_in_comment_is_not_applicable); 199 cov_mark::check!(extract_var_in_comment_is_not_applicable);
203 check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }"); 200 check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }");
204 } 201 }
205 202
206 #[test] 203 #[test]
207 fn test_extract_var_expr_stmt() { 204 fn test_extract_var_expr_stmt() {
208 mark::check!(test_extract_var_expr_stmt); 205 cov_mark::check!(test_extract_var_expr_stmt);
209 check_assist( 206 check_assist(
210 extract_variable, 207 extract_variable,
211 r#" 208 r#"
@@ -250,7 +247,7 @@ fn foo() {
250 247
251 #[test] 248 #[test]
252 fn test_extract_var_last_expr() { 249 fn test_extract_var_last_expr() {
253 mark::check!(test_extract_var_last_expr); 250 cov_mark::check!(test_extract_var_last_expr);
254 check_assist( 251 check_assist(
255 extract_variable, 252 extract_variable,
256 r#" 253 r#"
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs
index 7086e47d2..878b3a3fa 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -5,7 +5,6 @@ use ide_db::helpers::{mod_path_to_ast, FamousDefs};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use itertools::Itertools; 6use itertools::Itertools;
7use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 7use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
8use test_utils::mark;
9 8
10use crate::{ 9use crate::{
11 utils::{does_pat_match_variant, render_snippet, Cursor}, 10 utils::{does_pat_match_variant, render_snippet, Cursor},
@@ -62,7 +61,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
62 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
63 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() { 62 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() {
64 // Match `Some` variant first. 63 // Match `Some` variant first.
65 mark::hit!(option_order); 64 cov_mark::hit!(option_order);
66 variants.reverse() 65 variants.reverse()
67 } 66 }
68 variants 67 variants
@@ -195,7 +194,6 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio
195#[cfg(test)] 194#[cfg(test)]
196mod tests { 195mod tests {
197 use ide_db::helpers::FamousDefs; 196 use ide_db::helpers::FamousDefs;
198 use test_utils::mark;
199 197
200 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 198 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
201 199
@@ -730,7 +728,7 @@ fn main() {
730 728
731 #[test] 729 #[test]
732 fn option_order() { 730 fn option_order() {
733 mark::check!(option_order); 731 cov_mark::check!(option_order);
734 let before = r#" 732 let before = r#"
735fn foo(opt: Option<i32>) { 733fn foo(opt: Option<i32>) {
736 match opt$0 { 734 match opt$0 {
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
index 6a2ab9596..588ee1350 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
@@ -1,7 +1,6 @@
1use ide_db::helpers::FamousDefs; 1use ide_db::helpers::FamousDefs;
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5 4
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
7 6
@@ -38,12 +37,12 @@ pub(crate) fn generate_default_from_enum_variant(
38 let variant_name = variant.name()?; 37 let variant_name = variant.name()?;
39 let enum_name = variant.parent_enum().name()?; 38 let enum_name = variant.parent_enum().name()?;
40 if !matches!(variant.kind(), ast::StructKind::Unit) { 39 if !matches!(variant.kind(), ast::StructKind::Unit) {
41 mark::hit!(test_gen_default_on_non_unit_variant_not_implemented); 40 cov_mark::hit!(test_gen_default_on_non_unit_variant_not_implemented);
42 return None; 41 return None;
43 } 42 }
44 43
45 if existing_default_impl(&ctx.sema, &variant).is_some() { 44 if existing_default_impl(&ctx.sema, &variant).is_some() {
46 mark::hit!(test_gen_default_impl_already_exists); 45 cov_mark::hit!(test_gen_default_impl_already_exists);
47 return None; 46 return None;
48 } 47 }
49 48
@@ -89,8 +88,6 @@ fn existing_default_impl(
89 88
90#[cfg(test)] 89#[cfg(test)]
91mod tests { 90mod tests {
92 use test_utils::mark;
93
94 use crate::tests::{check_assist, check_assist_not_applicable}; 91 use crate::tests::{check_assist, check_assist_not_applicable};
95 92
96 use super::*; 93 use super::*;
@@ -127,7 +124,7 @@ impl Default for Variant {
127 124
128 #[test] 125 #[test]
129 fn test_generate_default_already_implemented() { 126 fn test_generate_default_already_implemented() {
130 mark::check!(test_gen_default_impl_already_exists); 127 cov_mark::check!(test_gen_default_impl_already_exists);
131 check_not_applicable( 128 check_not_applicable(
132 r#" 129 r#"
133enum Variant { 130enum Variant {
@@ -146,7 +143,7 @@ impl Default for Variant {
146 143
147 #[test] 144 #[test]
148 fn test_add_from_impl_no_element() { 145 fn test_add_from_impl_no_element() {
149 mark::check!(test_gen_default_on_non_unit_variant_not_implemented); 146 cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented);
150 check_not_applicable( 147 check_not_applicable(
151 r#" 148 r#"
152enum Variant { 149enum Variant {
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index fa1254579..81c54ba3e 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -7,7 +7,6 @@ use syntax::{
7 ast::{self, Impl, NameOwner}, 7 ast::{self, Impl, NameOwner},
8 AstNode, 8 AstNode,
9}; 9};
10use test_utils::mark;
11 10
12// Assist: generate_default_from_new 11// Assist: generate_default_from_new
13// 12//
@@ -43,19 +42,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext)
43 let fn_name = fn_node.name()?; 42 let fn_name = fn_node.name()?;
44 43
45 if fn_name.text() != "new" { 44 if fn_name.text() != "new" {
46 mark::hit!(other_function_than_new); 45 cov_mark::hit!(other_function_than_new);
47 return None; 46 return None;
48 } 47 }
49 48
50 if fn_node.param_list()?.params().next().is_some() { 49 if fn_node.param_list()?.params().next().is_some() {
51 mark::hit!(new_function_with_parameters); 50 cov_mark::hit!(new_function_with_parameters);
52 return None; 51 return None;
53 } 52 }
54 53
55 let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; 54 let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
56 if is_default_implemented(ctx, &impl_) { 55 if is_default_implemented(ctx, &impl_) {
57 mark::hit!(default_block_is_already_present); 56 cov_mark::hit!(default_block_is_already_present);
58 mark::hit!(struct_in_module_with_default); 57 cov_mark::hit!(struct_in_module_with_default);
59 return None; 58 return None;
60 } 59 }
61 60
@@ -178,7 +177,7 @@ impl Default for Test {
178 177
179 #[test] 178 #[test]
180 fn new_function_with_parameters() { 179 fn new_function_with_parameters() {
181 mark::check!(new_function_with_parameters); 180 cov_mark::check!(new_function_with_parameters);
182 check_not_applicable( 181 check_not_applicable(
183 r#" 182 r#"
184struct Example { _inner: () } 183struct Example { _inner: () }
@@ -194,7 +193,7 @@ impl Example {
194 193
195 #[test] 194 #[test]
196 fn other_function_than_new() { 195 fn other_function_than_new() {
197 mark::check!(other_function_than_new); 196 cov_mark::check!(other_function_than_new);
198 check_not_applicable( 197 check_not_applicable(
199 r#" 198 r#"
200struct Example { _inner: () } 199struct Example { _inner: () }
@@ -211,7 +210,7 @@ impl Example {
211 210
212 #[test] 211 #[test]
213 fn default_block_is_already_present() { 212 fn default_block_is_already_present() {
214 mark::check!(default_block_is_already_present); 213 cov_mark::check!(default_block_is_already_present);
215 check_not_applicable( 214 check_not_applicable(
216 r#" 215 r#"
217struct Example { _inner: () } 216struct Example { _inner: () }
@@ -340,7 +339,7 @@ impl Default for Example {
340 339
341 #[test] 340 #[test]
342 fn struct_in_module_with_default() { 341 fn struct_in_module_with_default() {
343 mark::check!(struct_in_module_with_default); 342 cov_mark::check!(struct_in_module_with_default);
344 check_not_applicable( 343 check_not_applicable(
345 r#" 344 r#"
346mod test { 345mod test {
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
index d9388a737..c13c6eebe 100644
--- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -1,7 +1,6 @@
1use ide_db::helpers::FamousDefs; 1use ide_db::helpers::FamousDefs;
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5 4
6use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; 5use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
7 6
@@ -44,7 +43,7 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext
44 }; 43 };
45 44
46 if existing_from_impl(&ctx.sema, &variant).is_some() { 45 if existing_from_impl(&ctx.sema, &variant).is_some() {
47 mark::hit!(test_add_from_impl_already_exists); 46 cov_mark::hit!(test_add_from_impl_already_exists);
48 return None; 47 return None;
49 } 48 }
50 49
@@ -103,8 +102,6 @@ fn existing_from_impl(
103 102
104#[cfg(test)] 103#[cfg(test)]
105mod tests { 104mod tests {
106 use test_utils::mark;
107
108 use crate::tests::{check_assist, check_assist_not_applicable}; 105 use crate::tests::{check_assist, check_assist_not_applicable};
109 106
110 use super::*; 107 use super::*;
@@ -172,7 +169,7 @@ impl From<u32> for A {
172 169
173 #[test] 170 #[test]
174 fn test_add_from_impl_already_exists() { 171 fn test_add_from_impl_already_exists() {
175 mark::check!(test_add_from_impl_already_exists); 172 cov_mark::check!(test_add_from_impl_already_exists);
176 check_not_applicable( 173 check_not_applicable(
177 r#" 174 r#"
178enum A { $0One(u32), } 175enum A { $0One(u32), }
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 3870b7e75..6f95b1a07 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -83,17 +83,18 @@ struct FunctionTemplate {
83 leading_ws: String, 83 leading_ws: String,
84 fn_def: ast::Fn, 84 fn_def: ast::Fn,
85 ret_type: ast::RetType, 85 ret_type: ast::RetType,
86 should_render_snippet: bool,
86 trailing_ws: String, 87 trailing_ws: String,
87 file: FileId, 88 file: FileId,
88} 89}
89 90
90impl FunctionTemplate { 91impl FunctionTemplate {
91 fn to_string(&self, cap: Option<SnippetCap>) -> String { 92 fn to_string(&self, cap: Option<SnippetCap>) -> String {
92 let f = match cap { 93 let f = match (cap, self.should_render_snippet) {
93 Some(cap) => { 94 (Some(cap), true) => {
94 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) 95 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax()))
95 } 96 }
96 None => self.fn_def.to_string(), 97 _ => self.fn_def.to_string(),
97 }; 98 };
98 format!("{}{}{}", self.leading_ws, f, self.trailing_ws) 99 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
99 } 100 }
@@ -104,6 +105,8 @@ struct FunctionBuilder {
104 fn_name: ast::Name, 105 fn_name: ast::Name,
105 type_params: Option<ast::GenericParamList>, 106 type_params: Option<ast::GenericParamList>,
106 params: ast::ParamList, 107 params: ast::ParamList,
108 ret_type: ast::RetType,
109 should_render_snippet: bool,
107 file: FileId, 110 file: FileId,
108 needs_pub: bool, 111 needs_pub: bool,
109} 112}
@@ -132,7 +135,43 @@ impl FunctionBuilder {
132 let fn_name = fn_name(&path)?; 135 let fn_name = fn_name(&path)?;
133 let (type_params, params) = fn_args(ctx, target_module, &call)?; 136 let (type_params, params) = fn_args(ctx, target_module, &call)?;
134 137
135 Some(Self { target, fn_name, type_params, params, file, needs_pub }) 138 // should_render_snippet intends to express a rough level of confidence about
139 // the correctness of the return type.
140 //
141 // If we are able to infer some return type, and that return type is not unit, we
142 // don't want to render the snippet. The assumption here is in this situation the
143 // return type is just as likely to be correct as any other part of the generated
144 // function.
145 //
146 // In the case where the return type is inferred as unit it is likely that the
147 // user does in fact intend for this generated function to return some non unit
148 // type, but that the current state of their code doesn't allow that return type
149 // to be accurately inferred.
150 let (ret_ty, should_render_snippet) = {
151 match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) {
152 Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true),
153 Some(ty) => {
154 let rendered = ty.display_source_code(ctx.db(), target_module.into());
155 match rendered {
156 Ok(rendered) => (make::ty(&rendered), false),
157 Err(_) => (make::ty_unit(), true),
158 }
159 }
160 None => (make::ty_unit(), true),
161 }
162 };
163 let ret_type = make::ret_type(ret_ty);
164
165 Some(Self {
166 target,
167 fn_name,
168 type_params,
169 params,
170 ret_type,
171 should_render_snippet,
172 file,
173 needs_pub,
174 })
136 } 175 }
137 176
138 fn render(self) -> FunctionTemplate { 177 fn render(self) -> FunctionTemplate {
@@ -145,7 +184,7 @@ impl FunctionBuilder {
145 self.type_params, 184 self.type_params,
146 self.params, 185 self.params,
147 fn_body, 186 fn_body,
148 Some(make::ret_type(make::ty_unit())), 187 Some(self.ret_type),
149 ); 188 );
150 let leading_ws; 189 let leading_ws;
151 let trailing_ws; 190 let trailing_ws;
@@ -171,6 +210,7 @@ impl FunctionBuilder {
171 insert_offset, 210 insert_offset,
172 leading_ws, 211 leading_ws,
173 ret_type: fn_def.ret_type().unwrap(), 212 ret_type: fn_def.ret_type().unwrap(),
213 should_render_snippet: self.should_render_snippet,
174 fn_def, 214 fn_def,
175 trailing_ws, 215 trailing_ws,
176 file: self.file, 216 file: self.file,
@@ -546,7 +586,7 @@ impl Baz {
546 } 586 }
547} 587}
548 588
549fn bar(baz: Baz) ${0:-> ()} { 589fn bar(baz: Baz) -> Baz {
550 todo!() 590 todo!()
551} 591}
552", 592",
@@ -1060,6 +1100,27 @@ pub(crate) fn bar() ${0:-> ()} {
1060 } 1100 }
1061 1101
1062 #[test] 1102 #[test]
1103 fn add_function_with_return_type() {
1104 check_assist(
1105 generate_function,
1106 r"
1107fn main() {
1108 let x: u32 = foo$0();
1109}
1110",
1111 r"
1112fn main() {
1113 let x: u32 = foo();
1114}
1115
1116fn foo() -> u32 {
1117 todo!()
1118}
1119",
1120 )
1121 }
1122
1123 #[test]
1063 fn add_function_not_applicable_if_function_already_exists() { 1124 fn add_function_not_applicable_if_function_already_exists() {
1064 check_assist_not_applicable( 1125 check_assist_not_applicable(
1065 generate_function, 1126