diff --git a/Cargo.toml b/Cargo.toml index 05cc53290..c231effd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ -# smoelius: `dylint_driver`, `dylint_linting`, and the library template are in their own workspaces -# because they require specific Rust components. +# smoelius: `dylint_driver`, `dylint_linting`, the library template, and `match_hir` are in their +# own workspaces because they require a nightly toolchain. [workspace] -exclude = ["driver", "internal/template", "utils/linting"] +exclude = ["driver", "internal/template", "match_hir", "utils/linting"] members = [ "cargo-dylint", "dylint", diff --git a/examples/experimental/disallowed_pattern/.cargo/config.toml b/examples/experimental/disallowed_pattern/.cargo/config.toml new file mode 100644 index 000000000..4f8093829 --- /dev/null +++ b/examples/experimental/disallowed_pattern/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target-dir = "../../../target/examples" + +[target.'cfg(all())'] +linker = "dylint-link" diff --git a/examples/experimental/disallowed_pattern/Cargo.lock b/examples/experimental/disallowed_pattern/Cargo.lock new file mode 100644 index 000000000..b0941f07b --- /dev/null +++ b/examples/experimental/disallowed_pattern/Cargo.lock @@ -0,0 +1,1503 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "camino" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8abf5d501fd757c2d2ee78d0cc40f606e92e3a63544420316565556ed28485e2" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.16", +] + +[[package]] +name = "cc" +version = "1.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clippy_utils" +version = "0.1.89" +source = "git+https://github.com/rust-lang/rust-clippy?rev=0450db33a5d8587f7c1d4b6d233dac963605766b#0450db33a5d8587f7c1d4b6d233dac963605766b" +dependencies = [ + "arrayvec", + "itertools", + "rustc_apfloat", + "serde", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "compiletest_rs" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f150fe9105fcd2a57cad53f0c079a24de65195903ef670990f5909f695eac04c" +dependencies = [ + "diff", + "filetime", + "getopts", + "lazy_static", + "libc", + "log", + "miow", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tester", + "windows-sys 0.59.0", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "disallowed_pattern" +version = "4.0.0" +dependencies = [ + "anyhow", + "clippy_utils", + "dylint_internal", + "dylint_linting", + "dylint_testing", + "libloading", + "match_hir", + "paste", + "quote", + "serde", + "syn", + "tempfile", + "toml", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dylint" +version = "5.0.0" +dependencies = [ + "anstyle", + "anyhow", + "cargo_metadata", + "dylint_internal", + "log", + "once_cell", + "semver", + "serde", + "serde_json", + "tempfile", +] + +[[package]] +name = "dylint_internal" +version = "5.0.0" +dependencies = [ + "anstyle", + "anyhow", + "bitflags", + "cargo_metadata", + "git2", + "home", + "log", + "regex", + "serde", + "tar", + "thiserror 2.0.16", + "toml", +] + +[[package]] +name = "dylint_linting" +version = "5.0.0" +dependencies = [ + "cargo_metadata", + "dylint_internal", + "paste", + "rustversion", + "serde", + "thiserror 2.0.16", + "toml", +] + +[[package]] +name = "dylint_testing" +version = "5.0.0" +dependencies = [ + "anyhow", + "cargo_metadata", + "compiletest_rs", + "dylint", + "dylint_internal", + "env_logger", + "once_cell", + "regex", + "serde_json", + "tempfile", +] + +[[package]] +name = "either" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "git2" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "libgit2-sys" +version = "0.18.3+1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "match_hir" +version = "0.1.0" +dependencies = [ + "inflections", + "paste", + "proc-macro2", + "quote", + "syn", + "thiserror 2.0.16", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miow" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc_apfloat" +version = "0.2.2+llvm-462a31f5a5ab" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" +dependencies = [ + "bitflags", + "smallvec", +] + +[[package]] +name = "rustfix" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a" +dependencies = [ + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.224" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaeb1e94f53b16384af593c71e20b095e958dab1d26939c1b70645c5cfbcc0b" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.224" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f39390fa6346e24defbcdd3d9544ba8a19985d0af74df8501fbfe9a64341ab" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.224" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.1", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "tester" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8bf7e0eb2dd7b4228cc1b6821fc5114cd6841ae59f652a85488c016091e5f" +dependencies = [ + "cfg-if", + "getopts", + "libc", + "num_cpus", + "term", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl 2.0.16", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_parser" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "xattr" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/examples/experimental/disallowed_pattern/Cargo.toml b/examples/experimental/disallowed_pattern/Cargo.toml new file mode 100644 index 000000000..43aa3b754 --- /dev/null +++ b/examples/experimental/disallowed_pattern/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "disallowed_pattern" +version = "5.0.0" +authors = ["Samuel E. Moelius III "] +description = "description goes here" +edition = "2024" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "0450db33a5d8587f7c1d4b6d233dac963605766b" } +libloading = "0.8" +match_hir = { path = "../../../match_hir" } +paste = "1.0" +quote = "1.0" +serde = "1.0" +syn = "2.0" +tempfile = "3.17" + +dylint_internal = { path = "../../../internal", features = ["cargo", "rustup"] } +dylint_linting = { path = "../../../utils/linting" } + +[build-dependencies] +toml = "0.9" + +dylint_internal = { path = "../../../internal" } + +[dev-dependencies] +dylint_testing = { path = "../../../utils/testing" } + +[lints.rust.unexpected_cfgs] +level = "deny" +check-cfg = ["cfg(dylint_lib, values(any()))"] + +[package.metadata.rust-analyzer] +rustc_private = true + +[workspace] + +[workspace.metadata.dylint] +libraries = [ + { path = "../../general" }, + { path = "../../supplementary" }, + { path = "../../testing/clippy" }, + { path = "../../restriction/*" }, +] diff --git a/examples/experimental/disallowed_pattern/README.md b/examples/experimental/disallowed_pattern/README.md new file mode 100644 index 000000000..db282ab8e --- /dev/null +++ b/examples/experimental/disallowed_pattern/README.md @@ -0,0 +1,9 @@ +# disallowed_pattern + +### What it does + +Checks for code patterns a user wishes to forbid. + +### Why is this bad? + +It depends on the code pattern and the user's reason for wanting to forbid it. diff --git a/examples/experimental/disallowed_pattern/build.rs b/examples/experimental/disallowed_pattern/build.rs new file mode 100644 index 000000000..ef6a250c1 --- /dev/null +++ b/examples/experimental/disallowed_pattern/build.rs @@ -0,0 +1,24 @@ +//! Extracts the `clippy_utils` revision from the project's Cargo.toml file and writes it to +//! `out_dir/clippy_utils_rev.txt`. + +use dylint_internal::env; +use std::{ + fs::{read_to_string, write}, + path::PathBuf, +}; + +fn main() { + let out_dir = env::var(env::OUT_DIR).unwrap(); + let contents = read_to_string("Cargo.toml").unwrap(); + let document = contents.parse::().unwrap(); + let rev = document + .get("dependencies") + .and_then(toml::Value::as_table) + .and_then(|table| table.get("clippy_utils")) + .and_then(toml::Value::as_table) + .and_then(|table| table.get("rev")) + .and_then(toml::Value::as_str) + .unwrap(); + let path_buf = PathBuf::from(out_dir).join("clippy_utils_rev.txt"); + write(path_buf, rev).unwrap(); +} diff --git a/examples/experimental/disallowed_pattern/rust-toolchain b/examples/experimental/disallowed_pattern/rust-toolchain new file mode 100644 index 000000000..b8e5648bf --- /dev/null +++ b/examples/experimental/disallowed_pattern/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-09-18" +components = ["llvm-tools-preview", "rustc-dev"] diff --git a/examples/experimental/disallowed_pattern/src/config.rs b/examples/experimental/disallowed_pattern/src/config.rs new file mode 100644 index 000000000..7c0f5c415 --- /dev/null +++ b/examples/experimental/disallowed_pattern/src/config.rs @@ -0,0 +1,83 @@ +use crate::{ + Pattern, + pattern::{CompiledPattern, UncompiledPattern}, +}; +use anyhow::Result; +use serde::{Deserialize, Deserializer}; +use std::collections::BTreeMap; + +pub struct Config { + pub type_pattern_map: BTreeMap>, +} + +impl Default for Config { + fn default() -> Self { + Self { + type_pattern_map: BTreeMap::new(), + } + } +} + +#[derive(Deserialize)] +struct PatternsWithOptionalTypes { + patterns: Vec, +} + +#[derive(Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Deserialize)] +pub enum Type { + Arm, + Block, + #[default] + Expr, + Stmt, +} + +#[derive(Deserialize)] +struct PatternWithOptionalType { + #[serde(rename = "type")] + type_: Option, + #[serde(flatten)] + pattern: UncompiledPattern, +} + +impl<'de> Deserialize<'de> for Config { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let mut type_pattern_map = BTreeMap::<_, Vec<_>>::new(); + let PatternsWithOptionalTypes { + patterns: patterns_with_types, + } = PatternsWithOptionalTypes::deserialize(deserializer)?; + for PatternWithOptionalType { type_, pattern } in patterns_with_types { + type_pattern_map + .entry(type_.unwrap_or_default()) + .or_default() + .push(pattern); + } + Ok(Config { type_pattern_map }) + } +} + +impl Config { + /// # Panics + /// + /// Panics if a pattern cannot be parsed, or if a predicate or callback cannot be compiled. + pub fn compile(self) -> Config { + let type_pattern_map = self + .type_pattern_map + .into_iter() + .map(|(type_, patterns)| { + let patterns = patterns.into_iter().map(Pattern::compile).collect(); + (type_, patterns) + }) + .collect(); + Config { type_pattern_map } + } +} + +impl Config { + pub fn get_slice(&self, type_: Type) -> Option<&[CompiledPattern]> { + self.type_pattern_map.get(&type_).map(Vec::as_slice) + } +} diff --git a/examples/experimental/disallowed_pattern/src/lib.rs b/examples/experimental/disallowed_pattern/src/lib.rs new file mode 100644 index 000000000..f4d365e0f --- /dev/null +++ b/examples/experimental/disallowed_pattern/src/lib.rs @@ -0,0 +1,240 @@ +#![feature(rustc_private)] +#![warn(unused_extern_crates)] + +extern crate rustc_hir; + +use anyhow::{Result, anyhow}; +use clippy_utils::diagnostics::span_lint; +use match_hir::ErrorKind; +use paste::paste; +use rustc_hir::HirId; +use rustc_lint::{LateContext, LateLintPass}; +use std::path::Path; + +mod config; +use config::{Config, Type}; + +mod pattern; +use pattern::{CallbackDir, Pattern}; + +use crate::pattern::{CompiledPattern, UncompiledPattern}; + +dylint_linting::impl_late_lint! { + /// ### What it does + /// + /// Checks for code patterns a user wishes to forbid. + /// + /// ### Why is this bad? + /// + /// It depends on the code pattern and the user's reason for wanting to forbid it. + pub DISALLOWED_PATTERN, + Warn, + "code patterns a user wishes to forbid", + DisallowedPattern::new() +} + +struct DisallowedPattern { + config: Config, +} + +impl DisallowedPattern { + pub fn new() -> Self { + let config: Config = + dylint_linting::config_or_default(env!("CARGO_PKG_NAME")); + Self { + config: config.compile(), + } + } +} + +macro_rules! impl_check { + ($ty:ident) => { + paste! { + fn [< check_ $ty >](&mut self, cx: &LateContext<'tcx>, $ty: &'tcx rustc_hir::[< $ty:camel >]) { + let patterns = self.config.get_slice(Type::[< $ty:camel >]); + Self::check_with_patterns(cx, $ty, patterns); + } + } + }; +} + +impl<'tcx> LateLintPass<'tcx> for DisallowedPattern { + impl_check!(arm); + impl_check!(block); + impl_check!(expr); + impl_check!(stmt); +} + +impl DisallowedPattern { + fn check_with_patterns( + cx: &LateContext<'_>, + hir_node: &T, + patterns: Option<&[Pattern]>, + ) where + T: match_hir::HirNode + match_hir::HirToSyn, + { + let Some(patterns) = patterns else { + return; + }; + let hir_id = hir_node.hir_id(); + for Pattern { + pattern, + predicate, + callback, + dependencies: _, + reason, + } in patterns + { + match pattern.matches_hir_id::(cx, hir_id) { + Ok(hir_ids) => { + if let Some(callback_dir) = callback { + assert!(!predicate.is_some()); + unsafe { call::<()>(cx, &callback_dir.lib_path(), &hir_ids) }.unwrap(); + return; + } + if let Some(predicate_dir) = predicate + && !unsafe { call::(cx, &predicate_dir.lib_path(), &hir_ids) } + .unwrap() + { + return; + } + + let span = cx.tcx.hir_span(hir_id); + let msg = reason.clone().unwrap_or(String::from("disallowed pattern")); + span_lint(cx, DISALLOWED_PATTERN, span, msg); + } + Err(error) => { + debug_assert!(matches!( + error.kind(), + ErrorKind::NoSource | ErrorKind::NoMatch | ErrorKind::NoHirId { .. } + )); + } + } + } + } +} + +type Callback = fn(&LateContext<'_>, &[HirId]) -> T; + +unsafe fn call(cx: &LateContext, path: &Path, hir_ids: &[HirId]) -> Result { + let lib = unsafe { libloading::Library::new(path) }?; + let func = unsafe { lib.get::>(b"callback") }.map_err(|error| { + anyhow!( + "could not find callback in `{}`: {error}", + path.to_string_lossy() + ) + })?; + let result = func(cx, hir_ids); + Ok(result) +} + +#[test] +fn ui_predicate() { + let toml = r##" +[[disallowed_pattern.patterns]] +pattern = "#(_) ( #(_) )" +predicate = """ + |cx: &LateContext<'tcx>, callee: &Expr<'tcx>, arg: &Expr<'tcx>| { + extern crate rustc_ast; + extern crate rustc_middle; + use clippy_utils::paths::{PathNS, lookup_path_str}; + let callee_ty = cx.typeck_results().expr_ty(callee); + if let &rustc_middle::ty::FnDef(def_id, _) = callee_ty.kind() + && (lookup_path_str(cx.tcx, PathNS::Value, "std::env::remove_var") == [def_id] + || lookup_path_str(cx.tcx, PathNS::Value, "std::env::var") == [def_id]) + && let rustc_hir::ExprKind::Lit(lit) = arg.kind + && matches!(lit.node, rustc_ast::ast::LitKind::Str(_, _)) + { + true + } else { + false + } + } +""" +reason = "referring to an environment variable with a string literal is error prone" + +[[disallowed_pattern.patterns]] +pattern = "#(_) ( #(_), #(_) )" +predicate = """ + |cx: &LateContext<'tcx>, callee: &Expr<'tcx>, arg: &Expr<'tcx>, _: &Expr<'tcx>| { + extern crate rustc_ast; + extern crate rustc_middle; + use clippy_utils::paths::{PathNS, lookup_path_str}; + let callee_ty = cx.typeck_results().expr_ty(callee); + if let &rustc_middle::ty::FnDef(def_id, _) = callee_ty.kind() + && lookup_path_str(cx.tcx, PathNS::Value, "std::env::set_var") == [def_id] + && let rustc_hir::ExprKind::Lit(lit) = arg.kind + && matches!(lit.node, rustc_ast::ast::LitKind::Str(_, _)) + { + true + } else { + false + } + } +""" +"##; + + dylint_testing::ui::Test::src_base(env!("CARGO_PKG_NAME"), "ui_predicate") + .dylint_toml(toml) + .run(); +} + +#[test] +fn ui_callback() { + let toml = r##" +[[disallowed_pattern.patterns]] +pattern = "#(_) ( #(_) )" +callback = """ + |cx: &LateContext<'tcx>, callee: &Expr<'tcx>, arg: &Expr<'tcx>| { + extern crate rustc_ast; + extern crate rustc_middle; + use clippy_utils::paths::{PathNS, lookup_path_str}; + let callee_ty = cx.typeck_results().expr_ty(callee); + if let &rustc_middle::ty::FnDef(def_id, _) = callee_ty.kind() + && (lookup_path_str(cx.tcx, PathNS::Value, "std::env::remove_var") == [def_id] + || lookup_path_str(cx.tcx, PathNS::Value, "std::env::var") == [def_id]) + && let rustc_hir::ExprKind::Lit(lit) = arg.kind + && let rustc_ast::LitKind::Str(ident, _) = lit.node + { + clippy_utils::diagnostics::span_lint_and_help( + cx, + DISALLOWED_PATTERN, + arg.span, + "referring to an environment variable with a string literal is error prone", + None, + format!("define a constant `{ident}` and use that instead"), + ); + } + } +""" + +[[disallowed_pattern.patterns]] +pattern = "#(_) ( #(_), #(_) )" +callback = """ + |cx: &LateContext<'tcx>, callee: &Expr<'tcx>, arg: &Expr<'tcx>, _: &Expr<'tcx>| { + extern crate rustc_ast; + extern crate rustc_middle; + use clippy_utils::paths::{PathNS, lookup_path_str}; + let callee_ty = cx.typeck_results().expr_ty(callee); + if let &rustc_middle::ty::FnDef(def_id, _) = callee_ty.kind() + && lookup_path_str(cx.tcx, PathNS::Value, "std::env::set_var") == [def_id] + && let rustc_hir::ExprKind::Lit(lit) = arg.kind + && let rustc_ast::LitKind::Str(ident, _) = lit.node + { + clippy_utils::diagnostics::span_lint_and_help( + cx, + DISALLOWED_PATTERN, + arg.span, + "referring to an environment variable with a string literal is error prone", + None, + format!("define a constant `{ident}` and use that instead"), + ); + } + } +""" +"##; + + dylint_testing::ui::Test::src_base(env!("CARGO_PKG_NAME"), "ui_callback") + .dylint_toml(toml) + .run(); +} diff --git a/examples/experimental/disallowed_pattern/src/pattern.rs b/examples/experimental/disallowed_pattern/src/pattern.rs new file mode 100644 index 000000000..fde3a5dea --- /dev/null +++ b/examples/experimental/disallowed_pattern/src/pattern.rs @@ -0,0 +1,287 @@ +use anyhow::{Result, anyhow, bail, ensure}; +use dylint_internal::{CommandExt, rustup::SanitizeEnvironment}; +use quote::ToTokens; +use serde::Deserialize; +use std::{ + env::consts, + fs::{File, OpenOptions, create_dir, write}, + io::Write, + path::PathBuf, + process::Command, +}; +use syn::spanned::Spanned; +use tempfile::TempDir; + +#[derive(Deserialize)] +pub struct Pattern { + pub pattern: T, + pub predicate: Option, + pub callback: Option, + pub dependencies: Option, + pub reason: Option, +} + +pub type UncompiledPattern = Pattern; + +pub type CompiledPattern = Pattern; + +impl UncompiledPattern { + /// # Panics + /// + /// Panics if a pattern cannot be parsed, or if a predicate or callback cannot be compiled. + pub fn compile(self) -> CompiledPattern { + let Pattern { + pattern, + predicate, + callback, + dependencies, + reason, + } = self; + let pattern = pattern.parse::().unwrap(); + let predicate = + predicate.map(|predicate| compile(&predicate, dependencies.as_deref(), true).unwrap()); + let callback = + callback.map(|callback| compile(&callback, dependencies.as_deref(), false).unwrap()); + Pattern { + pattern, + predicate, + callback, + dependencies: None, + reason, + } + } +} + +const RUST_TOOLCHAIN: &str = include_str!("../rust-toolchain"); +const CLIPPY_UTILS_REV: &str = include_str!(concat!(env!("OUT_DIR"), "/clippy_utils_rev.txt")); + +pub struct CallbackDir { + tempdir: TempDir, +} + +fn compile(callback: &str, dependencies: Option<&str>, is_predicate: bool) -> Result { + let (ident_types, body) = parse_callback(callback)?; + let output = if is_predicate { " -> bool" } else { "" }; + + let tempdir = TempDir::new()?; + + write(tempdir.path().join("rust-toolchain"), RUST_TOOLCHAIN)?; + + write( + tempdir.path().join("Cargo.toml"), + format!( + r#" +[package] +name = "callback" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +clippy_utils = {{ git = "https://github.com/rust-lang/rust-clippy", rev = "{CLIPPY_UTILS_REV}" }} +{} +"#, + dependencies.unwrap_or_default().trim_start() + ), + )?; + + create_dir(tempdir.path().join("src"))?; + + let mut lib_rs = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(tempdir.path().join("src/lib.rs"))?; + writeln!( + &mut lib_rs, + r#" +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_lint_defs; + +#[allow(clippy::wildcard_imports)] +use rustc_hir::*; + +use rustc_lint::LateContext; + +rustc_lint_defs::declare_lint! {{ + DISALLOWED_PATTERN, + Warn, + "a disallowed pattern" +}}"# + )?; + write_callback(&mut lib_rs, &ident_types, output, body)?; + + // smoelius: Ideally, this code would be combined with the code for building library packages. + Command::new("cargo") + .sanitize_environment() + .env_remove(dylint_internal::env::RUSTFLAGS) + .current_dir(&tempdir) + .args(["build", "--quiet", "--release"]) + .success()?; + + Ok(CallbackDir { tempdir }) +} + +#[derive(Debug)] +struct IdentType { + ident: String, + ty: syn::Type, +} + +fn parse_callback(callback: &str) -> Result<(Vec, &str)> { + let closure = syn::parse_str::(callback)?; + let syn::ExprClosure { + attrs, + lifetimes, + constness, + movability, + asyncness, + capture, + or1_token: _, + inputs, + or2_token: _, + output, + body, + } = closure; + ensure!(attrs.is_empty()); + ensure!(lifetimes.is_none()); + ensure!(constness.is_none()); + ensure!(movability.is_none()); + ensure!(asyncness.is_none()); + ensure!(capture.is_none()); + let ident_types = parse_inputs(inputs.iter())?; + ensure!(matches!(output, syn::ReturnType::Default)); + let body = &callback[body.span().byte_range()]; + Ok((ident_types, body)) +} + +fn parse_inputs<'a>(inputs: impl Iterator) -> Result> { + let mut ident_types = Vec::new(); + for input in inputs { + let syn::Pat::Type(syn::PatType { + attrs: attrs_type, + pat, + colon_token: _, + ty, + }) = input + else { + bail!("unexpected pattern: {}", input.to_token_stream()); + }; + if !attrs_type.is_empty() { + bail!("pattern cannot have attributes: {:?}", attrs_type); + } + let ident = match &**pat { + syn::Pat::Ident(syn::PatIdent { + attrs: attrs_pat, + by_ref, + mutability, + ident, + subpat, + }) if attrs_pat.is_empty() + && by_ref.is_none() + && mutability.is_none() + && subpat.is_none() => + { + ident.to_string() + } + syn::Pat::Wild(syn::PatWild { + attrs: attrs_pat, + underscore_token: _, + }) if attrs_pat.is_empty() => String::from("_"), + _ => { + bail!("unexpected pattern: {}", input.to_token_stream()); + } + }; + ident_types.push(IdentType { + ident, + ty: *ty.clone(), + }) + } + Ok(ident_types) +} + +fn write_callback( + lib_rs: &mut File, + ident_types: &[IdentType], + output: &str, + body: &str, +) -> Result<()> { + let Some(IdentType { + ident: cx_ident, + ty: cx_ty, + }) = ident_types.first() + else { + bail!("callback's first argument should be a `&LateContext<'_>`"); + }; + + ensure!(cx_ident != "hir_ids", "`hir_ids` is reserved"); + + writeln!( + lib_rs, + r" +#[unsafe(no_mangle)] +pub fn callback<'tcx>(" + )?; + writeln!(lib_rs, " {cx_ident}: {},", cx_ty.to_token_stream())?; + writeln!(lib_rs, " hir_ids: &[HirId],")?; + writeln!(lib_rs, r"){output} {{")?; + writeln!( + lib_rs, + r#" assert_eq!(1 + hir_ids.len(), {}, "expected {{}} closure arguments; got {0}", 1 + hir_ids.len());"#, + ident_types.len() + )?; + for (i, IdentType { ident, ty }) in ident_types.iter().skip(1).enumerate() { + let node_ty = parse_input_ty(ty)?; + writeln!( + lib_rs, + " let {ident} = {cx_ident}.tcx.hir_node(hir_ids[{i}]).expect_{node_ty}();" + )?; + } + writeln!(lib_rs, " {body}")?; + writeln!(lib_rs, "}}")?; + + Ok(()) +} + +fn parse_input_ty(ty: &syn::Type) -> Result { + if let syn::Type::Reference(syn::TypeReference { + and_token: _, + lifetime: _, + mutability, + elem, + }) = ty + && mutability.is_none() + && let syn::Type::Path(syn::TypePath { qself, path }) = &**elem + && qself.is_none() + && let syn::Path { + leading_colon, + segments, + } = path + && leading_colon.is_none() + && segments.len() == 1 + { + let syn::PathSegment { + ident, + arguments: _, + } = &segments[0]; + Ok(ident.to_string().to_lowercase()) + } else { + Err(anyhow!("unexpected type: {}", ty.to_token_stream())) + } +} + +impl CallbackDir { + pub fn lib_path(&self) -> PathBuf { + self.tempdir.path().join(format!( + "target/release/{}callback{}", + consts::DLL_PREFIX, + consts::DLL_SUFFIX + )) + } +} diff --git a/examples/experimental/disallowed_pattern/ui_callback/main.rs b/examples/experimental/disallowed_pattern/ui_callback/main.rs new file mode 100644 index 000000000..111350262 --- /dev/null +++ b/examples/experimental/disallowed_pattern/ui_callback/main.rs @@ -0,0 +1,5 @@ +fn main() { + let _ = std::env::var("RUSTFLAGS"); + std::env::remove_var("RUSTFALGS"); + std::env::set_var("RUSTFALGS", "-D warnings"); +} diff --git a/examples/experimental/disallowed_pattern/ui_callback/main.stderr b/examples/experimental/disallowed_pattern/ui_callback/main.stderr new file mode 100644 index 000000000..c551b3073 --- /dev/null +++ b/examples/experimental/disallowed_pattern/ui_callback/main.stderr @@ -0,0 +1,27 @@ +warning: referring to an environment variable with a string literal is error prone + --> $DIR/main.rs:2:27 + | +LL | let _ = std::env::var("RUSTFLAGS"); + | ^^^^^^^^^^^ + | + = help: define a constant `RUSTFLAGS` and use that instead + = note: `#[warn(disallowed_pattern)]` on by default + +warning: referring to an environment variable with a string literal is error prone + --> $DIR/main.rs:3:26 + | +LL | std::env::remove_var("RUSTFALGS"); + | ^^^^^^^^^^^ + | + = help: define a constant `RUSTFALGS` and use that instead + +warning: referring to an environment variable with a string literal is error prone + --> $DIR/main.rs:4:23 + | +LL | std::env::set_var("RUSTFALGS", "-D warnings"); + | ^^^^^^^^^^^ + | + = help: define a constant `RUSTFALGS` and use that instead + +warning: 3 warnings emitted + diff --git a/examples/experimental/disallowed_pattern/ui_predicate/main.rs b/examples/experimental/disallowed_pattern/ui_predicate/main.rs new file mode 100644 index 000000000..111350262 --- /dev/null +++ b/examples/experimental/disallowed_pattern/ui_predicate/main.rs @@ -0,0 +1,5 @@ +fn main() { + let _ = std::env::var("RUSTFLAGS"); + std::env::remove_var("RUSTFALGS"); + std::env::set_var("RUSTFALGS", "-D warnings"); +} diff --git a/examples/experimental/disallowed_pattern/ui_predicate/main.stderr b/examples/experimental/disallowed_pattern/ui_predicate/main.stderr new file mode 100644 index 000000000..114633f44 --- /dev/null +++ b/examples/experimental/disallowed_pattern/ui_predicate/main.stderr @@ -0,0 +1,22 @@ +warning: referring to an environment variable with a string literal is error prone + --> $DIR/main.rs:2:13 + | +LL | let _ = std::env::var("RUSTFLAGS"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(disallowed_pattern)]` on by default + +warning: referring to an environment variable with a string literal is error prone + --> $DIR/main.rs:3:5 + | +LL | std::env::remove_var("RUSTFALGS"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: disallowed pattern + --> $DIR/main.rs:4:5 + | +LL | std::env::set_var("RUSTFALGS", "-D warnings"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 3 warnings emitted + diff --git a/match_hir/.cargo/config.toml b/match_hir/.cargo/config.toml new file mode 100644 index 000000000..a205f9abd --- /dev/null +++ b/match_hir/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target-dir = "../target/nightly" + +[target.'cfg(all())'] +linker = "dylint-link" diff --git a/match_hir/Cargo.lock b/match_hir/Cargo.lock new file mode 100644 index 000000000..59ecf1954 --- /dev/null +++ b/match_hir/Cargo.lock @@ -0,0 +1,1625 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "assert_cmd" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd389a4b2970a01282ee455294913c0a43724daedcd1a24c3eb0ec1c1320b66" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122ec45a44b270afd1402f351b782c676b173e3c3fb28d86ff7ebfb4d86a4ee4" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981a6f317983eec002839b90fae7411a85621410ae591a9cab2ecf5cb5744873" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.17", +] + +[[package]] +name = "cc" +version = "1.2.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compiletest_rs" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f150fe9105fcd2a57cad53f0c079a24de65195903ef670990f5909f695eac04c" +dependencies = [ + "diff", + "filetime", + "getopts", + "lazy_static", + "libc", + "log", + "miow", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tester", + "windows-sys 0.59.0", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dylint" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a937bab540c0c8cdcbd650a572e6899ef2b6ffbc277d61bd2ae8d17c0edce" +dependencies = [ + "anstyle", + "anyhow", + "cargo_metadata", + "dylint_internal", + "log", + "once_cell", + "semver", + "serde", + "serde_json", + "tempfile", +] + +[[package]] +name = "dylint_internal" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e11f358a59510be7fa5c4f412729fabbe31a3587a342e4241a6a72020a2a0c5" +dependencies = [ + "anstyle", + "anyhow", + "bitflags", + "cargo_metadata", + "git2", + "home", + "if_chain", + "log", + "regex", + "rustversion", + "serde", + "tar", + "thiserror 2.0.17", + "toml", +] + +[[package]] +name = "dylint_linting" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4588b33aafbd472a6468ad1521d74094faa2bbdb53d534c2d24320300ea94135" +dependencies = [ + "cargo_metadata", + "dylint_internal", + "paste", + "rustversion", + "serde", + "thiserror 2.0.17", + "toml", +] + +[[package]] +name = "dylint_testing" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc27f344ddb5488eb16b6e0f8aec889a30fb7e4d135060d336cfa60d1fd671c" +dependencies = [ + "anyhow", + "cargo_metadata", + "compiletest_rs", + "dylint", + "dylint_internal", + "env_logger", + "once_cell", + "regex", + "serde_json", + "tempfile", +] + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if_chain" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libgit2-sys" +version = "0.18.2+1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "match_hir" +version = "0.1.0" +dependencies = [ + "assert_cmd", + "inflections", + "paste", + "proc-macro2", + "quote", + "snapbox", + "syn", + "thiserror 2.0.17", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miow" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "difflib", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "reflective_match" +version = "0.1.0" +dependencies = [ + "dylint_linting", + "dylint_testing", + "match_hir", + "thiserror 2.0.17", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustfix" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a" +dependencies = [ + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "snapbox" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805d09a74586d9b17061e5be6ee5f8cc37e5982c349948114ffc5f68093fe5ec" +dependencies = [ + "anstream", + "anstyle", + "normalize-line-endings", + "similar", + "snapbox-macros", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" +dependencies = [ + "anstream", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "tester" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8bf7e0eb2dd7b4228cc1b6821fc5114cd6841ae59f652a85488c016091e5f" +dependencies = [ + "cfg-if", + "getopts", + "libc", + "num_cpus", + "term", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/match_hir/Cargo.toml b/match_hir/Cargo.toml new file mode 100644 index 000000000..ab7a3398b --- /dev/null +++ b/match_hir/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "match_hir" +version = "0.1.0" +authors = ["Samuel Moelius "] +description = "A library to make matching Rust's High-level IR (HIR) easier" +edition = "2024" +license = "MIT OR Apache-2.0" +repository = "https://github.com/trailofbits/dylint" + +build = "build/main.rs" + +[dependencies] +paste = "1.0" +proc-macro2 = { version = "1.0", features = ["span-locations"] } +syn = { version = "2.0", features = [ + "extra-traits", + "full", + "parsing", + "visit", +] } +thiserror = "2.0" + +[dev-dependencies] +assert_cmd = "2.0" +quote = "1.0" +snapbox = "0.6" + +[build-dependencies] +inflections = "1.1" +quote = "1.0" +syn = { version = "2.0", features = ["extra-traits", "full"] } + +[lints] +workspace = true + +[package.metadata.rust-analyzer] +rustc_private = true + +[profile.release] +debug = true + +[workspace] +members = ["reflective_match"] + +[workspace.lints.clippy] +pedantic = { level = "warn", priority = -1 } +missing-errors-doc = "allow" +missing-panics-doc = "allow" + +[workspace.lints.rust.unexpected_cfgs] +level = "deny" +check-cfg = ["cfg(dylint_lib, values(any()))"] + +[workspace.metadata.dylint] +libraries = [ + { path = "../examples/general" }, + { path = "../examples/supplementary" }, + { path = "../examples/testing/clippy" }, + { path = "../examples/restriction/*" }, +] diff --git a/match_hir/assets/README.txt b/match_hir/assets/README.txt new file mode 100644 index 000000000..a0580a9d7 --- /dev/null +++ b/match_hir/assets/README.txt @@ -0,0 +1,12 @@ +The file hir.rs, in the same directory as this README, is from the following location: + +https://github.com/rust-lang/rust/blob/f0308938ba39bc3377f22f7479654ba32e9c233f/compiler/rustc_hir/src/hir.rs + +The file is used by build.rs to implement the `TypeNameGetter` trait, which the span-to-hir-id map +uses. + +The file visit.rs, also in the same directory as this README, is from the following location: + +https://github.com/dtolnay/syn/blob/6eb82a997589cf9c5b2bb36716443a19c4440c5e/src/gen/visit.rs + +The file is used by build.rs to implement the `Unify` and `Visitable` traits. diff --git a/match_hir/assets/hir.rs b/match_hir/assets/hir.rs new file mode 100644 index 000000000..46ce02495 --- /dev/null +++ b/match_hir/assets/hir.rs @@ -0,0 +1,4908 @@ +use std::fmt; + +use rustc_abi::ExternAbi; +// ignore-tidy-filelength +use rustc_ast::attr::AttributeExt; +use rustc_ast::token::CommentKind; +use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; +use rustc_ast::{ + self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, + IntTy, Label, LitIntType, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy, +}; +pub use rustc_ast::{ + BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, + ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind, +}; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::sorted_map::SortedMap; +use rustc_data_structures::tagged_ptr::TaggedRef; +use rustc_index::IndexVec; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::def_id::LocalDefId; +use rustc_span::hygiene::MacroKind; +use rustc_span::source_map::Spanned; +use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_target::asm::InlineAsmRegOrRegClass; +use smallvec::SmallVec; +use thin_vec::ThinVec; +use tracing::debug; + +use crate::LangItem; +use crate::def::{CtorKind, DefKind, Res}; +use crate::def_id::{DefId, LocalDefIdMap}; +pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; +use crate::intravisit::{FnKind, VisitorExt}; + +#[derive(Debug, Copy, Clone, HashStable_Generic)] +pub struct Lifetime { + #[stable_hasher(ignore)] + pub hir_id: HirId, + + /// Either "`'a`", referring to a named lifetime definition, + /// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`), + /// or "``" (i.e., `kw::Empty`) when appearing in path. + /// + /// See `Lifetime::suggestion_position` for practical use. + pub ident: Ident, + + /// Semantics of this lifetime. + pub res: LifetimeName, +} + +#[derive(Debug, Copy, Clone, HashStable_Generic)] +pub enum ParamName { + /// Some user-given name like `T` or `'x`. + Plain(Ident), + + /// Indicates an illegal name was given and an error has been + /// reported (so we should squelch other derived errors). + /// + /// Occurs when, e.g., `'_` is used in the wrong place, or a + /// lifetime name is duplicated. + Error(Ident), + + /// Synthetic name generated when user elided a lifetime in an impl header. + /// + /// E.g., the lifetimes in cases like these: + /// ```ignore (fragment) + /// impl Foo for &u32 + /// impl Foo<'_> for u32 + /// ``` + /// in that case, we rewrite to + /// ```ignore (fragment) + /// impl<'f> Foo for &'f u32 + /// impl<'f> Foo<'f> for u32 + /// ``` + /// where `'f` is something like `Fresh(0)`. The indices are + /// unique per impl, but not necessarily continuous. + Fresh, +} + +impl ParamName { + pub fn ident(&self) -> Ident { + match *self { + ParamName::Plain(ident) | ParamName::Error(ident) => ident, + ParamName::Fresh => Ident::with_dummy_span(kw::UnderscoreLifetime), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum LifetimeName { + /// User-given names or fresh (synthetic) names. + Param(LocalDefId), + + /// Implicit lifetime in a context like `dyn Foo`. This is + /// distinguished from implicit lifetimes elsewhere because the + /// lifetime that they default to must appear elsewhere within the + /// enclosing type. This means that, in an `impl Trait` context, we + /// don't have to create a parameter for them. That is, `impl + /// Trait` expands to an opaque type like `type + /// Foo<'a> = impl Trait`, but `impl Trait` expands to `type Foo = impl Trait`. The latter uses `ImplicitObjectLifetimeDefault` so + /// that surrounding code knows not to create a lifetime + /// parameter. + ImplicitObjectLifetimeDefault, + + /// Indicates an error during lowering (usually `'_` in wrong place) + /// that was already reported. + Error, + + /// User wrote an anonymous lifetime, either `'_` or nothing. + /// The semantics of this lifetime should be inferred by typechecking code. + Infer, + + /// User wrote `'static`. + Static, +} + +impl LifetimeName { + fn is_elided(&self) -> bool { + match self { + LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true, + + // It might seem surprising that `Fresh` counts as not *elided* + // -- but this is because, as far as the code in the compiler is + // concerned -- `Fresh` variants act equivalently to "some fresh name". + // They correspond to early-bound regions on an impl, in other words. + LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false, + } + } +} + +impl fmt::Display for Lifetime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.ident.name != kw::Empty { + self.ident.name.fmt(f) + } else { + "'_".fmt(f) + } + } +} + +pub enum LifetimeSuggestionPosition { + /// The user wrote `'a` or `'_`. + Normal, + /// The user wrote `&type` or `&mut type`. + Ampersand, + /// The user wrote `Path` and omitted the `<'_>`. + ElidedPath, + /// The user wrote `Path`, and omitted the `'_,`. + ElidedPathArgument, + /// The user wrote `dyn Trait` and omitted the `+ '_`. + ObjectDefault, +} + +impl Lifetime { + pub fn is_elided(&self) -> bool { + self.res.is_elided() + } + + pub fn is_anonymous(&self) -> bool { + self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime + } + + pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) { + if self.ident.name == kw::Empty { + if self.ident.span.is_empty() { + ( + LifetimeSuggestionPosition::ElidedPathArgument, + self.ident.span, + ) + } else { + ( + LifetimeSuggestionPosition::ElidedPath, + self.ident.span.shrink_to_hi(), + ) + } + } else if self.res == LifetimeName::ImplicitObjectLifetimeDefault { + (LifetimeSuggestionPosition::ObjectDefault, self.ident.span) + } else if self.ident.span.is_empty() { + (LifetimeSuggestionPosition::Ampersand, self.ident.span) + } else { + (LifetimeSuggestionPosition::Normal, self.ident.span) + } + } + + pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { + debug_assert!(new_lifetime.starts_with('\'')); + let (pos, span) = self.suggestion_position(); + let code = match pos { + LifetimeSuggestionPosition::Normal => format!("{new_lifetime}"), + LifetimeSuggestionPosition::Ampersand => format!("{new_lifetime} "), + LifetimeSuggestionPosition::ElidedPath => format!("<{new_lifetime}>"), + LifetimeSuggestionPosition::ElidedPathArgument => format!("{new_lifetime}, "), + LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lifetime}"), + }; + (span, code) + } +} + +/// A `Path` is essentially Rust's notion of a name; for instance, +/// `std::cmp::PartialEq`. It's represented as a sequence of identifiers, +/// along with a bunch of supporting information. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Path<'hir, R = Res> { + pub span: Span, + /// The resolution for the path. + pub res: R, + /// The segments in the path: the things separated by `::`. + pub segments: &'hir [PathSegment<'hir>], +} + +/// Up to three resolutions for type, value and macro namespaces. +pub type UsePath<'hir> = Path<'hir, SmallVec<[Res; 3]>>; + +impl Path<'_> { + pub fn is_global(&self) -> bool { + !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot + } +} + +/// A segment of a path: an identifier, an optional lifetime, and a set of +/// types. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct PathSegment<'hir> { + /// The identifier portion of this path segment. + pub ident: Ident, + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub res: Res, + + /// Type/lifetime parameters attached to this path. They come in + /// two flavors: `Path` and `Path(A,B) -> C`. Note that + /// this is more than just simple syntactic sugar; the use of + /// parens affects the region binding rules, so we preserve the + /// distinction. + pub args: Option<&'hir GenericArgs<'hir>>, + + /// Whether to infer remaining type parameters, if any. + /// This only applies to expression and pattern paths, and + /// out of those only the segments with no type parameters + /// to begin with, e.g., `Vec::new` is `>::new::<..>`. + pub infer_args: bool, +} + +impl<'hir> PathSegment<'hir> { + /// Converts an identifier to the corresponding segment. + pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { + PathSegment { + ident, + hir_id, + res, + infer_args: true, + args: None, + } + } + + pub fn invalid() -> Self { + Self::new(Ident::empty(), HirId::INVALID, Res::Err) + } + + pub fn args(&self) -> &GenericArgs<'hir> { + if let Some(ref args) = self.args { + args + } else { + const DUMMY: &GenericArgs<'_> = &GenericArgs::none(); + DUMMY + } + } +} + +/// A constant that enters the type system, used for arguments to const generics (e.g. array +/// lengths). +/// +/// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed +/// to use any generic parameters, therefore we must represent `N` differently. Additionally +/// future designs for supporting generic parameters in const arguments will likely not use +/// an anon const based design. +/// +/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args +/// that are [just paths](ConstArgKind::Path) (currently just bare const params) +/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). +/// +/// The `Unambig` generic parameter represents whether the position this const is from is +/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an +/// ambiguous context the parameter is instantiated with an uninhabited type making the +/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead. +#[derive(Clone, Copy, Debug, HashStable_Generic)] +#[repr(C)] +pub struct ConstArg<'hir, Unambig = ()> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: ConstArgKind<'hir, Unambig>, +} + +impl<'hir> ConstArg<'hir, AmbigArg> { + /// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position. + /// + /// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant + /// to be used. Care should be taken to separately handle infer consts when calling this + /// function as it cannot be handled by downstream code making use of the returned const. + /// + /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir + /// visitors, or specifically matching on [`GenericArg::Infer`] when handling generic + /// arguments. + /// + /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer] + pub fn as_unambig_ct(&self) -> &ConstArg<'hir> { + // SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the + // layout is the same across different ZST type arguments. + let ptr = self as *const ConstArg<'hir, AmbigArg> as *const ConstArg<'hir, ()>; + unsafe { &*ptr } + } +} + +impl<'hir> ConstArg<'hir> { + /// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is + /// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions. + /// + /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if + /// infer consts are relevant to you then care should be taken to handle them separately. + pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> { + if let ConstArgKind::Infer(_, ()) = self.kind { + return None; + } + + // SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the + // layout is the same across different ZST type arguments. We also asserted that the + // `self` is not a `ConstArgKind::Infer` so there is no risk of transmuting a `()` + // to `AmbigArg`. + let ptr = self as *const ConstArg<'hir> as *const ConstArg<'hir, AmbigArg>; + Some(unsafe { &*ptr }) + } +} + +impl<'hir, Unambig> ConstArg<'hir, Unambig> { + pub fn anon_const_hir_id(&self) -> Option { + match self.kind { + ConstArgKind::Anon(ac) => Some(ac.hir_id), + _ => None, + } + } + + pub fn span(&self) -> Span { + match self.kind { + ConstArgKind::Path(path) => path.span(), + ConstArgKind::Anon(anon) => anon.span, + ConstArgKind::Infer(span, _) => span, + } + } +} + +/// See [`ConstArg`]. +#[derive(Clone, Copy, Debug, HashStable_Generic)] +#[repr(u8, C)] +pub enum ConstArgKind<'hir, Unambig = ()> { + /// **Note:** Currently this is only used for bare const params + /// (`N` where `fn foo(...)`), + /// not paths to any const (`N` where `const N: usize = ...`). + /// + /// However, in the future, we'll be using it for all of those. + Path(QPath<'hir>), + Anon(&'hir AnonConst), + /// This variant is not always used to represent inference consts, sometimes + /// [`GenericArg::Infer`] is used instead. + Infer(Span, Unambig), +} + +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub struct InferArg { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, +} + +impl InferArg { + pub fn to_ty(&self) -> Ty<'static> { + Ty { + kind: TyKind::Infer(()), + span: self.span, + hir_id: self.hir_id, + } + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum GenericArg<'hir> { + Lifetime(&'hir Lifetime), + Type(&'hir Ty<'hir, AmbigArg>), + Const(&'hir ConstArg<'hir, AmbigArg>), + /// Inference variables in [`GenericArg`] are always represnted by + /// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and + /// [`ConstArgKind`] as it is not clear until hir ty lowering whether a + /// `_` argument is a type or const argument. + /// + /// However, some builtin types' generic arguments are represented by [`TyKind`] + /// without a [`GenericArg`], instead directly storing a [`Ty`] or [`ConstArg`]. In + /// such cases they *are* represented by the `Infer` variants on [`TyKind`] and + /// [`ConstArgKind`] as it is not ambiguous whether the argument is a type or const. + Infer(InferArg), +} + +impl GenericArg<'_> { + pub fn span(&self) -> Span { + match self { + GenericArg::Lifetime(l) => l.ident.span, + GenericArg::Type(t) => t.span, + GenericArg::Const(c) => c.span(), + GenericArg::Infer(i) => i.span, + } + } + + pub fn hir_id(&self) -> HirId { + match self { + GenericArg::Lifetime(l) => l.hir_id, + GenericArg::Type(t) => t.hir_id, + GenericArg::Const(c) => c.hir_id, + GenericArg::Infer(i) => i.hir_id, + } + } + + pub fn descr(&self) -> &'static str { + match self { + GenericArg::Lifetime(_) => "lifetime", + GenericArg::Type(_) => "type", + GenericArg::Const(_) => "constant", + GenericArg::Infer(_) => "placeholder", + } + } + + pub fn to_ord(&self) -> ast::ParamKindOrd { + match self { + GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime, + GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => { + ast::ParamKindOrd::TypeOrConst + } + } + } + + pub fn is_ty_or_const(&self) -> bool { + match self { + GenericArg::Lifetime(_) => false, + GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => true, + } + } +} + +/// The generic arguments and associated item constraints of a path segment. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct GenericArgs<'hir> { + /// The generic arguments for this path segment. + pub args: &'hir [GenericArg<'hir>], + /// The associated item constraints for this path segment. + pub constraints: &'hir [AssocItemConstraint<'hir>], + /// Whether the arguments were written in parenthesized form (e.g., `Fn(T) -> U`). + /// + /// This is required mostly for pretty-printing and diagnostics, + /// but also for changing lifetime elision rules to be "function-like". + pub parenthesized: GenericArgsParentheses, + /// The span encompassing the arguments, constraints and the surrounding brackets (`<>` or + /// `()`). + /// + /// For example: + /// + /// ```ignore (illustrative) + /// Foo Fn(T, U, V) -> W + /// ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ + /// ``` + /// + /// Note that this may be: + /// - empty, if there are no generic brackets (but there may be hidden lifetimes) + /// - dummy, if this was generated during desugaring + pub span_ext: Span, +} + +impl<'hir> GenericArgs<'hir> { + pub const fn none() -> Self { + Self { + args: &[], + constraints: &[], + parenthesized: GenericArgsParentheses::No, + span_ext: DUMMY_SP, + } + } + + /// Obtain the list of input types and the output type if the generic arguments are + /// parenthesized. + /// + /// Returns the `Ty0, Ty1, ...` and the `RetTy` in `Trait(Ty0, Ty1, ...) -> RetTy`. + /// Panics if the parenthesized arguments have an incorrect form (this shouldn't happen). + pub fn paren_sugar_inputs_output(&self) -> Option<(&[Ty<'hir>], &Ty<'hir>)> { + if self.parenthesized != GenericArgsParentheses::ParenSugar { + return None; + } + + let inputs = self + .args + .iter() + .find_map(|arg| { + let GenericArg::Type(ty) = arg else { + return None; + }; + let TyKind::Tup(tys) = &ty.kind else { + return None; + }; + Some(tys) + }) + .unwrap(); + + Some((inputs, self.paren_sugar_output_inner())) + } + + /// Obtain the output type if the generic arguments are parenthesized. + /// + /// Returns the `RetTy` in `Trait(Ty0, Ty1, ...) -> RetTy`. + /// Panics if the parenthesized arguments have an incorrect form (this shouldn't happen). + pub fn paren_sugar_output(&self) -> Option<&Ty<'hir>> { + (self.parenthesized == GenericArgsParentheses::ParenSugar) + .then(|| self.paren_sugar_output_inner()) + } + + fn paren_sugar_output_inner(&self) -> &Ty<'hir> { + let [constraint] = self.constraints.try_into().unwrap(); + debug_assert_eq!(constraint.ident.name, sym::Output); + constraint.ty().unwrap() + } + + pub fn has_err(&self) -> Option { + self.args + .iter() + .find_map(|arg| { + let GenericArg::Type(ty) = arg else { + return None; + }; + let TyKind::Err(guar) = ty.kind else { + return None; + }; + Some(guar) + }) + .or_else(|| { + self.constraints.iter().find_map(|constraint| { + let TyKind::Err(guar) = constraint.ty()?.kind else { + return None; + }; + Some(guar) + }) + }) + } + + #[inline] + pub fn num_lifetime_params(&self) -> usize { + self.args + .iter() + .filter(|arg| matches!(arg, GenericArg::Lifetime(_))) + .count() + } + + #[inline] + pub fn has_lifetime_params(&self) -> bool { + self.args + .iter() + .any(|arg| matches!(arg, GenericArg::Lifetime(_))) + } + + #[inline] + /// This function returns the number of type and const generic params. + /// It should only be used for diagnostics. + pub fn num_generic_params(&self) -> usize { + self.args + .iter() + .filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) + .count() + } + + /// The span encompassing the arguments and constraints[^1] inside the surrounding brackets. + /// + /// Returns `None` if the span is empty (i.e., no brackets) or dummy. + /// + /// [^1]: Unless of the form `-> Ty` (see [`GenericArgsParentheses`]). + pub fn span(&self) -> Option { + let span_ext = self.span_ext()?; + Some( + span_ext + .with_lo(span_ext.lo() + BytePos(1)) + .with_hi(span_ext.hi() - BytePos(1)), + ) + } + + /// Returns span encompassing arguments and their surrounding `<>` or `()` + pub fn span_ext(&self) -> Option { + Some(self.span_ext).filter(|span| !span.is_empty()) + } + + pub fn is_empty(&self) -> bool { + self.args.is_empty() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] +pub enum GenericArgsParentheses { + No, + /// Bounds for `feature(return_type_notation)`, like `T: Trait`, + /// where the args are explicitly elided with `..` + ReturnTypeNotation, + /// parenthesized function-family traits, like `T: Fn(u32) -> i32` + ParenSugar, +} + +/// The modifiers on a trait bound. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +pub struct TraitBoundModifiers { + pub constness: BoundConstness, + pub polarity: BoundPolarity, +} + +impl TraitBoundModifiers { + pub const NONE: Self = TraitBoundModifiers { + constness: BoundConstness::Never, + polarity: BoundPolarity::Positive, + }; +} + +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub enum GenericBound<'hir> { + Trait(PolyTraitRef<'hir>), + Outlives(&'hir Lifetime), + Use(&'hir [PreciseCapturingArg<'hir>], Span), +} + +impl GenericBound<'_> { + pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { + match self { + GenericBound::Trait(data) => Some(&data.trait_ref), + _ => None, + } + } + + pub fn span(&self) -> Span { + match self { + GenericBound::Trait(t, ..) => t.span, + GenericBound::Outlives(l) => l.ident.span, + GenericBound::Use(_, span) => *span, + } + } +} + +pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>]; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic, Debug)] +pub enum MissingLifetimeKind { + /// An explicit `'_`. + Underscore, + /// An elided lifetime `&' ty`. + Ampersand, + /// An elided lifetime in brackets with written brackets. + Comma, + /// An elided lifetime with elided brackets. + Brackets, +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum LifetimeParamKind { + // Indicates that the lifetime definition was explicitly declared (e.g., in + // `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`). + Explicit, + + // Indication that the lifetime was elided (e.g., in both cases in + // `fn foo(x: &u8) -> &'_ u8 { x }`). + Elided(MissingLifetimeKind), + + // Indication that the lifetime name was somehow in error. + Error, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum GenericParamKind<'hir> { + /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`). + Lifetime { kind: LifetimeParamKind }, + Type { + default: Option<&'hir Ty<'hir>>, + synthetic: bool, + }, + Const { + ty: &'hir Ty<'hir>, + /// Optional default value for the const generic param + default: Option<&'hir ConstArg<'hir>>, + synthetic: bool, + }, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct GenericParam<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub def_id: LocalDefId, + pub name: ParamName, + pub span: Span, + pub pure_wrt_drop: bool, + pub kind: GenericParamKind<'hir>, + pub colon_span: Option, + pub source: GenericParamSource, +} + +impl<'hir> GenericParam<'hir> { + /// Synthetic type-parameters are inserted after normal ones. + /// In order for normal parameters to be able to refer to synthetic ones, + /// scans them first. + pub fn is_impl_trait(&self) -> bool { + matches!( + self.kind, + GenericParamKind::Type { + synthetic: true, + .. + } + ) + } + + /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`. + /// + /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information. + pub fn is_elided_lifetime(&self) -> bool { + matches!( + self.kind, + GenericParamKind::Lifetime { + kind: LifetimeParamKind::Elided(_) + } + ) + } +} + +/// Records where the generic parameter originated from. +/// +/// This can either be from an item's generics, in which case it's typically +/// early-bound (but can be a late-bound lifetime in functions, for example), +/// or from a `for<...>` binder, in which case it's late-bound (and notably, +/// does not show up in the parent item's generics). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum GenericParamSource { + // Early or late-bound parameters defined on an item + Generics, + // Late-bound parameters defined via a `for<...>` + Binder, +} + +#[derive(Default)] +pub struct GenericParamCount { + pub lifetimes: usize, + pub types: usize, + pub consts: usize, + pub infer: usize, +} + +/// Represents lifetimes and type parameters attached to a declaration +/// of a function, enum, trait, etc. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Generics<'hir> { + pub params: &'hir [GenericParam<'hir>], + pub predicates: &'hir [WherePredicate<'hir>], + pub has_where_clause_predicates: bool, + pub where_clause_span: Span, + pub span: Span, +} + +impl<'hir> Generics<'hir> { + pub const fn empty() -> &'hir Generics<'hir> { + const NOPE: Generics<'_> = Generics { + params: &[], + predicates: &[], + has_where_clause_predicates: false, + where_clause_span: DUMMY_SP, + span: DUMMY_SP, + }; + &NOPE + } + + pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> { + self.params + .iter() + .find(|¶m| name == param.name.ident().name) + } + + /// If there are generic parameters, return where to introduce a new one. + pub fn span_for_lifetime_suggestion(&self) -> Option { + if let Some(first) = self.params.first() + && self.span.contains(first.span) + { + // `fn foo(t: impl Trait)` + // ^ suggest `'a, ` here + Some(first.span.shrink_to_lo()) + } else { + None + } + } + + /// If there are generic parameters, return where to introduce a new one. + pub fn span_for_param_suggestion(&self) -> Option { + self.params + .iter() + .any(|p| self.span.contains(p.span)) + .then(|| { + // `fn foo(t: impl Trait)` + // ^ suggest `, T: Trait` here + self.span + .with_lo(self.span.hi() - BytePos(1)) + .shrink_to_lo() + }) + } + + /// `Span` where further predicates would be suggested, accounting for trailing commas, like + /// in `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. + pub fn tail_span_for_predicate_suggestion(&self) -> Span { + let end = self.where_clause_span.shrink_to_hi(); + if self.has_where_clause_predicates { + self.predicates + .iter() + .rfind(|&p| p.kind.in_where_clause()) + .map_or(end, |p| p.span) + .shrink_to_hi() + .to(end) + } else { + end + } + } + + pub fn add_where_or_trailing_comma(&self) -> &'static str { + if self.has_where_clause_predicates { + "," + } else if self.where_clause_span.is_empty() { + " where" + } else { + // No where clause predicates, but we have `where` token + "" + } + } + + pub fn bounds_for_param( + &self, + param_def_id: LocalDefId, + ) -> impl Iterator> { + self.predicates + .iter() + .filter_map(move |pred| match pred.kind { + WherePredicateKind::BoundPredicate(bp) + if bp.is_param_bound(param_def_id.to_def_id()) => + { + Some(bp) + } + _ => None, + }) + } + + pub fn outlives_for_param( + &self, + param_def_id: LocalDefId, + ) -> impl Iterator> { + self.predicates + .iter() + .filter_map(move |pred| match pred.kind { + WherePredicateKind::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => { + Some(rp) + } + _ => None, + }) + } + + /// Returns a suggestable empty span right after the "final" bound of the generic parameter. + /// + /// If that bound needs to be wrapped in parentheses to avoid ambiguity with + /// subsequent bounds, it also returns an empty span for an open parenthesis + /// as the second component. + /// + /// E.g., adding `+ 'static` after `Fn() -> dyn Future` or + /// `Fn() -> &'static dyn Debug` requires parentheses: + /// `Fn() -> (dyn Future) + 'static` and + /// `Fn() -> &'static (dyn Debug) + 'static`, respectively. + pub fn bounds_span_for_suggestions( + &self, + param_def_id: LocalDefId, + ) -> Option<(Span, Option)> { + self.bounds_for_param(param_def_id) + .flat_map(|bp| bp.bounds.iter().rev()) + .find_map(|bound| { + let span_for_parentheses = if let Some(trait_ref) = bound.trait_ref() + && let [.., segment] = trait_ref.path.segments + && let Some(ret_ty) = segment.args().paren_sugar_output() + && let ret_ty = ret_ty.peel_refs() + && let TyKind::TraitObject(_, tagged_ptr) = ret_ty.kind + && let TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar = tagged_ptr.tag() + && ret_ty.span.can_be_used_for_suggestions() + { + Some(ret_ty.span) + } else { + None + }; + + span_for_parentheses.map_or_else( + || { + // We include bounds that come from a `#[derive(_)]` but point at the user's + // code, as we use this method to get a span + // appropriate for suggestions. + let bs = bound.span(); + bs.can_be_used_for_suggestions() + .then(|| (bs.shrink_to_hi(), None)) + }, + |span| Some((span.shrink_to_hi(), Some(span.shrink_to_lo()))), + ) + }) + } + + pub fn span_for_predicate_removal(&self, pos: usize) -> Span { + let predicate = &self.predicates[pos]; + let span = predicate.span; + + if !predicate.kind.in_where_clause() { + // + // ^^^^^^^^ + return span; + } + + // We need to find out which comma to remove. + if pos < self.predicates.len() - 1 { + let next_pred = &self.predicates[pos + 1]; + if next_pred.kind.in_where_clause() { + // where T: ?Sized, Foo: Bar, + // ^^^^^^^^^^^ + return span.until(next_pred.span); + } + } + + if pos > 0 { + let prev_pred = &self.predicates[pos - 1]; + if prev_pred.kind.in_where_clause() { + // where Foo: Bar, T: ?Sized, + // ^^^^^^^^^^^ + return prev_pred.span.shrink_to_hi().to(span); + } + } + + // This is the only predicate in the where clause. + // where T: ?Sized + // ^^^^^^^^^^^^^^^ + self.where_clause_span + } + + pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) -> Span { + let predicate = &self.predicates[predicate_pos]; + let bounds = predicate.kind.bounds(); + + if bounds.len() == 1 { + return self.span_for_predicate_removal(predicate_pos); + } + + let bound_span = bounds[bound_pos].span(); + if bound_pos < bounds.len() - 1 { + // If there's another bound after the current bound + // include the following '+' e.g.: + // + // `T: Foo + CurrentBound + Bar` + // ^^^^^^^^^^^^^^^ + bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo()) + } else { + // If the current bound is the last bound + // include the preceding '+' E.g.: + // + // `T: Foo + Bar + CurrentBound` + // ^^^^^^^^^^^^^^^ + bound_span.with_lo(bounds[bound_pos - 1].span().hi()) + } + } +} + +/// A single predicate in a where-clause. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct WherePredicate<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, + pub kind: &'hir WherePredicateKind<'hir>, +} + +/// The kind of a single predicate in a where-clause. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum WherePredicateKind<'hir> { + /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). + BoundPredicate(WhereBoundPredicate<'hir>), + /// A lifetime predicate (e.g., `'a: 'b + 'c`). + RegionPredicate(WhereRegionPredicate<'hir>), + /// An equality predicate (unsupported). + EqPredicate(WhereEqPredicate<'hir>), +} + +impl<'hir> WherePredicateKind<'hir> { + pub fn in_where_clause(&self) -> bool { + match self { + WherePredicateKind::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause, + WherePredicateKind::RegionPredicate(p) => p.in_where_clause, + WherePredicateKind::EqPredicate(_) => false, + } + } + + pub fn bounds(&self) -> GenericBounds<'hir> { + match self { + WherePredicateKind::BoundPredicate(p) => p.bounds, + WherePredicateKind::RegionPredicate(p) => p.bounds, + WherePredicateKind::EqPredicate(_) => &[], + } + } +} + +#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)] +pub enum PredicateOrigin { + WhereClause, + GenericParam, + ImplTrait, +} + +/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct WhereBoundPredicate<'hir> { + /// Origin of the predicate. + pub origin: PredicateOrigin, + /// Any generics from a `for` binding. + pub bound_generic_params: &'hir [GenericParam<'hir>], + /// The type being bounded. + pub bounded_ty: &'hir Ty<'hir>, + /// Trait and lifetime bounds (e.g., `Clone + Send + 'static`). + pub bounds: GenericBounds<'hir>, +} + +impl<'hir> WhereBoundPredicate<'hir> { + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn is_param_bound(&self, param_def_id: DefId) -> bool { + self.bounded_ty + .as_generic_param() + .is_some_and(|(def_id, _)| def_id == param_def_id) + } +} + +/// A lifetime predicate (e.g., `'a: 'b + 'c`). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct WhereRegionPredicate<'hir> { + pub in_where_clause: bool, + pub lifetime: &'hir Lifetime, + pub bounds: GenericBounds<'hir>, +} + +impl<'hir> WhereRegionPredicate<'hir> { + /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate. + fn is_param_bound(&self, param_def_id: LocalDefId) -> bool { + self.lifetime.res == LifetimeName::Param(param_def_id) + } +} + +/// An equality predicate (e.g., `T = int`); currently unsupported. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct WhereEqPredicate<'hir> { + pub lhs_ty: &'hir Ty<'hir>, + pub rhs_ty: &'hir Ty<'hir>, +} + +/// HIR node coupled with its parent's id in the same HIR owner. +/// +/// The parent is trash when the node is a HIR owner. +#[derive(Clone, Copy, Debug)] +pub struct ParentedNode<'tcx> { + pub parent: ItemLocalId, + pub node: Node<'tcx>, +} + +/// Arguments passed to an attribute macro. +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub enum AttrArgs { + /// No arguments: `#[attr]`. + Empty, + /// Delimited arguments: `#[attr()/[]/{}]`. + Delimited(DelimArgs), + /// Arguments of a key-value attribute: `#[attr = "value"]`. + Eq { + /// Span of the `=` token. + eq_span: Span, + /// The "value". + expr: MetaItemLit, + }, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub enum AttrKind { + /// A normal attribute. + Normal(Box), + + /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). + /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` + /// variant (which is much less compact and thus more expensive). + DocComment(CommentKind, Symbol), +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub struct AttrPath { + pub segments: Box<[Ident]>, + pub span: Span, +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub struct AttrItem { + pub unsafety: Safety, + // Not lowered to hir::Path because we have no NodeId to resolve to. + pub path: AttrPath, + pub args: AttrArgs, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct Attribute { + pub kind: AttrKind, + pub id: AttrId, + /// Denotes if the attribute decorates the following construct (outer) + /// or the construct this attribute is contained within (inner). + pub style: AttrStyle, + pub span: Span, +} + +impl Attribute { + pub fn get_normal_item(&self) -> &AttrItem { + match &self.kind { + AttrKind::Normal(normal) => &normal, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } + } + + pub fn unwrap_normal_item(self) -> AttrItem { + match self.kind { + AttrKind::Normal(normal) => *normal, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } + } + + pub fn value_lit(&self) -> Option<&MetaItemLit> { + match &self.kind { + AttrKind::Normal(n) => match n.as_ref() { + AttrItem { + args: AttrArgs::Eq { expr, .. }, + .. + } => Some(expr), + _ => None, + }, + _ => None, + } + } +} + +impl AttributeExt for Attribute { + fn id(&self) -> AttrId { + self.id + } + + fn meta_item_list(&self) -> Option> { + match &self.kind { + AttrKind::Normal(n) => match n.as_ref() { + AttrItem { + args: AttrArgs::Delimited(d), + .. + } => ast::MetaItemKind::list_from_tokens(d.tokens.clone()), + _ => None, + }, + _ => None, + } + } + + fn value_str(&self) -> Option { + self.value_lit().and_then(|x| x.value_str()) + } + + fn value_span(&self) -> Option { + self.value_lit().map(|i| i.span) + } + + /// For a single-segment attribute, returns its name; otherwise, returns `None`. + fn ident(&self) -> Option { + match &self.kind { + AttrKind::Normal(n) => { + if let [ident] = n.path.segments.as_ref() { + Some(*ident) + } else { + None + } + } + AttrKind::DocComment(..) => None, + } + } + + fn path_matches(&self, name: &[Symbol]) -> bool { + match &self.kind { + AttrKind::Normal(n) => { + n.path.segments.len() == name.len() + && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) + } + AttrKind::DocComment(..) => false, + } + } + + fn is_doc_comment(&self) -> bool { + matches!(self.kind, AttrKind::DocComment(..)) + } + + fn span(&self) -> Span { + self.span + } + + fn is_word(&self) -> bool { + match &self.kind { + AttrKind::Normal(n) => { + matches!(n.args, AttrArgs::Empty) + } + AttrKind::DocComment(..) => false, + } + } + + fn ident_path(&self) -> Option> { + match &self.kind { + AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()), + AttrKind::DocComment(..) => None, + } + } + + fn doc_str(&self) -> Option { + match &self.kind { + AttrKind::DocComment(.., data) => Some(*data), + AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(), + _ => None, + } + } + fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + match &self.kind { + AttrKind::DocComment(kind, data) => Some((*data, *kind)), + AttrKind::Normal(_) if self.name_or_empty() == sym::doc => { + self.value_str().map(|s| (s, CommentKind::Line)) + } + _ => None, + } + } + + fn style(&self) -> AttrStyle { + self.style + } +} + +// FIXME(fn_delegation): use function delegation instead of manually forwarding +impl Attribute { + pub fn id(&self) -> AttrId { + AttributeExt::id(self) + } + + pub fn name_or_empty(&self) -> Symbol { + AttributeExt::name_or_empty(self) + } + + pub fn meta_item_list(&self) -> Option> { + AttributeExt::meta_item_list(self) + } + + pub fn value_str(&self) -> Option { + AttributeExt::value_str(self) + } + + pub fn value_span(&self) -> Option { + AttributeExt::value_span(self) + } + + pub fn ident(&self) -> Option { + AttributeExt::ident(self) + } + + pub fn path_matches(&self, name: &[Symbol]) -> bool { + AttributeExt::path_matches(self, name) + } + + pub fn is_doc_comment(&self) -> bool { + AttributeExt::is_doc_comment(self) + } + + #[inline] + pub fn has_name(&self, name: Symbol) -> bool { + AttributeExt::has_name(self, name) + } + + pub fn span(&self) -> Span { + AttributeExt::span(self) + } + + pub fn is_word(&self) -> bool { + AttributeExt::is_word(self) + } + + pub fn path(&self) -> SmallVec<[Symbol; 1]> { + AttributeExt::path(self) + } + + pub fn ident_path(&self) -> Option> { + AttributeExt::ident_path(self) + } + + pub fn doc_str(&self) -> Option { + AttributeExt::doc_str(self) + } + + pub fn is_proc_macro_attr(&self) -> bool { + AttributeExt::is_proc_macro_attr(self) + } + + pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + AttributeExt::doc_str_and_comment_kind(self) + } + + pub fn style(&self) -> AttrStyle { + AttributeExt::style(self) + } +} + +/// Attributes owned by a HIR owner. +#[derive(Debug)] +pub struct AttributeMap<'tcx> { + pub map: SortedMap, + // Only present when the crate hash is needed. + pub opt_hash: Option, +} + +impl<'tcx> AttributeMap<'tcx> { + pub const EMPTY: &'static AttributeMap<'static> = &AttributeMap { + map: SortedMap::new(), + opt_hash: Some(Fingerprint::ZERO), + }; + + #[inline] + pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { + self.map.get(&id).copied().unwrap_or(&[]) + } +} + +/// Map of all HIR nodes inside the current owner. +/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node. +/// The HIR tree, including bodies, is pre-hashed. +pub struct OwnerNodes<'tcx> { + /// Pre-computed hash of the full HIR. Used in the crate hash. Only present + /// when incr. comp. is enabled. + pub opt_hash_including_bodies: Option, + /// Full HIR for the current owner. + // The zeroth node's parent should never be accessed: the owner's parent is computed by the + // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally + // used. + pub nodes: IndexVec>, + /// Content of local bodies. + pub bodies: SortedMap>, +} + +impl<'tcx> OwnerNodes<'tcx> { + pub fn node(&self) -> OwnerNode<'tcx> { + // Indexing must ensure it is an OwnerNode. + self.nodes[ItemLocalId::ZERO].node.as_owner().unwrap() + } +} + +impl fmt::Debug for OwnerNodes<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnerNodes") + // Do not print all the pointers to all the nodes, as it would be unreadable. + .field("node", &self.nodes[ItemLocalId::ZERO]) + .field( + "parents", + &fmt::from_fn(|f| { + f.debug_list() + .entries(self.nodes.iter_enumerated().map(|(id, parented_node)| { + fmt::from_fn(move |f| write!(f, "({id:?}, {:?})", parented_node.parent)) + })) + .finish() + }), + ) + .field("bodies", &self.bodies) + .field("opt_hash_including_bodies", &self.opt_hash_including_bodies) + .finish() + } +} + +/// Full information resulting from lowering an AST node. +#[derive(Debug, HashStable_Generic)] +pub struct OwnerInfo<'hir> { + /// Contents of the HIR. + pub nodes: OwnerNodes<'hir>, + /// Map from each nested owner to its parent's local id. + pub parenting: LocalDefIdMap, + /// Collected attributes of the HIR nodes. + pub attrs: AttributeMap<'hir>, + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: ItemLocalMap>, +} + +impl<'tcx> OwnerInfo<'tcx> { + #[inline] + pub fn node(&self) -> OwnerNode<'tcx> { + self.nodes.node() + } +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum MaybeOwner<'tcx> { + Owner(&'tcx OwnerInfo<'tcx>), + NonOwner(HirId), + /// Used as a placeholder for unused LocalDefId. + Phantom, +} + +impl<'tcx> MaybeOwner<'tcx> { + pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> { + match self { + MaybeOwner::Owner(i) => Some(i), + MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None, + } + } + + pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> { + self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner")) + } +} + +/// The top-level data structure that stores the entire contents of +/// the crate currently being compiled. +/// +/// For more details, see the [rustc dev guide]. +/// +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#[derive(Debug)] +pub struct Crate<'hir> { + pub owners: IndexVec>, + // Only present when incr. comp. is enabled. + pub opt_hir_hash: Option, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Closure<'hir> { + pub def_id: LocalDefId, + pub binder: ClosureBinder, + pub constness: Constness, + pub capture_clause: CaptureBy, + pub bound_generic_params: &'hir [GenericParam<'hir>], + pub fn_decl: &'hir FnDecl<'hir>, + pub body: BodyId, + /// The span of the declaration block: 'move |...| -> ...' + pub fn_decl_span: Span, + /// The span of the argument block `|...|` + pub fn_arg_span: Option, + pub kind: ClosureKind, +} + +#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)] +pub enum ClosureKind { + /// This is a plain closure expression. + Closure, + /// This is a coroutine expression -- i.e. a closure expression in which + /// we've found a `yield`. These can arise either from "plain" coroutine + /// usage (e.g. `let x = || { yield (); }`) or from a desugared expression + /// (e.g. `async` and `gen` blocks). + Coroutine(CoroutineKind), + /// This is a coroutine-closure, which is a special sugared closure that + /// returns one of the sugared coroutine (`async`/`gen`/`async gen`). It + /// additionally allows capturing the coroutine's upvars by ref, and therefore + /// needs to be specially treated during analysis and borrowck. + CoroutineClosure(CoroutineDesugaring), +} + +/// A block of statements `{ .. }`, which may have a label (in this case the +/// `targeted_by_break` field will be `true`) and may be `unsafe` by means of +/// the `rules` being anything but `DefaultBlock`. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Block<'hir> { + /// Statements in a block. + pub stmts: &'hir [Stmt<'hir>], + /// An expression at the end of the block + /// without a semicolon, if any. + pub expr: Option<&'hir Expr<'hir>>, + #[stable_hasher(ignore)] + pub hir_id: HirId, + /// Distinguishes between `unsafe { ... }` and `{ ... }`. + pub rules: BlockCheckMode, + /// The span includes the curly braces `{` and `}` around the block. + pub span: Span, + /// If true, then there may exist `break 'a` values that aim to + /// break out of this block early. + /// Used by `'label: {}` blocks and by `try {}` blocks. + pub targeted_by_break: bool, +} + +impl<'hir> Block<'hir> { + pub fn innermost_block(&self) -> &Block<'hir> { + let mut block = self; + while let Some(Expr { + kind: ExprKind::Block(inner_block, _), + .. + }) = block.expr + { + block = inner_block; + } + block + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct TyPat<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: TyPatKind<'hir>, + pub span: Span, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Pat<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: PatKind<'hir>, + pub span: Span, + /// Whether to use default binding modes. + /// At present, this is false only for destructuring assignment. + pub default_binding_modes: bool, +} + +impl<'hir> Pat<'hir> { + fn walk_short_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) -> bool { + if !it(self) { + return false; + } + + use PatKind::*; + match self.kind { + Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true, + Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it), + Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), + TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), + Slice(before, slice, after) => before + .iter() + .chain(slice) + .chain(after.iter()) + .all(|p| p.walk_short_(it)), + } + } + + /// Walk the pattern in left-to-right order, + /// short circuiting (with `.all(..)`) if `false` is returned. + /// + /// Note that when visiting e.g. `Tuple(ps)`, + /// if visiting `ps[0]` returns `false`, + /// then `ps[1]` will not be visited. + pub fn walk_short(&self, mut it: impl FnMut(&Pat<'hir>) -> bool) -> bool { + self.walk_short_(&mut it) + } + + fn walk_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) { + if !it(self) { + return; + } + + use PatKind::*; + match self.kind { + Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {} + Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it), + Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), + TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), + Slice(before, slice, after) => before + .iter() + .chain(slice) + .chain(after.iter()) + .for_each(|p| p.walk_(it)), + } + } + + /// Walk the pattern in left-to-right order. + /// + /// If `it(pat)` returns `false`, the children are not visited. + pub fn walk(&self, mut it: impl FnMut(&Pat<'hir>) -> bool) { + self.walk_(&mut it) + } + + /// Walk the pattern in left-to-right order. + /// + /// If you always want to recurse, prefer this method over `walk`. + pub fn walk_always(&self, mut it: impl FnMut(&Pat<'_>)) { + self.walk(|p| { + it(p); + true + }) + } + + /// Whether this a never pattern. + pub fn is_never_pattern(&self) -> bool { + let mut is_never_pattern = false; + self.walk(|pat| match &pat.kind { + PatKind::Never => { + is_never_pattern = true; + false + } + PatKind::Or(s) => { + is_never_pattern = s.iter().all(|p| p.is_never_pattern()); + false + } + _ => true, + }); + is_never_pattern + } +} + +/// A single field in a struct pattern. +/// +/// Patterns like the fields of Foo `{ x, ref y, ref mut z }` +/// are treated the same as` x: x, y: ref y, z: ref mut z`, +/// except `is_shorthand` is true. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct PatField<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + /// The identifier for the field. + pub ident: Ident, + /// The pattern the field is destructured to. + pub pat: &'hir Pat<'hir>, + pub is_shorthand: bool, + pub span: Span, +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] +pub enum RangeEnd { + Included, + Excluded, +} + +impl fmt::Display for RangeEnd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + RangeEnd::Included => "..=", + RangeEnd::Excluded => "..", + }) + } +} + +// Equivalent to `Option`. That type takes up 16 bytes on 64-bit, but +// this type only takes up 4 bytes, at the cost of being restricted to a +// maximum value of `u32::MAX - 1`. In practice, this is more than enough. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)] +pub struct DotDotPos(u32); + +impl DotDotPos { + /// Panics if n >= u32::MAX. + pub fn new(n: Option) -> Self { + match n { + Some(n) => { + assert!(n < u32::MAX as usize); + Self(n as u32) + } + None => Self(u32::MAX), + } + } + + pub fn as_opt_usize(&self) -> Option { + if self.0 == u32::MAX { + None + } else { + Some(self.0 as usize) + } + } +} + +impl fmt::Debug for DotDotPos { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_opt_usize().fmt(f) + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct PatExpr<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, + pub kind: PatExprKind<'hir>, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum PatExprKind<'hir> { + Lit { + lit: &'hir Lit, + // FIXME: move this into `Lit` and handle negated literal expressions + // once instead of matching on unop neg expressions everywhere. + negated: bool, + }, + ConstBlock(ConstBlock), + /// A path pattern for a unit struct/variant or a (maybe-associated) constant. + Path(QPath<'hir>), +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum TyPatKind<'hir> { + /// A range pattern (e.g., `1..=2` or `1..2`). + Range( + Option<&'hir ConstArg<'hir>>, + Option<&'hir ConstArg<'hir>>, + RangeEnd, + ), + + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum PatKind<'hir> { + /// Represents a wildcard pattern (i.e., `_`). + Wild, + + /// A fresh binding `ref mut binding @ OPT_SUBPATTERN`. + /// The `HirId` is the canonical ID for the variable being bound, + /// (e.g., in `Ok(x) | Err(x)`, both `x` use the same canonical ID), + /// which is the pattern ID of the first `x`. + Binding(BindingMode, HirId, Ident, Option<&'hir Pat<'hir>>), + + /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). + /// The `bool` is `true` in the presence of a `..`. + Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), + + /// A tuple struct/variant pattern `Variant(x, y, .., z)`. + /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. + /// `0 <= position <= subpats.len()` + TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos), + + /// An or-pattern `A | B | C`. + /// Invariant: `pats.len() >= 2`. + Or(&'hir [Pat<'hir>]), + + /// A never pattern `!`. + Never, + + /// A tuple pattern (e.g., `(a, b)`). + /// If the `..` pattern fragment is present, then `Option` denotes its position. + /// `0 <= position <= subpats.len()` + Tuple(&'hir [Pat<'hir>], DotDotPos), + + /// A `box` pattern. + Box(&'hir Pat<'hir>), + + /// A `deref` pattern (currently `deref!()` macro-based syntax). + Deref(&'hir Pat<'hir>), + + /// A reference pattern (e.g., `&mut (a, b)`). + Ref(&'hir Pat<'hir>, Mutability), + + /// A literal, const block or path. + Expr(&'hir PatExpr<'hir>), + + /// A guard pattern (e.g., `x if guard(x)`). + Guard(&'hir Pat<'hir>, &'hir Expr<'hir>), + + /// A range pattern (e.g., `1..=2` or `1..2`). + Range( + Option<&'hir PatExpr<'hir>>, + Option<&'hir PatExpr<'hir>>, + RangeEnd, + ), + + /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`. + /// + /// Here, `slice` is lowered from the syntax `($binding_mode $ident @)? ..`. + /// If `slice` exists, then `after` can be non-empty. + /// + /// The representation for e.g., `[a, b, .., c, d]` is: + /// ```ignore (illustrative) + /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)]) + /// ``` + Slice( + &'hir [Pat<'hir>], + Option<&'hir Pat<'hir>>, + &'hir [Pat<'hir>], + ), + + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), +} + +/// A statement. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Stmt<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: StmtKind<'hir>, + pub span: Span, +} + +/// The contents of a statement. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum StmtKind<'hir> { + /// A local (`let`) binding. + Let(&'hir LetStmt<'hir>), + + /// An item binding. + Item(ItemId), + + /// An expression without a trailing semi-colon (must have unit type). + Expr(&'hir Expr<'hir>), + + /// An expression with a trailing semi-colon (may have any type). + Semi(&'hir Expr<'hir>), +} + +/// Represents a `let` statement (i.e., `let : = ;`). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct LetStmt<'hir> { + pub pat: &'hir Pat<'hir>, + /// Type annotation, if any (otherwise the type will be inferred). + pub ty: Option<&'hir Ty<'hir>>, + /// Initializer expression to set the value, if any. + pub init: Option<&'hir Expr<'hir>>, + /// Else block for a `let...else` binding. + pub els: Option<&'hir Block<'hir>>, + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, + /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop + /// desugaring, or `AssignDesugar` if it is the result of a complex + /// assignment desugaring. Otherwise will be `Normal`. + pub source: LocalSource, +} + +/// Represents a single arm of a `match` expression, e.g. +/// ` (if ) => `. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Arm<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, + /// If this pattern and the optional guard matches, then `body` is evaluated. + pub pat: &'hir Pat<'hir>, + /// Optional guard clause. + pub guard: Option<&'hir Expr<'hir>>, + /// The expression the arm evaluates to if this arm matches. + pub body: &'hir Expr<'hir>, +} + +/// Represents a `let [: ] = ` expression (not a [`LetStmt`]), occurring in an +/// `if-let` or `let-else`, evaluating to a boolean. Typically the pattern is refutable. +/// +/// In an `if let`, imagine it as `if (let = ) { ... }`; in a let-else, it is part of +/// the desugaring to if-let. Only let-else supports the type annotation at present. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct LetExpr<'hir> { + pub span: Span, + pub pat: &'hir Pat<'hir>, + pub ty: Option<&'hir Ty<'hir>>, + pub init: &'hir Expr<'hir>, + /// `Recovered::Yes` when this let expressions is not in a syntactically valid location. + /// Used to prevent building MIR in such situations. + pub recovered: ast::Recovered, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct ExprField<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub ident: Ident, + pub expr: &'hir Expr<'hir>, + pub span: Span, + pub is_shorthand: bool, +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] +pub enum BlockCheckMode { + DefaultBlock, + UnsafeBlock(UnsafeSource), +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] +pub enum UnsafeSource { + CompilerGenerated, + UserProvided, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +pub struct BodyId { + pub hir_id: HirId, +} + +/// The body of a function, closure, or constant value. In the case of +/// a function, the body contains not only the function body itself +/// (which is an expression), but also the argument patterns, since +/// those are something that the caller doesn't really care about. +/// +/// # Examples +/// +/// ``` +/// fn foo((x, y): (u32, u32)) -> u32 { +/// x + y +/// } +/// ``` +/// +/// Here, the `Body` associated with `foo()` would contain: +/// +/// - an `params` array containing the `(x, y)` pattern +/// - a `value` containing the `x + y` expression (maybe wrapped in a block) +/// - `coroutine_kind` would be `None` +/// +/// All bodies have an **owner**, which can be accessed via the HIR +/// map using `body_owner_def_id()`. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Body<'hir> { + pub params: &'hir [Param<'hir>], + pub value: &'hir Expr<'hir>, +} + +impl<'hir> Body<'hir> { + pub fn id(&self) -> BodyId { + BodyId { + hir_id: self.value.hir_id, + } + } +} + +/// The type of source expression that caused this coroutine to be created. +#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)] +pub enum CoroutineKind { + /// A coroutine that comes from a desugaring. + Desugared(CoroutineDesugaring, CoroutineSource), + + /// A coroutine literal created via a `yield` inside a closure. + Coroutine(Movability), +} + +impl CoroutineKind { + pub fn movability(self) -> Movability { + match self { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + | CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => Movability::Static, + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => Movability::Movable, + CoroutineKind::Coroutine(mov) => mov, + } + } +} + +impl CoroutineKind { + pub fn is_fn_like(self) -> bool { + matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn)) + } +} + +impl fmt::Display for CoroutineKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CoroutineKind::Desugared(d, k) => { + d.fmt(f)?; + k.fmt(f) + } + CoroutineKind::Coroutine(_) => f.write_str("coroutine"), + } + } +} + +/// In the case of a coroutine created as part of an async/gen construct, +/// which kind of async/gen construct caused it to be created? +/// +/// This helps error messages but is also used to drive coercions in +/// type-checking (see #60424). +#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy, HashStable_Generic, Encodable, Decodable)] +pub enum CoroutineSource { + /// An explicit `async`/`gen` block written by the user. + Block, + + /// An explicit `async`/`gen` closure written by the user. + Closure, + + /// The `async`/`gen` block generated as the body of an async/gen function. + Fn, +} + +impl fmt::Display for CoroutineSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CoroutineSource::Block => "block", + CoroutineSource::Closure => "closure body", + CoroutineSource::Fn => "fn body", + } + .fmt(f) + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)] +pub enum CoroutineDesugaring { + /// An explicit `async` block or the body of an `async` function. + Async, + + /// An explicit `gen` block or the body of a `gen` function. + Gen, + + /// An explicit `async gen` block or the body of an `async gen` function, + /// which is able to both `yield` and `.await`. + AsyncGen, +} + +impl fmt::Display for CoroutineDesugaring { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CoroutineDesugaring::Async => { + if f.alternate() { + f.write_str("`async` ")?; + } else { + f.write_str("async ")? + } + } + CoroutineDesugaring::Gen => { + if f.alternate() { + f.write_str("`gen` ")?; + } else { + f.write_str("gen ")? + } + } + CoroutineDesugaring::AsyncGen => { + if f.alternate() { + f.write_str("`async gen` ")?; + } else { + f.write_str("async gen ")? + } + } + } + + Ok(()) + } +} + +#[derive(Copy, Clone, Debug)] +pub enum BodyOwnerKind { + /// Functions and methods. + Fn, + + /// Closures + Closure, + + /// Constants and associated constants, also including inline constants. + Const { inline: bool }, + + /// Initializer of a `static` item. + Static(Mutability), +} + +impl BodyOwnerKind { + pub fn is_fn_or_closure(self) -> bool { + match self { + BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false, + } + } +} + +/// The kind of an item that requires const-checking. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ConstContext { + /// A `const fn`. + ConstFn, + + /// A `static` or `static mut`. + Static(Mutability), + + /// A `const`, associated `const`, or other const context. + /// + /// Other contexts include: + /// - Array length expressions + /// - Enum discriminants + /// - Const generics + /// + /// For the most part, other contexts are treated just like a regular `const`, so they are + /// lumped into the same category. + Const { inline: bool }, +} + +impl ConstContext { + /// A description of this const context that can appear between backticks in an error message. + /// + /// E.g. `const` or `static mut`. + pub fn keyword_name(self) -> &'static str { + match self { + Self::Const { .. } => "const", + Self::Static(Mutability::Not) => "static", + Self::Static(Mutability::Mut) => "static mut", + Self::ConstFn => "const fn", + } + } +} + +/// A colloquial, trivially pluralizable description of this const context for use in error +/// messages. +impl fmt::Display for ConstContext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::Const { .. } => write!(f, "constant"), + Self::Static(_) => write!(f, "static"), + Self::ConstFn => write!(f, "constant function"), + } + } +} + +// NOTE: `IntoDiagArg` impl for `ConstContext` lives in `rustc_errors` +// due to a cyclical dependency between hir that crate. + +/// A literal. +pub type Lit = Spanned; + +/// A constant (expression) that's not an item or associated item, +/// but needs its own `DefId` for type-checking, const-eval, etc. +/// These are usually found nested inside types (e.g., array lengths) +/// or expressions (e.g., repeat counts), and also used to define +/// explicit discriminant values for enum variants. +/// +/// You can check if this anon const is a default in a const param +/// `const N: usize = { ... }` with `tcx.hir().opt_const_param_default_param_def_id(..)` +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct AnonConst { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub def_id: LocalDefId, + pub body: BodyId, + pub span: Span, +} + +/// An inline constant expression `const { something }`. +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct ConstBlock { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub def_id: LocalDefId, + pub body: BodyId, +} + +/// An expression. +/// +/// For more details, see the [rust lang reference]. +/// Note that the reference does not document nightly-only features. +/// There may be also slight differences in the names and representation of AST nodes between +/// the compiler and the reference. +/// +/// [rust lang reference]: https://doc.rust-lang.org/reference/expressions.html +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Expr<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: ExprKind<'hir>, + pub span: Span, +} + +impl Expr<'_> { + pub fn precedence(&self) -> ExprPrecedence { + match &self.kind { + ExprKind::Closure(closure) => { + match closure.fn_decl.output { + FnRetTy::DefaultReturn(_) => ExprPrecedence::Jump, + FnRetTy::Return(_) => ExprPrecedence::Unambiguous, + } + } + + ExprKind::Break(..) + | ExprKind::Ret(..) + | ExprKind::Yield(..) + | ExprKind::Become(..) => ExprPrecedence::Jump, + + // Binop-like expr kinds, handled by `AssocOp`. + ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(), + ExprKind::Cast(..) => ExprPrecedence::Cast, + + ExprKind::Assign(..) | + ExprKind::AssignOp(..) => ExprPrecedence::Assign, + + // Unary, prefix + ExprKind::AddrOf(..) + // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`. + // However, this is not exactly right. When `let _ = a` is the LHS of a binop we + // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b` + // but we need to print `(let _ = a) < b` as-is with parens. + | ExprKind::Let(..) + | ExprKind::Unary(..) => ExprPrecedence::Prefix, + + // Never need parens + ExprKind::Array(_) + | ExprKind::Block(..) + | ExprKind::Call(..) + | ExprKind::ConstBlock(_) + | ExprKind::Continue(..) + | ExprKind::Field(..) + | ExprKind::If(..) + | ExprKind::Index(..) + | ExprKind::InlineAsm(..) + | ExprKind::Lit(_) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::MethodCall(..) + | ExprKind::OffsetOf(..) + | ExprKind::Path(..) + | ExprKind::Repeat(..) + | ExprKind::Struct(..) + | ExprKind::Tup(_) + | ExprKind::Type(..) + | ExprKind::UnsafeBinderCast(..) + | ExprKind::Err(_) => ExprPrecedence::Unambiguous, + + ExprKind::DropTemps(expr, ..) => expr.precedence(), + } + } + + /// Whether this looks like a place expr, without checking for deref + /// adjustments. + /// This will return `true` in some potentially surprising cases such as + /// `CONSTANT.field`. + pub fn is_syntactic_place_expr(&self) -> bool { + self.is_place_expr(|_| true) + } + + /// Whether this is a place expression. + /// + /// `allow_projections_from` should return `true` if indexing a field or index expression based + /// on the given expression should be considered a place expression. + pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool { + match self.kind { + ExprKind::Path(QPath::Resolved(_, ref path)) => { + matches!( + path.res, + Res::Local(..) | Res::Def(DefKind::Static { .. }, _) | Res::Err + ) + } + + // Type ascription inherits its place expression kind from its + // operand. See: + // https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries + ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from), + + // Unsafe binder cast preserves place-ness of the sub-expression. + ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from), + + ExprKind::Unary(UnOp::Deref, _) => true, + + ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => { + allow_projections_from(base) || base.is_place_expr(allow_projections_from) + } + + // Lang item paths cannot currently be local variables or statics. + ExprKind::Path(QPath::LangItem(..)) => false, + + // Partially qualified paths in expressions can only legally + // refer to associated items which are always rvalues. + ExprKind::Path(QPath::TypeRelative(..)) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Struct(..) + | ExprKind::Tup(..) + | ExprKind::If(..) + | ExprKind::Match(..) + | ExprKind::Closure { .. } + | ExprKind::Block(..) + | ExprKind::Repeat(..) + | ExprKind::Array(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::Become(..) + | ExprKind::Let(..) + | ExprKind::Loop(..) + | ExprKind::Assign(..) + | ExprKind::InlineAsm(..) + | ExprKind::OffsetOf(..) + | ExprKind::AssignOp(..) + | ExprKind::Lit(_) + | ExprKind::ConstBlock(..) + | ExprKind::Unary(..) + | ExprKind::AddrOf(..) + | ExprKind::Binary(..) + | ExprKind::Yield(..) + | ExprKind::Cast(..) + | ExprKind::DropTemps(..) + | ExprKind::Err(_) => false, + } + } + + /// Check if expression is an integer literal that can be used + /// where `usize` is expected. + pub fn is_size_lit(&self) -> bool { + matches!( + self.kind, + ExprKind::Lit(Lit { + node: LitKind::Int( + _, + LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::Usize) + ), + .. + }) + ) + } + + /// If `Self.kind` is `ExprKind::DropTemps(expr)`, drill down until we get a non-`DropTemps` + /// `Expr`. This is used in suggestions to ignore this `ExprKind` as it is semantically + /// silent, only signaling the ownership system. By doing this, suggestions that check the + /// `ExprKind` of any given `Expr` for presentation don't have to care about `DropTemps` + /// beyond remembering to call this function before doing analysis on it. + pub fn peel_drop_temps(&self) -> &Self { + let mut expr = self; + while let ExprKind::DropTemps(inner) = &expr.kind { + expr = inner; + } + expr + } + + pub fn peel_blocks(&self) -> &Self { + let mut expr = self; + while let ExprKind::Block( + Block { + expr: Some(inner), .. + }, + _, + ) = &expr.kind + { + expr = inner; + } + expr + } + + pub fn peel_borrows(&self) -> &Self { + let mut expr = self; + while let ExprKind::AddrOf(.., inner) = &expr.kind { + expr = inner; + } + expr + } + + pub fn can_have_side_effects(&self) -> bool { + match self.peel_drop_temps().kind { + ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false, + ExprKind::Type(base, _) + | ExprKind::Unary(_, base) + | ExprKind::Field(base, _) + | ExprKind::Index(base, _, _) + | ExprKind::AddrOf(.., base) + | ExprKind::Cast(base, _) + | ExprKind::UnsafeBinderCast(_, base, _) => { + // This isn't exactly true for `Index` and all `Unary`, but we are using this + // method exclusively for diagnostics and there's a *cultural* pressure against + // them being used only for its side-effects. + base.can_have_side_effects() + } + ExprKind::Struct(_, fields, init) => { + let init_side_effects = match init { + StructTailExpr::Base(init) => init.can_have_side_effects(), + StructTailExpr::DefaultFields(_) | StructTailExpr::None => false, + }; + fields + .iter() + .map(|field| field.expr) + .any(|e| e.can_have_side_effects()) + || init_side_effects + } + + ExprKind::Array(args) + | ExprKind::Tup(args) + | ExprKind::Call( + Expr { + kind: + ExprKind::Path(QPath::Resolved( + None, + Path { + res: Res::Def(DefKind::Ctor(_, CtorKind::Fn), _), + .. + }, + )), + .. + }, + args, + ) => args.iter().any(|arg| arg.can_have_side_effects()), + ExprKind::If(..) + | ExprKind::Match(..) + | ExprKind::MethodCall(..) + | ExprKind::Call(..) + | ExprKind::Closure { .. } + | ExprKind::Block(..) + | ExprKind::Repeat(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::Become(..) + | ExprKind::Let(..) + | ExprKind::Loop(..) + | ExprKind::Assign(..) + | ExprKind::InlineAsm(..) + | ExprKind::AssignOp(..) + | ExprKind::ConstBlock(..) + | ExprKind::Binary(..) + | ExprKind::Yield(..) + | ExprKind::DropTemps(..) + | ExprKind::Err(_) => true, + } + } + + /// To a first-order approximation, is this a pattern? + pub fn is_approximately_pattern(&self) -> bool { + match &self.kind { + ExprKind::Array(_) + | ExprKind::Call(..) + | ExprKind::Tup(_) + | ExprKind::Lit(_) + | ExprKind::Path(_) + | ExprKind::Struct(..) => true, + _ => false, + } + } + + /// Whether this and the `other` expression are the same for purposes of an indexing operation. + /// + /// This is only used for diagnostics to see if we have things like `foo[i]` where `foo` is + /// borrowed multiple times with `i`. + pub fn equivalent_for_indexing(&self, other: &Expr<'_>) -> bool { + match (self.kind, other.kind) { + (ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node, + ( + ExprKind::Path(QPath::LangItem(item1, _)), + ExprKind::Path(QPath::LangItem(item2, _)), + ) => item1 == item2, + ( + ExprKind::Path(QPath::Resolved(None, path1)), + ExprKind::Path(QPath::Resolved(None, path2)), + ) => path1.res == path2.res, + ( + ExprKind::Struct( + QPath::LangItem(LangItem::RangeTo, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeTo, _), + [val2], + StructTailExpr::None, + ), + ) + | ( + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusive, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusive, _), + [val2], + StructTailExpr::None, + ), + ) + | ( + ExprKind::Struct( + QPath::LangItem(LangItem::RangeFrom, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeFrom, _), + [val2], + StructTailExpr::None, + ), + ) => val1.expr.equivalent_for_indexing(val2.expr), + ( + ExprKind::Struct( + QPath::LangItem(LangItem::Range, _), + [val1, val3], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::Range, _), + [val2, val4], + StructTailExpr::None, + ), + ) => { + val1.expr.equivalent_for_indexing(val2.expr) + && val3.expr.equivalent_for_indexing(val4.expr) + } + _ => false, + } + } + + pub fn method_ident(&self) -> Option { + match self.kind { + ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), + ExprKind::Unary(_, expr) | ExprKind::AddrOf(.., expr) => expr.method_ident(), + _ => None, + } + } +} + +/// Checks if the specified expression is a built-in range literal. +/// (See: `LoweringContext::lower_expr()`). +pub fn is_range_literal(expr: &Expr<'_>) -> bool { + match expr.kind { + // All built-in range literals but `..=` and `..` desugar to `Struct`s. + ExprKind::Struct(ref qpath, _, _) => matches!( + **qpath, + QPath::LangItem( + LangItem::Range + | LangItem::RangeTo + | LangItem::RangeFrom + | LangItem::RangeFull + | LangItem::RangeToInclusive, + .. + ) + ), + + // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. + ExprKind::Call(ref func, _) => { + matches!( + func.kind, + ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) + ) + } + + _ => false, + } +} + +/// Checks if the specified expression needs parentheses for prefix +/// or postfix suggestions to be valid. +/// For example, `a + b` requires parentheses to suggest `&(a + b)`, +/// but just `a` does not. +/// Similarly, `(a + b).c()` also requires parentheses. +/// This should not be used for other types of suggestions. +pub fn expr_needs_parens(expr: &Expr<'_>) -> bool { + match expr.kind { + // parenthesize if needed (Issue #46756) + ExprKind::Cast(_, _) | ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if is_range_literal(expr) => true, + _ => false, + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum ExprKind<'hir> { + /// Allow anonymous constants from an inline `const` block + ConstBlock(ConstBlock), + /// An array (e.g., `[a, b, c, d]`). + Array(&'hir [Expr<'hir>]), + /// A function call. + /// + /// The first field resolves to the function itself (usually an `ExprKind::Path`), + /// and the second field is the list of arguments. + /// This also represents calling the constructor of + /// tuple-like ADTs such as tuple structs and enum variants. + Call(&'hir Expr<'hir>, &'hir [Expr<'hir>]), + /// A method call (e.g., `x.foo::<'static, Bar, Baz>(a, b, c, d)`). + /// + /// The `PathSegment` represents the method name and its generic arguments + /// (within the angle brackets). + /// The `&Expr` is the expression that evaluates + /// to the object on which the method is being called on (the receiver), + /// and the `&[Expr]` is the rest of the arguments. + /// Thus, `x.foo::(a, b, c, d)` is represented as + /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`. + /// The final `Span` represents the span of the function and arguments + /// (e.g. `foo::(a, b, c, d)` in `x.foo::(a, b, c, d)` + /// + /// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with + /// the `hir_id` of the `MethodCall` node itself. + /// + /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id + MethodCall( + &'hir PathSegment<'hir>, + &'hir Expr<'hir>, + &'hir [Expr<'hir>], + Span, + ), + /// A tuple (e.g., `(a, b, c, d)`). + Tup(&'hir [Expr<'hir>]), + /// A binary operation (e.g., `a + b`, `a * b`). + Binary(BinOp, &'hir Expr<'hir>, &'hir Expr<'hir>), + /// A unary operation (e.g., `!x`, `*x`). + Unary(UnOp, &'hir Expr<'hir>), + /// A literal (e.g., `1`, `"foo"`). + Lit(&'hir Lit), + /// A cast (e.g., `foo as f64`). + Cast(&'hir Expr<'hir>, &'hir Ty<'hir>), + /// A type ascription (e.g., `x: Foo`). See RFC 3307. + Type(&'hir Expr<'hir>, &'hir Ty<'hir>), + /// Wraps the expression in a terminating scope. + /// This makes it semantically equivalent to `{ let _t = expr; _t }`. + /// + /// This construct only exists to tweak the drop order in AST lowering. + /// An example of that is the desugaring of `for` loops. + DropTemps(&'hir Expr<'hir>), + /// A `let $pat = $expr` expression. + /// + /// These are not [`LetStmt`] and only occur as expressions. + /// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`. + Let(&'hir LetExpr<'hir>), + /// An `if` block, with an optional else block. + /// + /// I.e., `if { } else { }`. + If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>), + /// A conditionless loop (can be exited with `break`, `continue`, or `return`). + /// + /// I.e., `'label: loop { }`. + /// + /// The `Span` is the loop header (`for x in y`/`while let pat = expr`). + Loop(&'hir Block<'hir>, Option` +/// * the `G = Ty` in `Trait = Ty>` +/// * the `A: Bound` in `Trait` +/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` +/// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct AssocItemConstraint<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub ident: Ident, + pub gen_args: &'hir GenericArgs<'hir>, + pub kind: AssocItemConstraintKind<'hir>, + pub span: Span, +} + +impl<'hir> AssocItemConstraint<'hir> { + /// Obtain the type on the RHS of an assoc ty equality constraint if applicable. + pub fn ty(self) -> Option<&'hir Ty<'hir>> { + match self.kind { + AssocItemConstraintKind::Equality { term: Term::Ty(ty) } => Some(ty), + _ => None, + } + } + + /// Obtain the const on the RHS of an assoc const equality constraint if applicable. + pub fn ct(self) -> Option<&'hir ConstArg<'hir>> { + match self.kind { + AssocItemConstraintKind::Equality { + term: Term::Const(ct), + } => Some(ct), + _ => None, + } + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum Term<'hir> { + Ty(&'hir Ty<'hir>), + Const(&'hir ConstArg<'hir>), +} + +impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> { + fn from(ty: &'hir Ty<'hir>) -> Self { + Term::Ty(ty) + } +} + +impl<'hir> From<&'hir ConstArg<'hir>> for Term<'hir> { + fn from(c: &'hir ConstArg<'hir>) -> Self { + Term::Const(c) + } +} + +/// The kind of [associated item constraint][AssocItemConstraint]. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum AssocItemConstraintKind<'hir> { + /// An equality constraint for an associated item (e.g., `AssocTy = Ty` in `Trait`). + /// + /// Also known as an *associated item binding* (we *bind* an associated item to a term). + /// + /// Furthermore, associated type equality constraints can also be referred to as *associated + /// type bindings*. Similarly with associated const equality constraints and *associated + /// const bindings*. + Equality { term: Term<'hir> }, + /// A bound on an associated type (e.g., `AssocTy: Bound` in `Trait`). + Bound { bounds: &'hir [GenericBound<'hir>] }, +} + +impl<'hir> AssocItemConstraintKind<'hir> { + pub fn descr(&self) -> &'static str { + match self { + AssocItemConstraintKind::Equality { .. } => "binding", + AssocItemConstraintKind::Bound { .. } => "constraint", + } + } +} + +/// An uninhabited enum used to make `Infer` variants on [`Ty`] and [`ConstArg`] be +/// unreachable. Zero-Variant enums are guaranteed to have the same layout as the never +/// type. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum AmbigArg {} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +#[repr(C)] +/// Represents a type in the `HIR`. +/// +/// The `Unambig` generic parameter represents whether the position this type is from is +/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an +/// ambiguous context the parameter is instantiated with an uninhabited type making the +/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead. +pub struct Ty<'hir, Unambig = ()> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, + pub kind: TyKind<'hir, Unambig>, +} + +impl<'hir> Ty<'hir, AmbigArg> { + /// Converts a `Ty` in an ambiguous position to one in an unambiguous position. + /// + /// Functions accepting an unambiguous types may expect the [`TyKind::Infer`] variant + /// to be used. Care should be taken to separately handle infer types when calling this + /// function as it cannot be handled by downstream code making use of the returned ty. + /// + /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir + /// visitors, or specifically matching on [`GenericArg::Infer`] when handling generic + /// arguments. + /// + /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer] + pub fn as_unambig_ty(&self) -> &Ty<'hir> { + // SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is + // the same across different ZST type arguments. + let ptr = self as *const Ty<'hir, AmbigArg> as *const Ty<'hir, ()>; + unsafe { &*ptr } + } +} + +impl<'hir> Ty<'hir> { + /// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is + /// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions. + /// + /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if + /// infer types are relevant to you then care should be taken to handle them separately. + pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> { + if let TyKind::Infer(()) = self.kind { + return None; + } + + // SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is + // the same across different ZST type arguments. We also asserted that the `self` is + // not a `TyKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`. + let ptr = self as *const Ty<'hir> as *const Ty<'hir, AmbigArg>; + Some(unsafe { &*ptr }) + } +} + +impl<'hir> Ty<'hir, AmbigArg> { + pub fn peel_refs(&self) -> &Ty<'hir> { + let mut final_ty = self.as_unambig_ty(); + while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind { + final_ty = ty; + } + final_ty + } +} + +impl<'hir> Ty<'hir> { + pub fn peel_refs(&self) -> &Self { + let mut final_ty = self; + while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind { + final_ty = ty; + } + final_ty + } + + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn as_generic_param(&self) -> Option<(DefId, Ident)> { + let TyKind::Path(QPath::Resolved(None, path)) = self.kind else { + return None; + }; + let [segment] = &path.segments else { + return None; + }; + match path.res { + Res::Def(DefKind::TyParam, def_id) | Res::SelfTyParam { trait_: def_id } => { + Some((def_id, segment.ident)) + } + _ => None, + } + } + + pub fn find_self_aliases(&self) -> Vec { + use crate::intravisit::Visitor; + struct MyVisitor(Vec); + impl<'v> Visitor<'v> for MyVisitor { + fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) { + if matches!( + &t.kind, + TyKind::Path(QPath::Resolved( + _, + Path { + res: crate::def::Res::SelfTyAlias { .. }, + .. + }, + )) + ) { + self.0.push(t.span); + return; + } + crate::intravisit::walk_ty(self, t); + } + } + + let mut my_visitor = MyVisitor(vec![]); + my_visitor.visit_ty_unambig(self); + my_visitor.0 + } + + /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only + /// to use inference to provide suggestions for the appropriate type if possible. + pub fn is_suggestable_infer_ty(&self) -> bool { + fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool { + generic_args.iter().any(|arg| match arg { + GenericArg::Type(ty) => ty.as_unambig_ty().is_suggestable_infer_ty(), + GenericArg::Infer(_) => true, + _ => false, + }) + } + debug!(?self); + match &self.kind { + TyKind::Infer(()) => true, + TyKind::Slice(ty) => ty.is_suggestable_infer_ty(), + TyKind::Array(ty, length) => { + ty.is_suggestable_infer_ty() || matches!(length.kind, ConstArgKind::Infer(..)) + } + TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), + TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), + TyKind::Path(QPath::TypeRelative(ty, segment)) => { + ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) + } + TyKind::Path(QPath::Resolved(ty_opt, Path { segments, .. })) => { + ty_opt.is_some_and(Self::is_suggestable_infer_ty) + || segments + .iter() + .any(|segment| are_suggestable_generic_args(segment.args().args)) + } + _ => false, + } + } +} + +/// Not represented directly in the AST; referred to by name through a `ty_path`. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)] +pub enum PrimTy { + Int(IntTy), + Uint(UintTy), + Float(FloatTy), + Str, + Bool, + Char, +} + +impl PrimTy { + /// All of the primitive types + pub const ALL: [Self; 19] = [ + // any changes here should also be reflected in `PrimTy::from_name` + Self::Int(IntTy::I8), + Self::Int(IntTy::I16), + Self::Int(IntTy::I32), + Self::Int(IntTy::I64), + Self::Int(IntTy::I128), + Self::Int(IntTy::Isize), + Self::Uint(UintTy::U8), + Self::Uint(UintTy::U16), + Self::Uint(UintTy::U32), + Self::Uint(UintTy::U64), + Self::Uint(UintTy::U128), + Self::Uint(UintTy::Usize), + Self::Float(FloatTy::F16), + Self::Float(FloatTy::F32), + Self::Float(FloatTy::F64), + Self::Float(FloatTy::F128), + Self::Bool, + Self::Char, + Self::Str, + ]; + + /// Like [`PrimTy::name`], but returns a &str instead of a symbol. + /// + /// Used by clippy. + pub fn name_str(self) -> &'static str { + match self { + PrimTy::Int(i) => i.name_str(), + PrimTy::Uint(u) => u.name_str(), + PrimTy::Float(f) => f.name_str(), + PrimTy::Str => "str", + PrimTy::Bool => "bool", + PrimTy::Char => "char", + } + } + + pub fn name(self) -> Symbol { + match self { + PrimTy::Int(i) => i.name(), + PrimTy::Uint(u) => u.name(), + PrimTy::Float(f) => f.name(), + PrimTy::Str => sym::str, + PrimTy::Bool => sym::bool, + PrimTy::Char => sym::char, + } + } + + /// Returns the matching `PrimTy` for a `Symbol` such as "str" or "i32". + /// Returns `None` if no matching type is found. + pub fn from_name(name: Symbol) -> Option { + let ty = match name { + // any changes here should also be reflected in `PrimTy::ALL` + sym::i8 => Self::Int(IntTy::I8), + sym::i16 => Self::Int(IntTy::I16), + sym::i32 => Self::Int(IntTy::I32), + sym::i64 => Self::Int(IntTy::I64), + sym::i128 => Self::Int(IntTy::I128), + sym::isize => Self::Int(IntTy::Isize), + sym::u8 => Self::Uint(UintTy::U8), + sym::u16 => Self::Uint(UintTy::U16), + sym::u32 => Self::Uint(UintTy::U32), + sym::u64 => Self::Uint(UintTy::U64), + sym::u128 => Self::Uint(UintTy::U128), + sym::usize => Self::Uint(UintTy::Usize), + sym::f16 => Self::Float(FloatTy::F16), + sym::f32 => Self::Float(FloatTy::F32), + sym::f64 => Self::Float(FloatTy::F64), + sym::f128 => Self::Float(FloatTy::F128), + sym::bool => Self::Bool, + sym::char => Self::Char, + sym::str => Self::Str, + _ => return None, + }; + Some(ty) + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct FnPtrTy<'hir> { + pub safety: Safety, + pub abi: ExternAbi, + pub generic_params: &'hir [GenericParam<'hir>], + pub decl: &'hir FnDecl<'hir>, + pub param_names: &'hir [Ident], +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct UnsafeBinderTy<'hir> { + pub generic_params: &'hir [GenericParam<'hir>], + pub inner_ty: &'hir Ty<'hir>, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct OpaqueTy<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub def_id: LocalDefId, + pub bounds: GenericBounds<'hir>, + pub origin: OpaqueTyOrigin, + pub span: Span, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum PreciseCapturingArg<'hir> { + Lifetime(&'hir Lifetime), + /// Non-lifetime argument (type or const) + Param(PreciseCapturingNonLifetimeArg), +} + +impl PreciseCapturingArg<'_> { + pub fn hir_id(self) -> HirId { + match self { + PreciseCapturingArg::Lifetime(lt) => lt.hir_id, + PreciseCapturingArg::Param(param) => param.hir_id, + } + } + + pub fn name(self) -> Symbol { + match self { + PreciseCapturingArg::Lifetime(lt) => lt.ident.name, + PreciseCapturingArg::Param(param) => param.ident.name, + } + } +} + +/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param +/// resolution to. Lifetimes don't have this problem, and for them, it's actually +/// kind of detrimental to use a custom node type versus just using [`Lifetime`], +/// since resolve_bound_vars operates on `Lifetime`s. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct PreciseCapturingNonLifetimeArg { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub ident: Ident, + pub res: Res, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic, Encodable, Decodable)] +pub enum RpitContext { + Trait, + TraitImpl, +} + +/// From whence the opaque type came. +#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic, Encodable, Decodable)] +pub enum OpaqueTyOrigin { + /// `-> impl Trait` + FnReturn { + /// The defining function. + parent: D, + // Whether this is an RPITIT (return position impl trait in trait) + in_trait_or_impl: Option, + }, + /// `async fn` + AsyncFn { + /// The defining function. + parent: D, + // Whether this is an AFIT (async fn in trait) + in_trait_or_impl: Option, + }, + /// type aliases: `type Foo = impl Trait;` + TyAlias { + /// The type alias or associated type parent of the TAIT/ATPIT + parent: D, + /// associated types in impl blocks for traits. + in_assoc_ty: bool, + }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)] +pub enum InferDelegationKind { + Input(usize), + Output, +} + +/// The various kinds of types recognized by the compiler. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind` are layout compatible +#[repr(u8, C)] +pub enum TyKind<'hir, Unambig = ()> { + /// Actual type should be inherited from `DefId` signature + InferDelegation(DefId, InferDelegationKind), + /// A variable length slice (i.e., `[T]`). + Slice(&'hir Ty<'hir>), + /// A fixed length array (i.e., `[T; n]`). + Array(&'hir Ty<'hir>, &'hir ConstArg<'hir>), + /// A raw pointer (i.e., `*const T` or `*mut T`). + Ptr(MutTy<'hir>), + /// A reference (i.e., `&'a T` or `&'a mut T`). + Ref(&'hir Lifetime, MutTy<'hir>), + /// A bare function (e.g., `fn(usize) -> bool`). + BareFn(&'hir FnPtrTy<'hir>), + /// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`). + UnsafeBinder(&'hir UnsafeBinderTy<'hir>), + /// The never type (`!`). + Never, + /// A tuple (`(A, B, C, D, ...)`). + Tup(&'hir [Ty<'hir>]), + /// A path to a type definition (`module::module::...::Type`), or an + /// associated type (e.g., ` as Trait>::Type` or `::Target`). + /// + /// Type parameters may be stored in each `PathSegment`. + Path(QPath<'hir>), + /// An opaque type definition itself. This is only used for `impl Trait`. + OpaqueDef(&'hir OpaqueTy<'hir>), + /// A trait ascription type, which is `impl Trait` within a local binding. + TraitAscription(GenericBounds<'hir>), + /// A trait object type `Bound1 + Bound2 + Bound3` + /// where `Bound` is a trait or a lifetime. + /// + /// We use pointer tagging to represent a `&'hir Lifetime` and `TraitObjectSyntax` pair + /// as otherwise this type being `repr(C)` would result in `TyKind` increasing in size. + TraitObject( + &'hir [PolyTraitRef<'hir>], + TaggedRef<'hir, Lifetime, TraitObjectSyntax>, + ), + /// Unused for now. + Typeof(&'hir AnonConst), + /// Placeholder for a type that has failed to be defined. + Err(rustc_span::ErrorGuaranteed), + /// Pattern types (`pattern_type!(u32 is 1..)`) + Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>), + /// `TyKind::Infer` means the type should be inferred instead of it having been + /// specified. This can appear anywhere in a type. + /// + /// This variant is not always used to represent inference types, sometimes + /// [`GenericArg::Infer`] is used instead. + Infer(Unambig), +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum InlineAsmOperand<'hir> { + In { + reg: InlineAsmRegOrRegClass, + expr: &'hir Expr<'hir>, + }, + Out { + reg: InlineAsmRegOrRegClass, + late: bool, + expr: Option<&'hir Expr<'hir>>, + }, + InOut { + reg: InlineAsmRegOrRegClass, + late: bool, + expr: &'hir Expr<'hir>, + }, + SplitInOut { + reg: InlineAsmRegOrRegClass, + late: bool, + in_expr: &'hir Expr<'hir>, + out_expr: Option<&'hir Expr<'hir>>, + }, + Const { + anon_const: &'hir AnonConst, + }, + SymFn { + anon_const: &'hir AnonConst, + }, + SymStatic { + path: QPath<'hir>, + def_id: DefId, + }, + Label { + block: &'hir Block<'hir>, + }, +} + +impl<'hir> InlineAsmOperand<'hir> { + pub fn reg(&self) -> Option { + match *self { + Self::In { reg, .. } + | Self::Out { reg, .. } + | Self::InOut { reg, .. } + | Self::SplitInOut { reg, .. } => Some(reg), + Self::Const { .. } + | Self::SymFn { .. } + | Self::SymStatic { .. } + | Self::Label { .. } => None, + } + } + + pub fn is_clobber(&self) -> bool { + matches!( + self, + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(_), + late: _, + expr: None + } + ) + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct InlineAsm<'hir> { + pub asm_macro: ast::AsmMacro, + pub template: &'hir [InlineAsmTemplatePiece], + pub template_strs: &'hir [(Symbol, Option, Span)], + pub operands: &'hir [(InlineAsmOperand<'hir>, Span)], + pub options: InlineAsmOptions, + pub line_spans: &'hir [Span], +} + +impl InlineAsm<'_> { + pub fn contains_label(&self) -> bool { + self.operands + .iter() + .any(|x| matches!(x.0, InlineAsmOperand::Label { .. })) + } +} + +/// Represents a parameter in a function header. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Param<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub pat: &'hir Pat<'hir>, + pub ty_span: Span, + pub span: Span, +} + +/// Represents the header (not the body) of a function declaration. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct FnDecl<'hir> { + /// The types of the function's parameters. + /// + /// Additional argument data is stored in the function's [body](Body::params). + pub inputs: &'hir [Ty<'hir>], + pub output: FnRetTy<'hir>, + pub c_variadic: bool, + /// Does the function have an implicit self? + pub implicit_self: ImplicitSelfKind, + /// Is lifetime elision allowed. + pub lifetime_elision_allowed: bool, +} + +impl<'hir> FnDecl<'hir> { + pub fn opt_delegation_sig_id(&self) -> Option { + if let FnRetTy::Return(ty) = self.output + && let TyKind::InferDelegation(sig_id, _) = ty.kind + { + return Some(sig_id); + } + None + } +} + +/// Represents what type of implicit self a function has, if any. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum ImplicitSelfKind { + /// Represents a `fn x(self);`. + Imm, + /// Represents a `fn x(mut self);`. + Mut, + /// Represents a `fn x(&self);`. + RefImm, + /// Represents a `fn x(&mut self);`. + RefMut, + /// Represents when a function does not have a self argument or + /// when a function has a `self: X` argument. + None, +} + +impl ImplicitSelfKind { + /// Does this represent an implicit self? + pub fn has_implicit_self(&self) -> bool { + !matches!(*self, ImplicitSelfKind::None) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum IsAsync { + Async(Span), + NotAsync, +} + +impl IsAsync { + pub fn is_async(self) -> bool { + matches!(self, IsAsync::Async(_)) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum Defaultness { + Default { has_value: bool }, + Final, +} + +impl Defaultness { + pub fn has_value(&self) -> bool { + match *self { + Defaultness::Default { has_value } => has_value, + Defaultness::Final => true, + } + } + + pub fn is_final(&self) -> bool { + *self == Defaultness::Final + } + + pub fn is_default(&self) -> bool { + matches!(*self, Defaultness::Default { .. }) + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum FnRetTy<'hir> { + /// Return type is not specified. + /// + /// Functions default to `()` and + /// closures default to inference. Span points to where return + /// type would be inserted. + DefaultReturn(Span), + /// Everything else. + Return(&'hir Ty<'hir>), +} + +impl<'hir> FnRetTy<'hir> { + #[inline] + pub fn span(&self) -> Span { + match *self { + Self::DefaultReturn(span) => span, + Self::Return(ref ty) => ty.span, + } + } + + pub fn is_suggestable_infer_ty(&self) -> Option<&'hir Ty<'hir>> { + if let Self::Return(ty) = self { + if ty.is_suggestable_infer_ty() { + return Some(*ty); + } + } + None + } +} + +/// Represents `for<...>` binder before a closure +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum ClosureBinder { + /// Binder is not specified. + Default, + /// Binder is specified. + /// + /// Span points to the whole `for<...>`. + For { span: Span }, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Mod<'hir> { + pub spans: ModSpans, + pub item_ids: &'hir [ItemId], +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct ModSpans { + /// A span from the first token past `{` to the last token until `}`. + /// For `mod foo;`, the inner span ranges from the first token + /// to the last token in the external file. + pub inner_span: Span, + pub inject_use_span: Span, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct EnumDef<'hir> { + pub variants: &'hir [Variant<'hir>], +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Variant<'hir> { + /// Name of the variant. + pub ident: Ident, + /// Id of the variant (not the constructor, see `VariantData::ctor_hir_id()`). + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub def_id: LocalDefId, + /// Fields and constructor id of the variant. + pub data: VariantData<'hir>, + /// Explicit discriminant (e.g., `Foo = 1`). + pub disr_expr: Option<&'hir AnonConst>, + /// Span + pub span: Span, +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] +pub enum UseKind { + /// One import, e.g., `use foo::bar` or `use foo::bar as baz`. + /// Also produced for each element of a list `use`, e.g. + /// `use foo::{a, b}` lowers to `use foo::a; use foo::b;`. + Single, + + /// Glob import, e.g., `use foo::*`. + Glob, + + /// Degenerate list import, e.g., `use foo::{a, b}` produces + /// an additional `use foo::{}` for performing checks such as + /// unstable feature gating. May be removed in the future. + ListStem, +} + +/// References to traits in impls. +/// +/// `resolve` maps each `TraitRef`'s `ref_id` to its defining trait; that's all +/// that the `ref_id` is for. Note that `ref_id`'s value is not the `HirId` of the +/// trait being referred to but just a unique `HirId` that serves as a key +/// within the resolution map. +#[derive(Clone, Debug, Copy, HashStable_Generic)] +pub struct TraitRef<'hir> { + pub path: &'hir Path<'hir>, + // Don't hash the `ref_id`. It is tracked via the thing it is used to access. + #[stable_hasher(ignore)] + pub hir_ref_id: HirId, +} + +impl TraitRef<'_> { + /// Gets the `DefId` of the referenced trait. It _must_ actually be a trait or trait alias. + pub fn trait_def_id(&self) -> Option { + match self.path.res { + Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did), + Res::Err => None, + res => panic!("{res:?} did not resolve to a trait or trait alias"), + } + } +} + +#[derive(Clone, Debug, Copy, HashStable_Generic)] +pub struct PolyTraitRef<'hir> { + /// The `'a` in `for<'a> Foo<&'a T>`. + pub bound_generic_params: &'hir [GenericParam<'hir>], + + /// The constness and polarity of the trait ref. + /// + /// The `async` modifier is lowered directly into a different trait for now. + pub modifiers: TraitBoundModifiers, + + /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. + pub trait_ref: TraitRef<'hir>, + + pub span: Span, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct FieldDef<'hir> { + pub span: Span, + pub vis_span: Span, + pub ident: Ident, + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub def_id: LocalDefId, + pub ty: &'hir Ty<'hir>, + pub safety: Safety, + pub default: Option<&'hir AnonConst>, +} + +impl FieldDef<'_> { + // Still necessary in couple of places + pub fn is_positional(&self) -> bool { + self.ident.as_str().as_bytes()[0].is_ascii_digit() + } +} + +/// Fields and constructor IDs of enum variants and structs. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum VariantData<'hir> { + /// A struct variant. + /// + /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. + Struct { + fields: &'hir [FieldDef<'hir>], + recovered: ast::Recovered, + }, + /// A tuple variant. + /// + /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. + Tuple( + &'hir [FieldDef<'hir>], + #[stable_hasher(ignore)] HirId, + LocalDefId, + ), + /// A unit variant. + /// + /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`. + Unit(#[stable_hasher(ignore)] HirId, LocalDefId), +} + +impl<'hir> VariantData<'hir> { + /// Return the fields of this variant. + pub fn fields(&self) -> &'hir [FieldDef<'hir>] { + match *self { + VariantData::Struct { fields, .. } | VariantData::Tuple(fields, ..) => fields, + _ => &[], + } + } + + pub fn ctor(&self) -> Option<(CtorKind, HirId, LocalDefId)> { + match *self { + VariantData::Tuple(_, hir_id, def_id) => Some((CtorKind::Fn, hir_id, def_id)), + VariantData::Unit(hir_id, def_id) => Some((CtorKind::Const, hir_id, def_id)), + VariantData::Struct { .. } => None, + } + } + + #[inline] + pub fn ctor_kind(&self) -> Option { + self.ctor().map(|(kind, ..)| kind) + } + + /// Return the `HirId` of this variant's constructor, if it has one. + #[inline] + pub fn ctor_hir_id(&self) -> Option { + self.ctor().map(|(_, hir_id, _)| hir_id) + } + + /// Return the `LocalDefId` of this variant's constructor, if it has one. + #[inline] + pub fn ctor_def_id(&self) -> Option { + self.ctor().map(|(.., def_id)| def_id) + } +} + +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the hir-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)] +pub struct ItemId { + pub owner_id: OwnerId, +} + +impl ItemId { + #[inline] + pub fn hir_id(&self) -> HirId { + // Items are always HIR owners. + HirId::make_owner(self.owner_id.def_id) + } +} + +/// An item +/// +/// The name might be a dummy name in case of anonymous items +/// +/// For more details, see the [rust lang reference]. +/// Note that the reference does not document nightly-only features. +/// There may be also slight differences in the names and representation of AST nodes between +/// the compiler and the reference. +/// +/// [rust lang reference]: https://doc.rust-lang.org/reference/items.html +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Item<'hir> { + pub ident: Ident, + pub owner_id: OwnerId, + pub kind: ItemKind<'hir>, + pub span: Span, + pub vis_span: Span, +} + +impl<'hir> Item<'hir> { + #[inline] + pub fn hir_id(&self) -> HirId { + // Items are always HIR owners. + HirId::make_owner(self.owner_id.def_id) + } + + pub fn item_id(&self) -> ItemId { + ItemId { + owner_id: self.owner_id, + } + } + + /// Check if this is an [`ItemKind::Enum`], [`ItemKind::Struct`] or + /// [`ItemKind::Union`]. + pub fn is_adt(&self) -> bool { + matches!( + self.kind, + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) + ) + } + + /// Check if this is an [`ItemKind::Struct`] or [`ItemKind::Union`]. + pub fn is_struct_or_union(&self) -> bool { + matches!(self.kind, ItemKind::Struct(..) | ItemKind::Union(..)) + } + + expect_methods_self_kind! { + expect_extern_crate, Option, ItemKind::ExternCrate(s), *s; + + expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk); + + expect_static, (&'hir Ty<'hir>, Mutability, BodyId), + ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body); + + expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), + ItemKind::Const(ty, generics, body), (ty, generics, *body); + + expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId), + ItemKind::Fn { sig, generics, body, .. }, (sig, generics, *body); + + expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk); + + expect_mod, &'hir Mod<'hir>, ItemKind::Mod(m), m; + + expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]), + ItemKind::ForeignMod { abi, items }, (*abi, items); + + expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm; + + expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), + ItemKind::TyAlias(ty, generics), (ty, generics); + + expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics); + + expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>), + ItemKind::Struct(data, generics), (data, generics); + + expect_union, (&VariantData<'hir>, &'hir Generics<'hir>), + ItemKind::Union(data, generics), (data, generics); + + expect_trait, + (IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), + ItemKind::Trait(is_auto, safety, generics, bounds, items), + (*is_auto, *safety, generics, bounds, items); + + expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>), + ItemKind::TraitAlias(generics, bounds), (generics, bounds); + + expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp; + } +} + +#[derive( + Copy, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + Encodable, + Decodable, + HashStable_Generic, +)] +pub enum Safety { + Unsafe, + Safe, +} + +impl Safety { + pub fn prefix_str(self) -> &'static str { + match self { + Self::Unsafe => "unsafe ", + Self::Safe => "", + } + } + + #[inline] + pub fn is_unsafe(self) -> bool { + !self.is_safe() + } + + #[inline] + pub fn is_safe(self) -> bool { + match self { + Self::Unsafe => false, + Self::Safe => true, + } + } +} + +impl fmt::Display for Safety { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + Self::Unsafe => "unsafe", + Self::Safe => "safe", + }) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum Constness { + Const, + NotConst, +} + +impl fmt::Display for Constness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + Self::Const => "const", + Self::NotConst => "non-const", + }) + } +} + +/// The actualy safety specified in syntax. We may treat +/// its safety different within the type system to create a +/// "sound by default" system that needs checking this enum +/// explicitly to allow unsafe operations. +#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)] +pub enum HeaderSafety { + /// A safe function annotated with `#[target_features]`. + /// The type system treats this function as an unsafe function, + /// but safety checking will check this enum to treat it as safe + /// and allowing calling other safe target feature functions with + /// the same features without requiring an additional unsafe block. + SafeTargetFeatures, + Normal(Safety), +} + +impl From for HeaderSafety { + fn from(v: Safety) -> Self { + Self::Normal(v) + } +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct FnHeader { + pub safety: HeaderSafety, + pub constness: Constness, + pub asyncness: IsAsync, + pub abi: ExternAbi, +} + +impl FnHeader { + pub fn is_async(&self) -> bool { + matches!(&self.asyncness, IsAsync::Async(_)) + } + + pub fn is_const(&self) -> bool { + matches!(&self.constness, Constness::Const) + } + + pub fn is_unsafe(&self) -> bool { + self.safety().is_unsafe() + } + + pub fn is_safe(&self) -> bool { + self.safety().is_safe() + } + + pub fn safety(&self) -> Safety { + match self.safety { + HeaderSafety::SafeTargetFeatures => Safety::Unsafe, + HeaderSafety::Normal(safety) => safety, + } + } +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum ItemKind<'hir> { + /// An `extern crate` item, with optional *original* crate name if the crate was renamed. + /// + /// E.g., `extern crate foo` or `extern crate foo_bar as foo`. + ExternCrate(Option), + + /// `use foo::bar::*;` or `use foo::bar::baz as quux;` + /// + /// or just + /// + /// `use foo::bar::baz;` (with `as baz` implicitly on the right). + Use(&'hir UsePath<'hir>, UseKind), + + /// A `static` item. + Static(&'hir Ty<'hir>, Mutability, BodyId), + /// A `const` item. + Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), + /// A function declaration. + Fn { + sig: FnSig<'hir>, + generics: &'hir Generics<'hir>, + body: BodyId, + /// Whether this function actually has a body. + /// For functions without a body, `body` is synthesized (to avoid ICEs all over the + /// compiler), but that code should never be translated. + has_body: bool, + }, + /// A MBE macro definition (`macro_rules!` or `macro`). + Macro(&'hir ast::MacroDef, MacroKind), + /// A module. + Mod(&'hir Mod<'hir>), + /// An external module, e.g. `extern { .. }`. + ForeignMod { + abi: ExternAbi, + items: &'hir [ForeignItemRef], + }, + /// Module-level inline assembly (from `global_asm!`). + GlobalAsm(&'hir InlineAsm<'hir>), + /// A type alias, e.g., `type Foo = Bar`. + TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), + /// An enum definition, e.g., `enum Foo {C, D}`. + Enum(EnumDef<'hir>, &'hir Generics<'hir>), + /// A struct definition, e.g., `struct Foo {x: A}`. + Struct(VariantData<'hir>, &'hir Generics<'hir>), + /// A union definition, e.g., `union Foo {x: A, y: B}`. + Union(VariantData<'hir>, &'hir Generics<'hir>), + /// A trait definition. + Trait( + IsAuto, + Safety, + &'hir Generics<'hir>, + GenericBounds<'hir>, + &'hir [TraitItemRef], + ), + /// A trait alias. + TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>), + + /// An implementation, e.g., `impl Trait for Foo { .. }`. + Impl(&'hir Impl<'hir>), +} + +/// Represents an impl block declaration. +/// +/// E.g., `impl $Type { .. }` or `impl $Trait for $Type { .. }` +/// Refer to [`ImplItem`] for an associated item within an impl block. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct Impl<'hir> { + pub constness: Constness, + pub safety: Safety, + pub polarity: ImplPolarity, + pub defaultness: Defaultness, + // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata + // decoding as `Span`s cannot be decoded when a `Session` is not available. + pub defaultness_span: Option, + pub generics: &'hir Generics<'hir>, + + /// The trait being implemented, if any. + pub of_trait: Option>, + + pub self_ty: &'hir Ty<'hir>, + pub items: &'hir [ImplItemRef], +} + +impl ItemKind<'_> { + pub fn generics(&self) -> Option<&Generics<'_>> { + Some(match *self { + ItemKind::Fn { ref generics, .. } + | ItemKind::TyAlias(_, ref generics) + | ItemKind::Const(_, ref generics, _) + | ItemKind::Enum(_, ref generics) + | ItemKind::Struct(_, ref generics) + | ItemKind::Union(_, ref generics) + | ItemKind::Trait(_, _, ref generics, _, _) + | ItemKind::TraitAlias(ref generics, _) + | ItemKind::Impl(Impl { ref generics, .. }) => generics, + _ => return None, + }) + } + + pub fn descr(&self) -> &'static str { + match self { + ItemKind::ExternCrate(..) => "extern crate", + ItemKind::Use(..) => "`use` import", + ItemKind::Static(..) => "static item", + ItemKind::Const(..) => "constant item", + ItemKind::Fn { .. } => "function", + ItemKind::Macro(..) => "macro", + ItemKind::Mod(..) => "module", + ItemKind::ForeignMod { .. } => "extern block", + ItemKind::GlobalAsm(..) => "global asm item", + ItemKind::TyAlias(..) => "type alias", + ItemKind::Enum(..) => "enum", + ItemKind::Struct(..) => "struct", + ItemKind::Union(..) => "union", + ItemKind::Trait(..) => "trait", + ItemKind::TraitAlias(..) => "trait alias", + ItemKind::Impl(..) => "implementation", + } + } +} + +/// A reference from an trait to one of its associated items. This +/// contains the item's id, naturally, but also the item's name and +/// some other high-level details (like whether it is an associated +/// type or method, and whether it is public). This allows other +/// passes to find the impl they want without loading the ID (which +/// means fewer edges in the incremental compilation graph). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct TraitItemRef { + pub id: TraitItemId, + pub ident: Ident, + pub kind: AssocItemKind, + pub span: Span, +} + +/// A reference from an impl to one of its associated items. This +/// contains the item's ID, naturally, but also the item's name and +/// some other high-level details (like whether it is an associated +/// type or method, and whether it is public). This allows other +/// passes to find the impl they want without loading the ID (which +/// means fewer edges in the incremental compilation graph). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct ImplItemRef { + pub id: ImplItemId, + pub ident: Ident, + pub kind: AssocItemKind, + pub span: Span, + /// When we are in a trait impl, link to the trait-item's id. + pub trait_item_def_id: Option, +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] +pub enum AssocItemKind { + Const, + Fn { has_self: bool }, + Type, +} + +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the hir-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] +pub struct ForeignItemId { + pub owner_id: OwnerId, +} + +impl ForeignItemId { + #[inline] + pub fn hir_id(&self) -> HirId { + // Items are always HIR owners. + HirId::make_owner(self.owner_id.def_id) + } +} + +/// A reference from a foreign block to one of its items. This +/// contains the item's ID, naturally, but also the item's name and +/// some other high-level details (like whether it is an associated +/// type or method, and whether it is public). This allows other +/// passes to find the impl they want without loading the ID (which +/// means fewer edges in the incremental compilation graph). +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct ForeignItemRef { + pub id: ForeignItemId, + pub ident: Ident, + pub span: Span, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct ForeignItem<'hir> { + pub ident: Ident, + pub kind: ForeignItemKind<'hir>, + pub owner_id: OwnerId, + pub span: Span, + pub vis_span: Span, +} + +impl ForeignItem<'_> { + #[inline] + pub fn hir_id(&self) -> HirId { + // Items are always HIR owners. + HirId::make_owner(self.owner_id.def_id) + } + + pub fn foreign_item_id(&self) -> ForeignItemId { + ForeignItemId { + owner_id: self.owner_id, + } + } +} + +/// An item within an `extern` block. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum ForeignItemKind<'hir> { + /// A foreign function. + Fn(FnSig<'hir>, &'hir [Ident], &'hir Generics<'hir>), + /// A foreign static item (`static ext: u8`). + Static(&'hir Ty<'hir>, Mutability, Safety), + /// A foreign type. + Type, +} + +/// A variable captured by a closure. +#[derive(Debug, Copy, Clone, HashStable_Generic)] +pub struct Upvar { + /// First span where it is accessed (there can be multiple). + pub span: Span, +} + +// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and +// has length > 0 if the trait is found through an chain of imports, starting with the +// import/use statement in the scope where the trait is used. +#[derive(Debug, Clone, HashStable_Generic)] +pub struct TraitCandidate { + pub def_id: DefId, + pub import_ids: SmallVec<[LocalDefId; 1]>, +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum OwnerNode<'hir> { + Item(&'hir Item<'hir>), + ForeignItem(&'hir ForeignItem<'hir>), + TraitItem(&'hir TraitItem<'hir>), + ImplItem(&'hir ImplItem<'hir>), + Crate(&'hir Mod<'hir>), + Synthetic, +} + +impl<'hir> OwnerNode<'hir> { + pub fn ident(&self) -> Option { + match self { + OwnerNode::Item(Item { ident, .. }) + | OwnerNode::ForeignItem(ForeignItem { ident, .. }) + | OwnerNode::ImplItem(ImplItem { ident, .. }) + | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident), + OwnerNode::Crate(..) | OwnerNode::Synthetic => None, + } + } + + pub fn span(&self) -> Span { + match self { + OwnerNode::Item(Item { span, .. }) + | OwnerNode::ForeignItem(ForeignItem { span, .. }) + | OwnerNode::ImplItem(ImplItem { span, .. }) + | OwnerNode::TraitItem(TraitItem { span, .. }) => *span, + OwnerNode::Crate(Mod { + spans: ModSpans { inner_span, .. }, + .. + }) => *inner_span, + OwnerNode::Synthetic => unreachable!(), + } + } + + pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> { + match self { + OwnerNode::TraitItem(TraitItem { + kind: TraitItemKind::Fn(fn_sig, _), + .. + }) + | OwnerNode::ImplItem(ImplItem { + kind: ImplItemKind::Fn(fn_sig, _), + .. + }) + | OwnerNode::Item(Item { + kind: ItemKind::Fn { sig: fn_sig, .. }, + .. + }) + | OwnerNode::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_sig, _, _), + .. + }) => Some(fn_sig), + _ => None, + } + } + + pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> { + match self { + OwnerNode::TraitItem(TraitItem { + kind: TraitItemKind::Fn(fn_sig, _), + .. + }) + | OwnerNode::ImplItem(ImplItem { + kind: ImplItemKind::Fn(fn_sig, _), + .. + }) + | OwnerNode::Item(Item { + kind: ItemKind::Fn { sig: fn_sig, .. }, + .. + }) + | OwnerNode::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_sig, _, _), + .. + }) => Some(fn_sig.decl), + _ => None, + } + } + + pub fn body_id(&self) -> Option { + match self { + OwnerNode::Item(Item { + kind: + ItemKind::Static(_, _, body) + | ItemKind::Const(_, _, body) + | ItemKind::Fn { body, .. }, + .. + }) + | OwnerNode::TraitItem(TraitItem { + kind: + TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + .. + }) + | OwnerNode::ImplItem(ImplItem { + kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), + .. + }) => Some(*body), + _ => None, + } + } + + pub fn generics(self) -> Option<&'hir Generics<'hir>> { + Node::generics(self.into()) + } + + pub fn def_id(self) -> OwnerId { + match self { + OwnerNode::Item(Item { owner_id, .. }) + | OwnerNode::TraitItem(TraitItem { owner_id, .. }) + | OwnerNode::ImplItem(ImplItem { owner_id, .. }) + | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id, + OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner, + OwnerNode::Synthetic => unreachable!(), + } + } + + /// Check if node is an impl block. + pub fn is_impl_block(&self) -> bool { + matches!( + self, + OwnerNode::Item(Item { + kind: ItemKind::Impl(_), + .. + }) + ) + } + + expect_methods_self! { + expect_item, &'hir Item<'hir>, OwnerNode::Item(n), n; + expect_foreign_item, &'hir ForeignItem<'hir>, OwnerNode::ForeignItem(n), n; + expect_impl_item, &'hir ImplItem<'hir>, OwnerNode::ImplItem(n), n; + expect_trait_item, &'hir TraitItem<'hir>, OwnerNode::TraitItem(n), n; + } +} + +impl<'hir> From<&'hir Item<'hir>> for OwnerNode<'hir> { + fn from(val: &'hir Item<'hir>) -> Self { + OwnerNode::Item(val) + } +} + +impl<'hir> From<&'hir ForeignItem<'hir>> for OwnerNode<'hir> { + fn from(val: &'hir ForeignItem<'hir>) -> Self { + OwnerNode::ForeignItem(val) + } +} + +impl<'hir> From<&'hir ImplItem<'hir>> for OwnerNode<'hir> { + fn from(val: &'hir ImplItem<'hir>) -> Self { + OwnerNode::ImplItem(val) + } +} + +impl<'hir> From<&'hir TraitItem<'hir>> for OwnerNode<'hir> { + fn from(val: &'hir TraitItem<'hir>) -> Self { + OwnerNode::TraitItem(val) + } +} + +impl<'hir> From> for Node<'hir> { + fn from(val: OwnerNode<'hir>) -> Self { + match val { + OwnerNode::Item(n) => Node::Item(n), + OwnerNode::ForeignItem(n) => Node::ForeignItem(n), + OwnerNode::ImplItem(n) => Node::ImplItem(n), + OwnerNode::TraitItem(n) => Node::TraitItem(n), + OwnerNode::Crate(n) => Node::Crate(n), + OwnerNode::Synthetic => Node::Synthetic, + } + } +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum Node<'hir> { + Param(&'hir Param<'hir>), + Item(&'hir Item<'hir>), + ForeignItem(&'hir ForeignItem<'hir>), + TraitItem(&'hir TraitItem<'hir>), + ImplItem(&'hir ImplItem<'hir>), + Variant(&'hir Variant<'hir>), + Field(&'hir FieldDef<'hir>), + AnonConst(&'hir AnonConst), + ConstBlock(&'hir ConstBlock), + ConstArg(&'hir ConstArg<'hir>), + Expr(&'hir Expr<'hir>), + ExprField(&'hir ExprField<'hir>), + Stmt(&'hir Stmt<'hir>), + PathSegment(&'hir PathSegment<'hir>), + Ty(&'hir Ty<'hir>), + AssocItemConstraint(&'hir AssocItemConstraint<'hir>), + TraitRef(&'hir TraitRef<'hir>), + OpaqueTy(&'hir OpaqueTy<'hir>), + TyPat(&'hir TyPat<'hir>), + Pat(&'hir Pat<'hir>), + PatField(&'hir PatField<'hir>), + /// Needed as its own node with its own HirId for tracking + /// the unadjusted type of literals within patterns + /// (e.g. byte str literals not being of slice type). + PatExpr(&'hir PatExpr<'hir>), + Arm(&'hir Arm<'hir>), + Block(&'hir Block<'hir>), + LetStmt(&'hir LetStmt<'hir>), + /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants + /// with synthesized constructors. + Ctor(&'hir VariantData<'hir>), + Lifetime(&'hir Lifetime), + GenericParam(&'hir GenericParam<'hir>), + Crate(&'hir Mod<'hir>), + Infer(&'hir InferArg), + WherePredicate(&'hir WherePredicate<'hir>), + PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg), + // Created by query feeding + Synthetic, + Err(Span), +} + +impl<'hir> Node<'hir> { + /// Get the identifier of this `Node`, if applicable. + /// + /// # Edge cases + /// + /// Calling `.ident()` on a [`Node::Ctor`] will return `None` + /// because `Ctor`s do not have identifiers themselves. + /// Instead, call `.ident()` on the parent struct/variant, like so: + /// + /// ```ignore (illustrative) + /// ctor + /// .ctor_hir_id() + /// .map(|ctor_id| tcx.parent_hir_node(ctor_id)) + /// .and_then(|parent| parent.ident()) + /// ``` + pub fn ident(&self) -> Option { + match self { + Node::TraitItem(TraitItem { ident, .. }) + | Node::ImplItem(ImplItem { ident, .. }) + | Node::ForeignItem(ForeignItem { ident, .. }) + | Node::Field(FieldDef { ident, .. }) + | Node::Variant(Variant { ident, .. }) + | Node::Item(Item { ident, .. }) + | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident), + Node::Lifetime(lt) => Some(lt.ident), + Node::GenericParam(p) => Some(p.name.ident()), + Node::AssocItemConstraint(c) => Some(c.ident), + Node::PatField(f) => Some(f.ident), + Node::ExprField(f) => Some(f.ident), + Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident), + Node::Param(..) + | Node::AnonConst(..) + | Node::ConstBlock(..) + | Node::ConstArg(..) + | Node::Expr(..) + | Node::Stmt(..) + | Node::Block(..) + | Node::Ctor(..) + | Node::Pat(..) + | Node::TyPat(..) + | Node::PatExpr(..) + | Node::Arm(..) + | Node::LetStmt(..) + | Node::Crate(..) + | Node::Ty(..) + | Node::TraitRef(..) + | Node::OpaqueTy(..) + | Node::Infer(..) + | Node::WherePredicate(..) + | Node::Synthetic + | Node::Err(..) => None, + } + } + + pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> { + match self { + Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(fn_sig, _), + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(fn_sig, _), + .. + }) + | Node::Item(Item { + kind: ItemKind::Fn { sig: fn_sig, .. }, + .. + }) + | Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_sig, _, _), + .. + }) => Some(fn_sig.decl), + Node::Expr(Expr { + kind: ExprKind::Closure(Closure { fn_decl, .. }), + .. + }) => Some(fn_decl), + _ => None, + } + } + + /// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`. + pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> { + match self { + Node::Item(Item { + kind: ItemKind::Impl(impl_block), + .. + }) if impl_block + .of_trait + .and_then(|trait_ref| trait_ref.trait_def_id()) + .is_some_and(|trait_id| trait_id == trait_def_id) => + { + Some(impl_block) + } + _ => None, + } + } + + pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> { + match self { + Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(fn_sig, _), + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(fn_sig, _), + .. + }) + | Node::Item(Item { + kind: ItemKind::Fn { sig: fn_sig, .. }, + .. + }) + | Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_sig, _, _), + .. + }) => Some(fn_sig), + _ => None, + } + } + + /// Get the type for constants, assoc types, type aliases and statics. + pub fn ty(self) -> Option<&'hir Ty<'hir>> { + match self { + Node::Item(it) => match it.kind { + ItemKind::TyAlias(ty, _) + | ItemKind::Static(ty, _, _) + | ItemKind::Const(ty, _, _) => Some(ty), + ItemKind::Impl(impl_item) => Some(&impl_item.self_ty), + _ => None, + }, + Node::TraitItem(it) => match it.kind { + TraitItemKind::Const(ty, _) => Some(ty), + TraitItemKind::Type(_, ty) => ty, + _ => None, + }, + Node::ImplItem(it) => match it.kind { + ImplItemKind::Const(ty, _) => Some(ty), + ImplItemKind::Type(ty) => Some(ty), + _ => None, + }, + _ => None, + } + } + + pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> { + match self { + Node::Item(Item { + kind: ItemKind::TyAlias(ty, ..), + .. + }) => Some(ty), + _ => None, + } + } + + #[inline] + pub fn associated_body(&self) -> Option<(LocalDefId, BodyId)> { + match self { + Node::Item(Item { + owner_id, + kind: + ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn { body, .. }, + .. + }) + | Node::TraitItem(TraitItem { + owner_id, + kind: + TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), + .. + }) + | Node::ImplItem(ImplItem { + owner_id, + kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), + .. + }) => Some((owner_id.def_id, *body)), + + Node::Expr(Expr { + kind: ExprKind::Closure(Closure { def_id, body, .. }), + .. + }) => Some((*def_id, *body)), + + Node::AnonConst(constant) => Some((constant.def_id, constant.body)), + Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), + + _ => None, + } + } + + pub fn body_id(&self) -> Option { + Some(self.associated_body()?.1) + } + + pub fn generics(self) -> Option<&'hir Generics<'hir>> { + match self { + Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(_, _, generics), + .. + }) + | Node::TraitItem(TraitItem { generics, .. }) + | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), + Node::Item(item) => item.kind.generics(), + _ => None, + } + } + + pub fn as_owner(self) -> Option> { + match self { + Node::Item(i) => Some(OwnerNode::Item(i)), + Node::ForeignItem(i) => Some(OwnerNode::ForeignItem(i)), + Node::TraitItem(i) => Some(OwnerNode::TraitItem(i)), + Node::ImplItem(i) => Some(OwnerNode::ImplItem(i)), + Node::Crate(i) => Some(OwnerNode::Crate(i)), + Node::Synthetic => Some(OwnerNode::Synthetic), + _ => None, + } + } + + pub fn fn_kind(self) -> Option> { + match self { + Node::Item(i) => match i.kind { + ItemKind::Fn { sig, generics, .. } => { + Some(FnKind::ItemFn(i.ident, generics, sig.header)) + } + _ => None, + }, + Node::TraitItem(ti) => match ti.kind { + TraitItemKind::Fn(ref sig, _) => Some(FnKind::Method(ti.ident, sig)), + _ => None, + }, + Node::ImplItem(ii) => match ii.kind { + ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig)), + _ => None, + }, + Node::Expr(e) => match e.kind { + ExprKind::Closure { .. } => Some(FnKind::Closure), + _ => None, + }, + _ => None, + } + } + + expect_methods_self! { + expect_param, &'hir Param<'hir>, Node::Param(n), n; + expect_item, &'hir Item<'hir>, Node::Item(n), n; + expect_foreign_item, &'hir ForeignItem<'hir>, Node::ForeignItem(n), n; + expect_trait_item, &'hir TraitItem<'hir>, Node::TraitItem(n), n; + expect_impl_item, &'hir ImplItem<'hir>, Node::ImplItem(n), n; + expect_variant, &'hir Variant<'hir>, Node::Variant(n), n; + expect_field, &'hir FieldDef<'hir>, Node::Field(n), n; + expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n; + expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n; + expect_expr, &'hir Expr<'hir>, Node::Expr(n), n; + expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n; + expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n; + expect_path_segment, &'hir PathSegment<'hir>, Node::PathSegment(n), n; + expect_ty, &'hir Ty<'hir>, Node::Ty(n), n; + expect_assoc_item_constraint, &'hir AssocItemConstraint<'hir>, Node::AssocItemConstraint(n), n; + expect_trait_ref, &'hir TraitRef<'hir>, Node::TraitRef(n), n; + expect_opaque_ty, &'hir OpaqueTy<'hir>, Node::OpaqueTy(n), n; + expect_pat, &'hir Pat<'hir>, Node::Pat(n), n; + expect_pat_field, &'hir PatField<'hir>, Node::PatField(n), n; + expect_arm, &'hir Arm<'hir>, Node::Arm(n), n; + expect_block, &'hir Block<'hir>, Node::Block(n), n; + expect_let_stmt, &'hir LetStmt<'hir>, Node::LetStmt(n), n; + expect_ctor, &'hir VariantData<'hir>, Node::Ctor(n), n; + expect_lifetime, &'hir Lifetime, Node::Lifetime(n), n; + expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n; + expect_crate, &'hir Mod<'hir>, Node::Crate(n), n; + expect_infer, &'hir InferArg, Node::Infer(n), n; + expect_closure, &'hir Closure<'hir>, Node::Expr(Expr { kind: ExprKind::Closure(n), .. }), n; + } +} + +// Some nodes are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::*; + // tidy-alphabetical-start + static_assert_size!(Block<'_>, 48); + static_assert_size!(Body<'_>, 24); + static_assert_size!(Expr<'_>, 64); + static_assert_size!(ExprKind<'_>, 48); + static_assert_size!(FnDecl<'_>, 40); + static_assert_size!(ForeignItem<'_>, 88); + static_assert_size!(ForeignItemKind<'_>, 56); + static_assert_size!(GenericArg<'_>, 16); + static_assert_size!(GenericBound<'_>, 64); + static_assert_size!(Generics<'_>, 56); + static_assert_size!(Impl<'_>, 80); + static_assert_size!(ImplItem<'_>, 88); + static_assert_size!(ImplItemKind<'_>, 40); + static_assert_size!(Item<'_>, 88); + static_assert_size!(ItemKind<'_>, 56); + static_assert_size!(LetStmt<'_>, 64); + static_assert_size!(Param<'_>, 32); + static_assert_size!(Pat<'_>, 72); + static_assert_size!(Path<'_>, 40); + static_assert_size!(PathSegment<'_>, 48); + static_assert_size!(PatKind<'_>, 48); + static_assert_size!(QPath<'_>, 24); + static_assert_size!(Res, 12); + static_assert_size!(Stmt<'_>, 32); + static_assert_size!(StmtKind<'_>, 16); + static_assert_size!(TraitItem<'_>, 88); + static_assert_size!(TraitItemKind<'_>, 48); + static_assert_size!(Ty<'_>, 48); + static_assert_size!(TyKind<'_>, 32); + // tidy-alphabetical-end +} + +#[cfg(test)] +mod tests; diff --git a/match_hir/assets/visit.rs b/match_hir/assets/visit.rs new file mode 100644 index 000000000..5d87e63f7 --- /dev/null +++ b/match_hir/assets/visit.rs @@ -0,0 +1,3848 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#![allow(unused_variables)] +#![allow(clippy::needless_pass_by_ref_mut)] +#[cfg(any(feature = "full", feature = "derive"))] +use crate::punctuated::Punctuated; +#[cfg(feature = "full")] +macro_rules! full { + ($e:expr) => { + $e + }; +} +#[cfg(all(feature = "derive", not(feature = "full")))] +macro_rules! full { + ($e:expr) => { + unreachable!() + }; +} +macro_rules! skip { + ($($tt:tt)*) => {}; +} +/// Syntax tree traversal to walk a shared borrow of a syntax tree. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: self +pub trait Visit<'ast> { + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_abi(&mut self, i: &'ast crate::Abi) { + visit_abi(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_angle_bracketed_generic_arguments( + &mut self, + i: &'ast crate::AngleBracketedGenericArguments, + ) { + visit_angle_bracketed_generic_arguments(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_arm(&mut self, i: &'ast crate::Arm) { + visit_arm(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_assoc_const(&mut self, i: &'ast crate::AssocConst) { + visit_assoc_const(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_assoc_type(&mut self, i: &'ast crate::AssocType) { + visit_assoc_type(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_attr_style(&mut self, i: &'ast crate::AttrStyle) { + visit_attr_style(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_attribute(&mut self, i: &'ast crate::Attribute) { + visit_attribute(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_bare_fn_arg(&mut self, i: &'ast crate::BareFnArg) { + visit_bare_fn_arg(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_bare_variadic(&mut self, i: &'ast crate::BareVariadic) { + visit_bare_variadic(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_bin_op(&mut self, i: &'ast crate::BinOp) { + visit_bin_op(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_block(&mut self, i: &'ast crate::Block) { + visit_block(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_bound_lifetimes(&mut self, i: &'ast crate::BoundLifetimes) { + visit_bound_lifetimes(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_const_param(&mut self, i: &'ast crate::ConstParam) { + visit_const_param(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_constraint(&mut self, i: &'ast crate::Constraint) { + visit_constraint(self, i); + } + #[cfg(feature = "derive")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] + fn visit_data(&mut self, i: &'ast crate::Data) { + visit_data(self, i); + } + #[cfg(feature = "derive")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] + fn visit_data_enum(&mut self, i: &'ast crate::DataEnum) { + visit_data_enum(self, i); + } + #[cfg(feature = "derive")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] + fn visit_data_struct(&mut self, i: &'ast crate::DataStruct) { + visit_data_struct(self, i); + } + #[cfg(feature = "derive")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] + fn visit_data_union(&mut self, i: &'ast crate::DataUnion) { + visit_data_union(self, i); + } + #[cfg(feature = "derive")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] + fn visit_derive_input(&mut self, i: &'ast crate::DeriveInput) { + visit_derive_input(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr(&mut self, i: &'ast crate::Expr) { + visit_expr(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_array(&mut self, i: &'ast crate::ExprArray) { + visit_expr_array(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_assign(&mut self, i: &'ast crate::ExprAssign) { + visit_expr_assign(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_async(&mut self, i: &'ast crate::ExprAsync) { + visit_expr_async(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_await(&mut self, i: &'ast crate::ExprAwait) { + visit_expr_await(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_binary(&mut self, i: &'ast crate::ExprBinary) { + visit_expr_binary(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_block(&mut self, i: &'ast crate::ExprBlock) { + visit_expr_block(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_break(&mut self, i: &'ast crate::ExprBreak) { + visit_expr_break(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_call(&mut self, i: &'ast crate::ExprCall) { + visit_expr_call(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_cast(&mut self, i: &'ast crate::ExprCast) { + visit_expr_cast(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_closure(&mut self, i: &'ast crate::ExprClosure) { + visit_expr_closure(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_const(&mut self, i: &'ast crate::ExprConst) { + visit_expr_const(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_continue(&mut self, i: &'ast crate::ExprContinue) { + visit_expr_continue(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_field(&mut self, i: &'ast crate::ExprField) { + visit_expr_field(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_for_loop(&mut self, i: &'ast crate::ExprForLoop) { + visit_expr_for_loop(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_group(&mut self, i: &'ast crate::ExprGroup) { + visit_expr_group(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_if(&mut self, i: &'ast crate::ExprIf) { + visit_expr_if(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_index(&mut self, i: &'ast crate::ExprIndex) { + visit_expr_index(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_infer(&mut self, i: &'ast crate::ExprInfer) { + visit_expr_infer(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_let(&mut self, i: &'ast crate::ExprLet) { + visit_expr_let(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_lit(&mut self, i: &'ast crate::ExprLit) { + visit_expr_lit(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_loop(&mut self, i: &'ast crate::ExprLoop) { + visit_expr_loop(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_macro(&mut self, i: &'ast crate::ExprMacro) { + visit_expr_macro(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_match(&mut self, i: &'ast crate::ExprMatch) { + visit_expr_match(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_method_call(&mut self, i: &'ast crate::ExprMethodCall) { + visit_expr_method_call(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_paren(&mut self, i: &'ast crate::ExprParen) { + visit_expr_paren(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_path(&mut self, i: &'ast crate::ExprPath) { + visit_expr_path(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_range(&mut self, i: &'ast crate::ExprRange) { + visit_expr_range(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_reference(&mut self, i: &'ast crate::ExprReference) { + visit_expr_reference(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_repeat(&mut self, i: &'ast crate::ExprRepeat) { + visit_expr_repeat(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_return(&mut self, i: &'ast crate::ExprReturn) { + visit_expr_return(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_struct(&mut self, i: &'ast crate::ExprStruct) { + visit_expr_struct(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_try(&mut self, i: &'ast crate::ExprTry) { + visit_expr_try(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_try_block(&mut self, i: &'ast crate::ExprTryBlock) { + visit_expr_try_block(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_tuple(&mut self, i: &'ast crate::ExprTuple) { + visit_expr_tuple(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_expr_unary(&mut self, i: &'ast crate::ExprUnary) { + visit_expr_unary(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_unsafe(&mut self, i: &'ast crate::ExprUnsafe) { + visit_expr_unsafe(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_while(&mut self, i: &'ast crate::ExprWhile) { + visit_expr_while(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_expr_yield(&mut self, i: &'ast crate::ExprYield) { + visit_expr_yield(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_field(&mut self, i: &'ast crate::Field) { + visit_field(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_field_mutability(&mut self, i: &'ast crate::FieldMutability) { + visit_field_mutability(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_field_pat(&mut self, i: &'ast crate::FieldPat) { + visit_field_pat(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_field_value(&mut self, i: &'ast crate::FieldValue) { + visit_field_value(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_fields(&mut self, i: &'ast crate::Fields) { + visit_fields(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_fields_named(&mut self, i: &'ast crate::FieldsNamed) { + visit_fields_named(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_fields_unnamed(&mut self, i: &'ast crate::FieldsUnnamed) { + visit_fields_unnamed(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_file(&mut self, i: &'ast crate::File) { + visit_file(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_fn_arg(&mut self, i: &'ast crate::FnArg) { + visit_fn_arg(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_foreign_item(&mut self, i: &'ast crate::ForeignItem) { + visit_foreign_item(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_foreign_item_fn(&mut self, i: &'ast crate::ForeignItemFn) { + visit_foreign_item_fn(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_foreign_item_macro(&mut self, i: &'ast crate::ForeignItemMacro) { + visit_foreign_item_macro(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_foreign_item_static(&mut self, i: &'ast crate::ForeignItemStatic) { + visit_foreign_item_static(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_foreign_item_type(&mut self, i: &'ast crate::ForeignItemType) { + visit_foreign_item_type(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_generic_argument(&mut self, i: &'ast crate::GenericArgument) { + visit_generic_argument(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_generic_param(&mut self, i: &'ast crate::GenericParam) { + visit_generic_param(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_generics(&mut self, i: &'ast crate::Generics) { + visit_generics(self, i); + } + fn visit_ident(&mut self, i: &'ast proc_macro2::Ident) { + visit_ident(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_impl_item(&mut self, i: &'ast crate::ImplItem) { + visit_impl_item(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_impl_item_const(&mut self, i: &'ast crate::ImplItemConst) { + visit_impl_item_const(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_impl_item_fn(&mut self, i: &'ast crate::ImplItemFn) { + visit_impl_item_fn(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_impl_item_macro(&mut self, i: &'ast crate::ImplItemMacro) { + visit_impl_item_macro(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_impl_item_type(&mut self, i: &'ast crate::ImplItemType) { + visit_impl_item_type(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_impl_restriction(&mut self, i: &'ast crate::ImplRestriction) { + visit_impl_restriction(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_index(&mut self, i: &'ast crate::Index) { + visit_index(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item(&mut self, i: &'ast crate::Item) { + visit_item(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_const(&mut self, i: &'ast crate::ItemConst) { + visit_item_const(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_enum(&mut self, i: &'ast crate::ItemEnum) { + visit_item_enum(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_extern_crate(&mut self, i: &'ast crate::ItemExternCrate) { + visit_item_extern_crate(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_fn(&mut self, i: &'ast crate::ItemFn) { + visit_item_fn(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_foreign_mod(&mut self, i: &'ast crate::ItemForeignMod) { + visit_item_foreign_mod(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_impl(&mut self, i: &'ast crate::ItemImpl) { + visit_item_impl(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_macro(&mut self, i: &'ast crate::ItemMacro) { + visit_item_macro(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_mod(&mut self, i: &'ast crate::ItemMod) { + visit_item_mod(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_static(&mut self, i: &'ast crate::ItemStatic) { + visit_item_static(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_struct(&mut self, i: &'ast crate::ItemStruct) { + visit_item_struct(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_trait(&mut self, i: &'ast crate::ItemTrait) { + visit_item_trait(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_trait_alias(&mut self, i: &'ast crate::ItemTraitAlias) { + visit_item_trait_alias(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_type(&mut self, i: &'ast crate::ItemType) { + visit_item_type(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_union(&mut self, i: &'ast crate::ItemUnion) { + visit_item_union(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_item_use(&mut self, i: &'ast crate::ItemUse) { + visit_item_use(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_label(&mut self, i: &'ast crate::Label) { + visit_label(self, i); + } + fn visit_lifetime(&mut self, i: &'ast crate::Lifetime) { + visit_lifetime(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_lifetime_param(&mut self, i: &'ast crate::LifetimeParam) { + visit_lifetime_param(self, i); + } + fn visit_lit(&mut self, i: &'ast crate::Lit) { + visit_lit(self, i); + } + fn visit_lit_bool(&mut self, i: &'ast crate::LitBool) { + visit_lit_bool(self, i); + } + fn visit_lit_byte(&mut self, i: &'ast crate::LitByte) { + visit_lit_byte(self, i); + } + fn visit_lit_byte_str(&mut self, i: &'ast crate::LitByteStr) { + visit_lit_byte_str(self, i); + } + fn visit_lit_char(&mut self, i: &'ast crate::LitChar) { + visit_lit_char(self, i); + } + fn visit_lit_float(&mut self, i: &'ast crate::LitFloat) { + visit_lit_float(self, i); + } + fn visit_lit_int(&mut self, i: &'ast crate::LitInt) { + visit_lit_int(self, i); + } + fn visit_lit_str(&mut self, i: &'ast crate::LitStr) { + visit_lit_str(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_local(&mut self, i: &'ast crate::Local) { + visit_local(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_local_init(&mut self, i: &'ast crate::LocalInit) { + visit_local_init(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_macro(&mut self, i: &'ast crate::Macro) { + visit_macro(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_macro_delimiter(&mut self, i: &'ast crate::MacroDelimiter) { + visit_macro_delimiter(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_member(&mut self, i: &'ast crate::Member) { + visit_member(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_meta(&mut self, i: &'ast crate::Meta) { + visit_meta(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_meta_list(&mut self, i: &'ast crate::MetaList) { + visit_meta_list(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_meta_name_value(&mut self, i: &'ast crate::MetaNameValue) { + visit_meta_name_value(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_parenthesized_generic_arguments( + &mut self, + i: &'ast crate::ParenthesizedGenericArguments, + ) { + visit_parenthesized_generic_arguments(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat(&mut self, i: &'ast crate::Pat) { + visit_pat(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_ident(&mut self, i: &'ast crate::PatIdent) { + visit_pat_ident(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_or(&mut self, i: &'ast crate::PatOr) { + visit_pat_or(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_paren(&mut self, i: &'ast crate::PatParen) { + visit_pat_paren(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_reference(&mut self, i: &'ast crate::PatReference) { + visit_pat_reference(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_rest(&mut self, i: &'ast crate::PatRest) { + visit_pat_rest(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_slice(&mut self, i: &'ast crate::PatSlice) { + visit_pat_slice(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_struct(&mut self, i: &'ast crate::PatStruct) { + visit_pat_struct(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_tuple(&mut self, i: &'ast crate::PatTuple) { + visit_pat_tuple(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_tuple_struct(&mut self, i: &'ast crate::PatTupleStruct) { + visit_pat_tuple_struct(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_type(&mut self, i: &'ast crate::PatType) { + visit_pat_type(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_pat_wild(&mut self, i: &'ast crate::PatWild) { + visit_pat_wild(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_path(&mut self, i: &'ast crate::Path) { + visit_path(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_path_arguments(&mut self, i: &'ast crate::PathArguments) { + visit_path_arguments(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_path_segment(&mut self, i: &'ast crate::PathSegment) { + visit_path_segment(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_predicate_lifetime(&mut self, i: &'ast crate::PredicateLifetime) { + visit_predicate_lifetime(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_predicate_type(&mut self, i: &'ast crate::PredicateType) { + visit_predicate_type(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_qself(&mut self, i: &'ast crate::QSelf) { + visit_qself(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_range_limits(&mut self, i: &'ast crate::RangeLimits) { + visit_range_limits(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_receiver(&mut self, i: &'ast crate::Receiver) { + visit_receiver(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_return_type(&mut self, i: &'ast crate::ReturnType) { + visit_return_type(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_signature(&mut self, i: &'ast crate::Signature) { + visit_signature(self, i); + } + fn visit_span(&mut self, i: &proc_macro2::Span) { + visit_span(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_static_mutability(&mut self, i: &'ast crate::StaticMutability) { + visit_static_mutability(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_stmt(&mut self, i: &'ast crate::Stmt) { + visit_stmt(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_stmt_macro(&mut self, i: &'ast crate::StmtMacro) { + visit_stmt_macro(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_trait_bound(&mut self, i: &'ast crate::TraitBound) { + visit_trait_bound(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_trait_bound_modifier(&mut self, i: &'ast crate::TraitBoundModifier) { + visit_trait_bound_modifier(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_trait_item(&mut self, i: &'ast crate::TraitItem) { + visit_trait_item(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_trait_item_const(&mut self, i: &'ast crate::TraitItemConst) { + visit_trait_item_const(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_trait_item_fn(&mut self, i: &'ast crate::TraitItemFn) { + visit_trait_item_fn(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_trait_item_macro(&mut self, i: &'ast crate::TraitItemMacro) { + visit_trait_item_macro(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_trait_item_type(&mut self, i: &'ast crate::TraitItemType) { + visit_trait_item_type(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type(&mut self, i: &'ast crate::Type) { + visit_type(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_array(&mut self, i: &'ast crate::TypeArray) { + visit_type_array(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_bare_fn(&mut self, i: &'ast crate::TypeBareFn) { + visit_type_bare_fn(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_group(&mut self, i: &'ast crate::TypeGroup) { + visit_type_group(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_impl_trait(&mut self, i: &'ast crate::TypeImplTrait) { + visit_type_impl_trait(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_infer(&mut self, i: &'ast crate::TypeInfer) { + visit_type_infer(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_macro(&mut self, i: &'ast crate::TypeMacro) { + visit_type_macro(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_never(&mut self, i: &'ast crate::TypeNever) { + visit_type_never(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_param(&mut self, i: &'ast crate::TypeParam) { + visit_type_param(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_param_bound(&mut self, i: &'ast crate::TypeParamBound) { + visit_type_param_bound(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_paren(&mut self, i: &'ast crate::TypeParen) { + visit_type_paren(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_path(&mut self, i: &'ast crate::TypePath) { + visit_type_path(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_ptr(&mut self, i: &'ast crate::TypePtr) { + visit_type_ptr(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_reference(&mut self, i: &'ast crate::TypeReference) { + visit_type_reference(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_slice(&mut self, i: &'ast crate::TypeSlice) { + visit_type_slice(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_trait_object(&mut self, i: &'ast crate::TypeTraitObject) { + visit_type_trait_object(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_type_tuple(&mut self, i: &'ast crate::TypeTuple) { + visit_type_tuple(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_un_op(&mut self, i: &'ast crate::UnOp) { + visit_un_op(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_use_glob(&mut self, i: &'ast crate::UseGlob) { + visit_use_glob(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_use_group(&mut self, i: &'ast crate::UseGroup) { + visit_use_group(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_use_name(&mut self, i: &'ast crate::UseName) { + visit_use_name(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_use_path(&mut self, i: &'ast crate::UsePath) { + visit_use_path(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_use_rename(&mut self, i: &'ast crate::UseRename) { + visit_use_rename(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_use_tree(&mut self, i: &'ast crate::UseTree) { + visit_use_tree(self, i); + } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + fn visit_variadic(&mut self, i: &'ast crate::Variadic) { + visit_variadic(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_variant(&mut self, i: &'ast crate::Variant) { + visit_variant(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_vis_restricted(&mut self, i: &'ast crate::VisRestricted) { + visit_vis_restricted(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_visibility(&mut self, i: &'ast crate::Visibility) { + visit_visibility(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_where_clause(&mut self, i: &'ast crate::WhereClause) { + visit_where_clause(self, i); + } + #[cfg(any(feature = "derive", feature = "full"))] + #[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] + fn visit_where_predicate(&mut self, i: &'ast crate::WherePredicate) { + visit_where_predicate(self, i); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_abi<'ast, V>(v: &mut V, node: &'ast crate::Abi) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.extern_token); + if let Some(it) = &node.name { + v.visit_lit_str(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_angle_bracketed_generic_arguments<'ast, V>( + v: &mut V, + node: &'ast crate::AngleBracketedGenericArguments, +) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.colon2_token); + skip!(node.lt_token); + for el in Punctuated::pairs(&node.args) { + let it = el.value(); + v.visit_generic_argument(it); + } + skip!(node.gt_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_arm<'ast, V>(v: &mut V, node: &'ast crate::Arm) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_pat(&node.pat); + if let Some(it) = &node.guard { + skip!((it).0); + v.visit_expr(&*(it).1); + } + skip!(node.fat_arrow_token); + v.visit_expr(&*node.body); + skip!(node.comma); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_assoc_const<'ast, V>(v: &mut V, node: &'ast crate::AssocConst) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + if let Some(it) = &node.generics { + v.visit_angle_bracketed_generic_arguments(it); + } + skip!(node.eq_token); + v.visit_expr(&node.value); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_assoc_type<'ast, V>(v: &mut V, node: &'ast crate::AssocType) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + if let Some(it) = &node.generics { + v.visit_angle_bracketed_generic_arguments(it); + } + skip!(node.eq_token); + v.visit_type(&node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_attr_style<'ast, V>(v: &mut V, node: &'ast crate::AttrStyle) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::AttrStyle::Outer => {} + crate::AttrStyle::Inner(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_attribute<'ast, V>(v: &mut V, node: &'ast crate::Attribute) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.pound_token); + v.visit_attr_style(&node.style); + skip!(node.bracket_token); + v.visit_meta(&node.meta); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_bare_fn_arg<'ast, V>(v: &mut V, node: &'ast crate::BareFnArg) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.name { + v.visit_ident(&(it).0); + skip!((it).1); + } + v.visit_type(&node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_bare_variadic<'ast, V>(v: &mut V, node: &'ast crate::BareVariadic) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.name { + v.visit_ident(&(it).0); + skip!((it).1); + } + skip!(node.dots); + skip!(node.comma); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_bin_op<'ast, V>(v: &mut V, node: &'ast crate::BinOp) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::BinOp::Add(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Sub(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Mul(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Div(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Rem(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::And(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Or(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::BitXor(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::BitAnd(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::BitOr(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Shl(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Shr(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Eq(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Lt(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Le(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Ne(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Ge(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::Gt(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::AddAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::SubAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::MulAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::DivAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::RemAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::BitXorAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::BitAndAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::BitOrAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::ShlAssign(_binding_0) => { + skip!(_binding_0); + } + crate::BinOp::ShrAssign(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_block<'ast, V>(v: &mut V, node: &'ast crate::Block) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.brace_token); + for it in &node.stmts { + v.visit_stmt(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_bound_lifetimes<'ast, V>(v: &mut V, node: &'ast crate::BoundLifetimes) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.for_token); + skip!(node.lt_token); + for el in Punctuated::pairs(&node.lifetimes) { + let it = el.value(); + v.visit_generic_param(it); + } + skip!(node.gt_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_const_param<'ast, V>(v: &mut V, node: &'ast crate::ConstParam) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.const_token); + v.visit_ident(&node.ident); + skip!(node.colon_token); + v.visit_type(&node.ty); + skip!(node.eq_token); + if let Some(it) = &node.default { + v.visit_expr(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_constraint<'ast, V>(v: &mut V, node: &'ast crate::Constraint) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + if let Some(it) = &node.generics { + v.visit_angle_bracketed_generic_arguments(it); + } + skip!(node.colon_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } +} +#[cfg(feature = "derive")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub fn visit_data<'ast, V>(v: &mut V, node: &'ast crate::Data) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Data::Struct(_binding_0) => { + v.visit_data_struct(_binding_0); + } + crate::Data::Enum(_binding_0) => { + v.visit_data_enum(_binding_0); + } + crate::Data::Union(_binding_0) => { + v.visit_data_union(_binding_0); + } + } +} +#[cfg(feature = "derive")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub fn visit_data_enum<'ast, V>(v: &mut V, node: &'ast crate::DataEnum) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.enum_token); + skip!(node.brace_token); + for el in Punctuated::pairs(&node.variants) { + let it = el.value(); + v.visit_variant(it); + } +} +#[cfg(feature = "derive")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub fn visit_data_struct<'ast, V>(v: &mut V, node: &'ast crate::DataStruct) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.struct_token); + v.visit_fields(&node.fields); + skip!(node.semi_token); +} +#[cfg(feature = "derive")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub fn visit_data_union<'ast, V>(v: &mut V, node: &'ast crate::DataUnion) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.union_token); + v.visit_fields_named(&node.fields); +} +#[cfg(feature = "derive")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub fn visit_derive_input<'ast, V>(v: &mut V, node: &'ast crate::DeriveInput) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + v.visit_data(&node.data); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr<'ast, V>(v: &mut V, node: &'ast crate::Expr) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Expr::Array(_binding_0) => { + full!(v.visit_expr_array(_binding_0)); + } + crate::Expr::Assign(_binding_0) => { + full!(v.visit_expr_assign(_binding_0)); + } + crate::Expr::Async(_binding_0) => { + full!(v.visit_expr_async(_binding_0)); + } + crate::Expr::Await(_binding_0) => { + full!(v.visit_expr_await(_binding_0)); + } + crate::Expr::Binary(_binding_0) => { + v.visit_expr_binary(_binding_0); + } + crate::Expr::Block(_binding_0) => { + full!(v.visit_expr_block(_binding_0)); + } + crate::Expr::Break(_binding_0) => { + full!(v.visit_expr_break(_binding_0)); + } + crate::Expr::Call(_binding_0) => { + v.visit_expr_call(_binding_0); + } + crate::Expr::Cast(_binding_0) => { + v.visit_expr_cast(_binding_0); + } + crate::Expr::Closure(_binding_0) => { + full!(v.visit_expr_closure(_binding_0)); + } + crate::Expr::Const(_binding_0) => { + full!(v.visit_expr_const(_binding_0)); + } + crate::Expr::Continue(_binding_0) => { + full!(v.visit_expr_continue(_binding_0)); + } + crate::Expr::Field(_binding_0) => { + v.visit_expr_field(_binding_0); + } + crate::Expr::ForLoop(_binding_0) => { + full!(v.visit_expr_for_loop(_binding_0)); + } + crate::Expr::Group(_binding_0) => { + v.visit_expr_group(_binding_0); + } + crate::Expr::If(_binding_0) => { + full!(v.visit_expr_if(_binding_0)); + } + crate::Expr::Index(_binding_0) => { + v.visit_expr_index(_binding_0); + } + crate::Expr::Infer(_binding_0) => { + full!(v.visit_expr_infer(_binding_0)); + } + crate::Expr::Let(_binding_0) => { + full!(v.visit_expr_let(_binding_0)); + } + crate::Expr::Lit(_binding_0) => { + v.visit_expr_lit(_binding_0); + } + crate::Expr::Loop(_binding_0) => { + full!(v.visit_expr_loop(_binding_0)); + } + crate::Expr::Macro(_binding_0) => { + v.visit_expr_macro(_binding_0); + } + crate::Expr::Match(_binding_0) => { + full!(v.visit_expr_match(_binding_0)); + } + crate::Expr::MethodCall(_binding_0) => { + v.visit_expr_method_call(_binding_0); + } + crate::Expr::Paren(_binding_0) => { + v.visit_expr_paren(_binding_0); + } + crate::Expr::Path(_binding_0) => { + v.visit_expr_path(_binding_0); + } + crate::Expr::Range(_binding_0) => { + full!(v.visit_expr_range(_binding_0)); + } + crate::Expr::Reference(_binding_0) => { + v.visit_expr_reference(_binding_0); + } + crate::Expr::Repeat(_binding_0) => { + full!(v.visit_expr_repeat(_binding_0)); + } + crate::Expr::Return(_binding_0) => { + full!(v.visit_expr_return(_binding_0)); + } + crate::Expr::Struct(_binding_0) => { + v.visit_expr_struct(_binding_0); + } + crate::Expr::Try(_binding_0) => { + full!(v.visit_expr_try(_binding_0)); + } + crate::Expr::TryBlock(_binding_0) => { + full!(v.visit_expr_try_block(_binding_0)); + } + crate::Expr::Tuple(_binding_0) => { + full!(v.visit_expr_tuple(_binding_0)); + } + crate::Expr::Unary(_binding_0) => { + v.visit_expr_unary(_binding_0); + } + crate::Expr::Unsafe(_binding_0) => { + full!(v.visit_expr_unsafe(_binding_0)); + } + crate::Expr::Verbatim(_binding_0) => { + skip!(_binding_0); + } + crate::Expr::While(_binding_0) => { + full!(v.visit_expr_while(_binding_0)); + } + crate::Expr::Yield(_binding_0) => { + full!(v.visit_expr_yield(_binding_0)); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_array<'ast, V>(v: &mut V, node: &'ast crate::ExprArray) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.bracket_token); + for el in Punctuated::pairs(&node.elems) { + let it = el.value(); + v.visit_expr(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_assign<'ast, V>(v: &mut V, node: &'ast crate::ExprAssign) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.left); + skip!(node.eq_token); + v.visit_expr(&*node.right); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_async<'ast, V>(v: &mut V, node: &'ast crate::ExprAsync) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.async_token); + skip!(node.capture); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_await<'ast, V>(v: &mut V, node: &'ast crate::ExprAwait) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.base); + skip!(node.dot_token); + skip!(node.await_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast crate::ExprBinary) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.left); + v.visit_bin_op(&node.op); + v.visit_expr(&*node.right); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_block<'ast, V>(v: &mut V, node: &'ast crate::ExprBlock) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.label { + v.visit_label(it); + } + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_break<'ast, V>(v: &mut V, node: &'ast crate::ExprBreak) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.break_token); + if let Some(it) = &node.label { + v.visit_lifetime(it); + } + if let Some(it) = &node.expr { + v.visit_expr(&**it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_call<'ast, V>(v: &mut V, node: &'ast crate::ExprCall) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.func); + skip!(node.paren_token); + for el in Punctuated::pairs(&node.args) { + let it = el.value(); + v.visit_expr(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_cast<'ast, V>(v: &mut V, node: &'ast crate::ExprCast) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.expr); + skip!(node.as_token); + v.visit_type(&*node.ty); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_closure<'ast, V>(v: &mut V, node: &'ast crate::ExprClosure) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it); + } + skip!(node.constness); + skip!(node.movability); + skip!(node.asyncness); + skip!(node.capture); + skip!(node.or1_token); + for el in Punctuated::pairs(&node.inputs) { + let it = el.value(); + v.visit_pat(it); + } + skip!(node.or2_token); + v.visit_return_type(&node.output); + v.visit_expr(&*node.body); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_const<'ast, V>(v: &mut V, node: &'ast crate::ExprConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.const_token); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_continue<'ast, V>(v: &mut V, node: &'ast crate::ExprContinue) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.continue_token); + if let Some(it) = &node.label { + v.visit_lifetime(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_field<'ast, V>(v: &mut V, node: &'ast crate::ExprField) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.base); + skip!(node.dot_token); + v.visit_member(&node.member); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_for_loop<'ast, V>(v: &mut V, node: &'ast crate::ExprForLoop) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.label { + v.visit_label(it); + } + skip!(node.for_token); + v.visit_pat(&*node.pat); + skip!(node.in_token); + v.visit_expr(&*node.expr); + v.visit_block(&node.body); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_group<'ast, V>(v: &mut V, node: &'ast crate::ExprGroup) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.group_token); + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_if<'ast, V>(v: &mut V, node: &'ast crate::ExprIf) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.if_token); + v.visit_expr(&*node.cond); + v.visit_block(&node.then_branch); + if let Some(it) = &node.else_branch { + skip!((it).0); + v.visit_expr(&*(it).1); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_index<'ast, V>(v: &mut V, node: &'ast crate::ExprIndex) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.expr); + skip!(node.bracket_token); + v.visit_expr(&*node.index); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_infer<'ast, V>(v: &mut V, node: &'ast crate::ExprInfer) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.underscore_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_let<'ast, V>(v: &mut V, node: &'ast crate::ExprLet) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.let_token); + v.visit_pat(&*node.pat); + skip!(node.eq_token); + v.visit_expr(&*node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_lit<'ast, V>(v: &mut V, node: &'ast crate::ExprLit) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_lit(&node.lit); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_loop<'ast, V>(v: &mut V, node: &'ast crate::ExprLoop) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.label { + v.visit_label(it); + } + skip!(node.loop_token); + v.visit_block(&node.body); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_macro<'ast, V>(v: &mut V, node: &'ast crate::ExprMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_macro(&node.mac); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_match<'ast, V>(v: &mut V, node: &'ast crate::ExprMatch) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.match_token); + v.visit_expr(&*node.expr); + skip!(node.brace_token); + for it in &node.arms { + v.visit_arm(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_method_call<'ast, V>(v: &mut V, node: &'ast crate::ExprMethodCall) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.receiver); + skip!(node.dot_token); + v.visit_ident(&node.method); + if let Some(it) = &node.turbofish { + v.visit_angle_bracketed_generic_arguments(it); + } + skip!(node.paren_token); + for el in Punctuated::pairs(&node.args) { + let it = el.value(); + v.visit_expr(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_paren<'ast, V>(v: &mut V, node: &'ast crate::ExprParen) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.paren_token); + v.visit_expr(&*node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_path<'ast, V>(v: &mut V, node: &'ast crate::ExprPath) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.qself { + v.visit_qself(it); + } + v.visit_path(&node.path); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_range<'ast, V>(v: &mut V, node: &'ast crate::ExprRange) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.start { + v.visit_expr(&**it); + } + v.visit_range_limits(&node.limits); + if let Some(it) = &node.end { + v.visit_expr(&**it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_reference<'ast, V>(v: &mut V, node: &'ast crate::ExprReference) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.and_token); + skip!(node.mutability); + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_repeat<'ast, V>(v: &mut V, node: &'ast crate::ExprRepeat) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.bracket_token); + v.visit_expr(&*node.expr); + skip!(node.semi_token); + v.visit_expr(&*node.len); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_return<'ast, V>(v: &mut V, node: &'ast crate::ExprReturn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.return_token); + if let Some(it) = &node.expr { + v.visit_expr(&**it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_struct<'ast, V>(v: &mut V, node: &'ast crate::ExprStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.qself { + v.visit_qself(it); + } + v.visit_path(&node.path); + skip!(node.brace_token); + for el in Punctuated::pairs(&node.fields) { + let it = el.value(); + v.visit_field_value(it); + } + skip!(node.dot2_token); + if let Some(it) = &node.rest { + v.visit_expr(&**it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_try<'ast, V>(v: &mut V, node: &'ast crate::ExprTry) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_expr(&*node.expr); + skip!(node.question_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_try_block<'ast, V>(v: &mut V, node: &'ast crate::ExprTryBlock) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.try_token); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_tuple<'ast, V>(v: &mut V, node: &'ast crate::ExprTuple) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.paren_token); + for el in Punctuated::pairs(&node.elems) { + let it = el.value(); + v.visit_expr(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_expr_unary<'ast, V>(v: &mut V, node: &'ast crate::ExprUnary) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_un_op(&node.op); + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_unsafe<'ast, V>(v: &mut V, node: &'ast crate::ExprUnsafe) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.unsafe_token); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_while<'ast, V>(v: &mut V, node: &'ast crate::ExprWhile) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.label { + v.visit_label(it); + } + skip!(node.while_token); + v.visit_expr(&*node.cond); + v.visit_block(&node.body); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_expr_yield<'ast, V>(v: &mut V, node: &'ast crate::ExprYield) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.yield_token); + if let Some(it) = &node.expr { + v.visit_expr(&**it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_field<'ast, V>(v: &mut V, node: &'ast crate::Field) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + v.visit_field_mutability(&node.mutability); + if let Some(it) = &node.ident { + v.visit_ident(it); + } + skip!(node.colon_token); + v.visit_type(&node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_field_mutability<'ast, V>(v: &mut V, node: &'ast crate::FieldMutability) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::FieldMutability::None => {} + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_field_pat<'ast, V>(v: &mut V, node: &'ast crate::FieldPat) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_member(&node.member); + skip!(node.colon_token); + v.visit_pat(&*node.pat); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_field_value<'ast, V>(v: &mut V, node: &'ast crate::FieldValue) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_member(&node.member); + skip!(node.colon_token); + v.visit_expr(&node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_fields<'ast, V>(v: &mut V, node: &'ast crate::Fields) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Fields::Named(_binding_0) => { + v.visit_fields_named(_binding_0); + } + crate::Fields::Unnamed(_binding_0) => { + v.visit_fields_unnamed(_binding_0); + } + crate::Fields::Unit => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_fields_named<'ast, V>(v: &mut V, node: &'ast crate::FieldsNamed) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.brace_token); + for el in Punctuated::pairs(&node.named) { + let it = el.value(); + v.visit_field(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_fields_unnamed<'ast, V>(v: &mut V, node: &'ast crate::FieldsUnnamed) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.paren_token); + for el in Punctuated::pairs(&node.unnamed) { + let it = el.value(); + v.visit_field(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_file<'ast, V>(v: &mut V, node: &'ast crate::File) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.shebang); + for it in &node.attrs { + v.visit_attribute(it); + } + for it in &node.items { + v.visit_item(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_fn_arg<'ast, V>(v: &mut V, node: &'ast crate::FnArg) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::FnArg::Receiver(_binding_0) => { + v.visit_receiver(_binding_0); + } + crate::FnArg::Typed(_binding_0) => { + v.visit_pat_type(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_foreign_item<'ast, V>(v: &mut V, node: &'ast crate::ForeignItem) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::ForeignItem::Fn(_binding_0) => { + v.visit_foreign_item_fn(_binding_0); + } + crate::ForeignItem::Static(_binding_0) => { + v.visit_foreign_item_static(_binding_0); + } + crate::ForeignItem::Type(_binding_0) => { + v.visit_foreign_item_type(_binding_0); + } + crate::ForeignItem::Macro(_binding_0) => { + v.visit_foreign_item_macro(_binding_0); + } + crate::ForeignItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_foreign_item_fn<'ast, V>(v: &mut V, node: &'ast crate::ForeignItemFn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + v.visit_signature(&node.sig); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_foreign_item_macro<'ast, V>(v: &mut V, node: &'ast crate::ForeignItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_macro(&node.mac); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_foreign_item_static<'ast, V>( + v: &mut V, + node: &'ast crate::ForeignItemStatic, +) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.static_token); + v.visit_static_mutability(&node.mutability); + v.visit_ident(&node.ident); + skip!(node.colon_token); + v.visit_type(&*node.ty); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_foreign_item_type<'ast, V>(v: &mut V, node: &'ast crate::ForeignItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.type_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.semi_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_generic_argument<'ast, V>(v: &mut V, node: &'ast crate::GenericArgument) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::GenericArgument::Lifetime(_binding_0) => { + v.visit_lifetime(_binding_0); + } + crate::GenericArgument::Type(_binding_0) => { + v.visit_type(_binding_0); + } + crate::GenericArgument::Const(_binding_0) => { + v.visit_expr(_binding_0); + } + crate::GenericArgument::AssocType(_binding_0) => { + v.visit_assoc_type(_binding_0); + } + crate::GenericArgument::AssocConst(_binding_0) => { + v.visit_assoc_const(_binding_0); + } + crate::GenericArgument::Constraint(_binding_0) => { + v.visit_constraint(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_generic_param<'ast, V>(v: &mut V, node: &'ast crate::GenericParam) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::GenericParam::Lifetime(_binding_0) => { + v.visit_lifetime_param(_binding_0); + } + crate::GenericParam::Type(_binding_0) => { + v.visit_type_param(_binding_0); + } + crate::GenericParam::Const(_binding_0) => { + v.visit_const_param(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_generics<'ast, V>(v: &mut V, node: &'ast crate::Generics) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.lt_token); + for el in Punctuated::pairs(&node.params) { + let it = el.value(); + v.visit_generic_param(it); + } + skip!(node.gt_token); + if let Some(it) = &node.where_clause { + v.visit_where_clause(it); + } +} +pub fn visit_ident<'ast, V>(v: &mut V, node: &'ast proc_macro2::Ident) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_span(&node.span()); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_impl_item<'ast, V>(v: &mut V, node: &'ast crate::ImplItem) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::ImplItem::Const(_binding_0) => { + v.visit_impl_item_const(_binding_0); + } + crate::ImplItem::Fn(_binding_0) => { + v.visit_impl_item_fn(_binding_0); + } + crate::ImplItem::Type(_binding_0) => { + v.visit_impl_item_type(_binding_0); + } + crate::ImplItem::Macro(_binding_0) => { + v.visit_impl_item_macro(_binding_0); + } + crate::ImplItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_impl_item_const<'ast, V>(v: &mut V, node: &'ast crate::ImplItemConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.defaultness); + skip!(node.const_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.colon_token); + v.visit_type(&node.ty); + skip!(node.eq_token); + v.visit_expr(&node.expr); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_impl_item_fn<'ast, V>(v: &mut V, node: &'ast crate::ImplItemFn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.defaultness); + v.visit_signature(&node.sig); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_impl_item_macro<'ast, V>(v: &mut V, node: &'ast crate::ImplItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_macro(&node.mac); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_impl_item_type<'ast, V>(v: &mut V, node: &'ast crate::ImplItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.defaultness); + skip!(node.type_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.eq_token); + v.visit_type(&node.ty); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_impl_restriction<'ast, V>(v: &mut V, node: &'ast crate::ImplRestriction) +where + V: Visit<'ast> + ?Sized, +{ + match *node {} +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_index<'ast, V>(v: &mut V, node: &'ast crate::Index) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.index); + v.visit_span(&node.span); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item<'ast, V>(v: &mut V, node: &'ast crate::Item) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Item::Const(_binding_0) => { + v.visit_item_const(_binding_0); + } + crate::Item::Enum(_binding_0) => { + v.visit_item_enum(_binding_0); + } + crate::Item::ExternCrate(_binding_0) => { + v.visit_item_extern_crate(_binding_0); + } + crate::Item::Fn(_binding_0) => { + v.visit_item_fn(_binding_0); + } + crate::Item::ForeignMod(_binding_0) => { + v.visit_item_foreign_mod(_binding_0); + } + crate::Item::Impl(_binding_0) => { + v.visit_item_impl(_binding_0); + } + crate::Item::Macro(_binding_0) => { + v.visit_item_macro(_binding_0); + } + crate::Item::Mod(_binding_0) => { + v.visit_item_mod(_binding_0); + } + crate::Item::Static(_binding_0) => { + v.visit_item_static(_binding_0); + } + crate::Item::Struct(_binding_0) => { + v.visit_item_struct(_binding_0); + } + crate::Item::Trait(_binding_0) => { + v.visit_item_trait(_binding_0); + } + crate::Item::TraitAlias(_binding_0) => { + v.visit_item_trait_alias(_binding_0); + } + crate::Item::Type(_binding_0) => { + v.visit_item_type(_binding_0); + } + crate::Item::Union(_binding_0) => { + v.visit_item_union(_binding_0); + } + crate::Item::Use(_binding_0) => { + v.visit_item_use(_binding_0); + } + crate::Item::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_const<'ast, V>(v: &mut V, node: &'ast crate::ItemConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.const_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.colon_token); + v.visit_type(&*node.ty); + skip!(node.eq_token); + v.visit_expr(&*node.expr); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_enum<'ast, V>(v: &mut V, node: &'ast crate::ItemEnum) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.enum_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.brace_token); + for el in Punctuated::pairs(&node.variants) { + let it = el.value(); + v.visit_variant(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_extern_crate<'ast, V>(v: &mut V, node: &'ast crate::ItemExternCrate) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.extern_token); + skip!(node.crate_token); + v.visit_ident(&node.ident); + if let Some(it) = &node.rename { + skip!((it).0); + v.visit_ident(&(it).1); + } + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_fn<'ast, V>(v: &mut V, node: &'ast crate::ItemFn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + v.visit_signature(&node.sig); + v.visit_block(&*node.block); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_foreign_mod<'ast, V>(v: &mut V, node: &'ast crate::ItemForeignMod) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.unsafety); + v.visit_abi(&node.abi); + skip!(node.brace_token); + for it in &node.items { + v.visit_foreign_item(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_impl<'ast, V>(v: &mut V, node: &'ast crate::ItemImpl) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.defaultness); + skip!(node.unsafety); + skip!(node.impl_token); + v.visit_generics(&node.generics); + if let Some(it) = &node.trait_ { + skip!((it).0); + v.visit_path(&(it).1); + skip!((it).2); + } + v.visit_type(&*node.self_ty); + skip!(node.brace_token); + for it in &node.items { + v.visit_impl_item(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_macro<'ast, V>(v: &mut V, node: &'ast crate::ItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.ident { + v.visit_ident(it); + } + v.visit_macro(&node.mac); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_mod<'ast, V>(v: &mut V, node: &'ast crate::ItemMod) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.unsafety); + skip!(node.mod_token); + v.visit_ident(&node.ident); + if let Some(it) = &node.content { + skip!((it).0); + for it in &(it).1 { + v.visit_item(it); + } + } + skip!(node.semi); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_static<'ast, V>(v: &mut V, node: &'ast crate::ItemStatic) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.static_token); + v.visit_static_mutability(&node.mutability); + v.visit_ident(&node.ident); + skip!(node.colon_token); + v.visit_type(&*node.ty); + skip!(node.eq_token); + v.visit_expr(&*node.expr); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_struct<'ast, V>(v: &mut V, node: &'ast crate::ItemStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.struct_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + v.visit_fields(&node.fields); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_trait<'ast, V>(v: &mut V, node: &'ast crate::ItemTrait) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.unsafety); + skip!(node.auto_token); + if let Some(it) = &node.restriction { + v.visit_impl_restriction(it); + } + skip!(node.trait_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.colon_token); + for el in Punctuated::pairs(&node.supertraits) { + let it = el.value(); + v.visit_type_param_bound(it); + } + skip!(node.brace_token); + for it in &node.items { + v.visit_trait_item(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_trait_alias<'ast, V>(v: &mut V, node: &'ast crate::ItemTraitAlias) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.trait_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.eq_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_type<'ast, V>(v: &mut V, node: &'ast crate::ItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.type_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.eq_token); + v.visit_type(&*node.ty); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_union<'ast, V>(v: &mut V, node: &'ast crate::ItemUnion) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.union_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + v.visit_fields_named(&node.fields); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_item_use<'ast, V>(v: &mut V, node: &'ast crate::ItemUse) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_visibility(&node.vis); + skip!(node.use_token); + skip!(node.leading_colon); + v.visit_use_tree(&node.tree); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_label<'ast, V>(v: &mut V, node: &'ast crate::Label) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_lifetime(&node.name); + skip!(node.colon_token); +} +pub fn visit_lifetime<'ast, V>(v: &mut V, node: &'ast crate::Lifetime) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_span(&node.apostrophe); + v.visit_ident(&node.ident); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_lifetime_param<'ast, V>(v: &mut V, node: &'ast crate::LifetimeParam) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_lifetime(&node.lifetime); + skip!(node.colon_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_lifetime(it); + } +} +pub fn visit_lit<'ast, V>(v: &mut V, node: &'ast crate::Lit) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Lit::Str(_binding_0) => { + v.visit_lit_str(_binding_0); + } + crate::Lit::ByteStr(_binding_0) => { + v.visit_lit_byte_str(_binding_0); + } + crate::Lit::Byte(_binding_0) => { + v.visit_lit_byte(_binding_0); + } + crate::Lit::Char(_binding_0) => { + v.visit_lit_char(_binding_0); + } + crate::Lit::Int(_binding_0) => { + v.visit_lit_int(_binding_0); + } + crate::Lit::Float(_binding_0) => { + v.visit_lit_float(_binding_0); + } + crate::Lit::Bool(_binding_0) => { + v.visit_lit_bool(_binding_0); + } + crate::Lit::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +pub fn visit_lit_bool<'ast, V>(v: &mut V, node: &'ast crate::LitBool) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.value); + v.visit_span(&node.span); +} +pub fn visit_lit_byte<'ast, V>(v: &mut V, node: &'ast crate::LitByte) +where + V: Visit<'ast> + ?Sized, +{} +pub fn visit_lit_byte_str<'ast, V>(v: &mut V, node: &'ast crate::LitByteStr) +where + V: Visit<'ast> + ?Sized, +{} +pub fn visit_lit_char<'ast, V>(v: &mut V, node: &'ast crate::LitChar) +where + V: Visit<'ast> + ?Sized, +{} +pub fn visit_lit_float<'ast, V>(v: &mut V, node: &'ast crate::LitFloat) +where + V: Visit<'ast> + ?Sized, +{} +pub fn visit_lit_int<'ast, V>(v: &mut V, node: &'ast crate::LitInt) +where + V: Visit<'ast> + ?Sized, +{} +pub fn visit_lit_str<'ast, V>(v: &mut V, node: &'ast crate::LitStr) +where + V: Visit<'ast> + ?Sized, +{} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_local<'ast, V>(v: &mut V, node: &'ast crate::Local) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.let_token); + v.visit_pat(&node.pat); + if let Some(it) = &node.init { + v.visit_local_init(it); + } + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_local_init<'ast, V>(v: &mut V, node: &'ast crate::LocalInit) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.eq_token); + v.visit_expr(&*node.expr); + if let Some(it) = &node.diverge { + skip!((it).0); + v.visit_expr(&*(it).1); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_macro<'ast, V>(v: &mut V, node: &'ast crate::Macro) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_path(&node.path); + skip!(node.bang_token); + v.visit_macro_delimiter(&node.delimiter); + skip!(node.tokens); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_macro_delimiter<'ast, V>(v: &mut V, node: &'ast crate::MacroDelimiter) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::MacroDelimiter::Paren(_binding_0) => { + skip!(_binding_0); + } + crate::MacroDelimiter::Brace(_binding_0) => { + skip!(_binding_0); + } + crate::MacroDelimiter::Bracket(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_member<'ast, V>(v: &mut V, node: &'ast crate::Member) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Member::Named(_binding_0) => { + v.visit_ident(_binding_0); + } + crate::Member::Unnamed(_binding_0) => { + v.visit_index(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_meta<'ast, V>(v: &mut V, node: &'ast crate::Meta) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Meta::Path(_binding_0) => { + v.visit_path(_binding_0); + } + crate::Meta::List(_binding_0) => { + v.visit_meta_list(_binding_0); + } + crate::Meta::NameValue(_binding_0) => { + v.visit_meta_name_value(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_meta_list<'ast, V>(v: &mut V, node: &'ast crate::MetaList) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_path(&node.path); + v.visit_macro_delimiter(&node.delimiter); + skip!(node.tokens); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_meta_name_value<'ast, V>(v: &mut V, node: &'ast crate::MetaNameValue) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_path(&node.path); + skip!(node.eq_token); + v.visit_expr(&node.value); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_parenthesized_generic_arguments<'ast, V>( + v: &mut V, + node: &'ast crate::ParenthesizedGenericArguments, +) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.paren_token); + for el in Punctuated::pairs(&node.inputs) { + let it = el.value(); + v.visit_type(it); + } + v.visit_return_type(&node.output); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat<'ast, V>(v: &mut V, node: &'ast crate::Pat) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Pat::Const(_binding_0) => { + v.visit_expr_const(_binding_0); + } + crate::Pat::Ident(_binding_0) => { + v.visit_pat_ident(_binding_0); + } + crate::Pat::Lit(_binding_0) => { + v.visit_expr_lit(_binding_0); + } + crate::Pat::Macro(_binding_0) => { + v.visit_expr_macro(_binding_0); + } + crate::Pat::Or(_binding_0) => { + v.visit_pat_or(_binding_0); + } + crate::Pat::Paren(_binding_0) => { + v.visit_pat_paren(_binding_0); + } + crate::Pat::Path(_binding_0) => { + v.visit_expr_path(_binding_0); + } + crate::Pat::Range(_binding_0) => { + v.visit_expr_range(_binding_0); + } + crate::Pat::Reference(_binding_0) => { + v.visit_pat_reference(_binding_0); + } + crate::Pat::Rest(_binding_0) => { + v.visit_pat_rest(_binding_0); + } + crate::Pat::Slice(_binding_0) => { + v.visit_pat_slice(_binding_0); + } + crate::Pat::Struct(_binding_0) => { + v.visit_pat_struct(_binding_0); + } + crate::Pat::Tuple(_binding_0) => { + v.visit_pat_tuple(_binding_0); + } + crate::Pat::TupleStruct(_binding_0) => { + v.visit_pat_tuple_struct(_binding_0); + } + crate::Pat::Type(_binding_0) => { + v.visit_pat_type(_binding_0); + } + crate::Pat::Verbatim(_binding_0) => { + skip!(_binding_0); + } + crate::Pat::Wild(_binding_0) => { + v.visit_pat_wild(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_ident<'ast, V>(v: &mut V, node: &'ast crate::PatIdent) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.by_ref); + skip!(node.mutability); + v.visit_ident(&node.ident); + if let Some(it) = &node.subpat { + skip!((it).0); + v.visit_pat(&*(it).1); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_or<'ast, V>(v: &mut V, node: &'ast crate::PatOr) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.leading_vert); + for el in Punctuated::pairs(&node.cases) { + let it = el.value(); + v.visit_pat(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_paren<'ast, V>(v: &mut V, node: &'ast crate::PatParen) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.paren_token); + v.visit_pat(&*node.pat); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_reference<'ast, V>(v: &mut V, node: &'ast crate::PatReference) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.and_token); + skip!(node.mutability); + v.visit_pat(&*node.pat); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_rest<'ast, V>(v: &mut V, node: &'ast crate::PatRest) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.dot2_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_slice<'ast, V>(v: &mut V, node: &'ast crate::PatSlice) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.bracket_token); + for el in Punctuated::pairs(&node.elems) { + let it = el.value(); + v.visit_pat(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_struct<'ast, V>(v: &mut V, node: &'ast crate::PatStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.qself { + v.visit_qself(it); + } + v.visit_path(&node.path); + skip!(node.brace_token); + for el in Punctuated::pairs(&node.fields) { + let it = el.value(); + v.visit_field_pat(it); + } + if let Some(it) = &node.rest { + v.visit_pat_rest(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_tuple<'ast, V>(v: &mut V, node: &'ast crate::PatTuple) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.paren_token); + for el in Punctuated::pairs(&node.elems) { + let it = el.value(); + v.visit_pat(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_tuple_struct<'ast, V>(v: &mut V, node: &'ast crate::PatTupleStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.qself { + v.visit_qself(it); + } + v.visit_path(&node.path); + skip!(node.paren_token); + for el in Punctuated::pairs(&node.elems) { + let it = el.value(); + v.visit_pat(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_type<'ast, V>(v: &mut V, node: &'ast crate::PatType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_pat(&*node.pat); + skip!(node.colon_token); + v.visit_type(&*node.ty); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_pat_wild<'ast, V>(v: &mut V, node: &'ast crate::PatWild) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.underscore_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_path<'ast, V>(v: &mut V, node: &'ast crate::Path) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.leading_colon); + for el in Punctuated::pairs(&node.segments) { + let it = el.value(); + v.visit_path_segment(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_path_arguments<'ast, V>(v: &mut V, node: &'ast crate::PathArguments) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::PathArguments::None => {} + crate::PathArguments::AngleBracketed(_binding_0) => { + v.visit_angle_bracketed_generic_arguments(_binding_0); + } + crate::PathArguments::Parenthesized(_binding_0) => { + v.visit_parenthesized_generic_arguments(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_path_segment<'ast, V>(v: &mut V, node: &'ast crate::PathSegment) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + v.visit_path_arguments(&node.arguments); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_predicate_lifetime<'ast, V>(v: &mut V, node: &'ast crate::PredicateLifetime) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_lifetime(&node.lifetime); + skip!(node.colon_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_lifetime(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_predicate_type<'ast, V>(v: &mut V, node: &'ast crate::PredicateType) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it); + } + v.visit_type(&node.bounded_ty); + skip!(node.colon_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_qself<'ast, V>(v: &mut V, node: &'ast crate::QSelf) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.lt_token); + v.visit_type(&*node.ty); + skip!(node.position); + skip!(node.as_token); + skip!(node.gt_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_range_limits<'ast, V>(v: &mut V, node: &'ast crate::RangeLimits) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::RangeLimits::HalfOpen(_binding_0) => { + skip!(_binding_0); + } + crate::RangeLimits::Closed(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_receiver<'ast, V>(v: &mut V, node: &'ast crate::Receiver) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.reference { + skip!((it).0); + if let Some(it) = &(it).1 { + v.visit_lifetime(it); + } + } + skip!(node.mutability); + skip!(node.self_token); + skip!(node.colon_token); + v.visit_type(&*node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_return_type<'ast, V>(v: &mut V, node: &'ast crate::ReturnType) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::ReturnType::Default => {} + crate::ReturnType::Type(_binding_0, _binding_1) => { + skip!(_binding_0); + v.visit_type(&**_binding_1); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_signature<'ast, V>(v: &mut V, node: &'ast crate::Signature) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.constness); + skip!(node.asyncness); + skip!(node.unsafety); + if let Some(it) = &node.abi { + v.visit_abi(it); + } + skip!(node.fn_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.paren_token); + for el in Punctuated::pairs(&node.inputs) { + let it = el.value(); + v.visit_fn_arg(it); + } + if let Some(it) = &node.variadic { + v.visit_variadic(it); + } + v.visit_return_type(&node.output); +} +pub fn visit_span<'ast, V>(v: &mut V, node: &proc_macro2::Span) +where + V: Visit<'ast> + ?Sized, +{} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_static_mutability<'ast, V>(v: &mut V, node: &'ast crate::StaticMutability) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::StaticMutability::Mut(_binding_0) => { + skip!(_binding_0); + } + crate::StaticMutability::None => {} + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_stmt<'ast, V>(v: &mut V, node: &'ast crate::Stmt) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Stmt::Local(_binding_0) => { + v.visit_local(_binding_0); + } + crate::Stmt::Item(_binding_0) => { + v.visit_item(_binding_0); + } + crate::Stmt::Expr(_binding_0, _binding_1) => { + v.visit_expr(_binding_0); + skip!(_binding_1); + } + crate::Stmt::Macro(_binding_0) => { + v.visit_stmt_macro(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_stmt_macro<'ast, V>(v: &mut V, node: &'ast crate::StmtMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_macro(&node.mac); + skip!(node.semi_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_trait_bound<'ast, V>(v: &mut V, node: &'ast crate::TraitBound) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.paren_token); + v.visit_trait_bound_modifier(&node.modifier); + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it); + } + v.visit_path(&node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_trait_bound_modifier<'ast, V>( + v: &mut V, + node: &'ast crate::TraitBoundModifier, +) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::TraitBoundModifier::None => {} + crate::TraitBoundModifier::Maybe(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_trait_item<'ast, V>(v: &mut V, node: &'ast crate::TraitItem) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::TraitItem::Const(_binding_0) => { + v.visit_trait_item_const(_binding_0); + } + crate::TraitItem::Fn(_binding_0) => { + v.visit_trait_item_fn(_binding_0); + } + crate::TraitItem::Type(_binding_0) => { + v.visit_trait_item_type(_binding_0); + } + crate::TraitItem::Macro(_binding_0) => { + v.visit_trait_item_macro(_binding_0); + } + crate::TraitItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_trait_item_const<'ast, V>(v: &mut V, node: &'ast crate::TraitItemConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.const_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.colon_token); + v.visit_type(&node.ty); + if let Some(it) = &node.default { + skip!((it).0); + v.visit_expr(&(it).1); + } + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_trait_item_fn<'ast, V>(v: &mut V, node: &'ast crate::TraitItemFn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_signature(&node.sig); + if let Some(it) = &node.default { + v.visit_block(it); + } + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_trait_item_macro<'ast, V>(v: &mut V, node: &'ast crate::TraitItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_macro(&node.mac); + skip!(node.semi_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_trait_item_type<'ast, V>(v: &mut V, node: &'ast crate::TraitItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + skip!(node.type_token); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + skip!(node.colon_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } + if let Some(it) = &node.default { + skip!((it).0); + v.visit_type(&(it).1); + } + skip!(node.semi_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type<'ast, V>(v: &mut V, node: &'ast crate::Type) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Type::Array(_binding_0) => { + v.visit_type_array(_binding_0); + } + crate::Type::BareFn(_binding_0) => { + v.visit_type_bare_fn(_binding_0); + } + crate::Type::Group(_binding_0) => { + v.visit_type_group(_binding_0); + } + crate::Type::ImplTrait(_binding_0) => { + v.visit_type_impl_trait(_binding_0); + } + crate::Type::Infer(_binding_0) => { + v.visit_type_infer(_binding_0); + } + crate::Type::Macro(_binding_0) => { + v.visit_type_macro(_binding_0); + } + crate::Type::Never(_binding_0) => { + v.visit_type_never(_binding_0); + } + crate::Type::Paren(_binding_0) => { + v.visit_type_paren(_binding_0); + } + crate::Type::Path(_binding_0) => { + v.visit_type_path(_binding_0); + } + crate::Type::Ptr(_binding_0) => { + v.visit_type_ptr(_binding_0); + } + crate::Type::Reference(_binding_0) => { + v.visit_type_reference(_binding_0); + } + crate::Type::Slice(_binding_0) => { + v.visit_type_slice(_binding_0); + } + crate::Type::TraitObject(_binding_0) => { + v.visit_type_trait_object(_binding_0); + } + crate::Type::Tuple(_binding_0) => { + v.visit_type_tuple(_binding_0); + } + crate::Type::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_array<'ast, V>(v: &mut V, node: &'ast crate::TypeArray) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.bracket_token); + v.visit_type(&*node.elem); + skip!(node.semi_token); + v.visit_expr(&node.len); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_bare_fn<'ast, V>(v: &mut V, node: &'ast crate::TypeBareFn) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it); + } + skip!(node.unsafety); + if let Some(it) = &node.abi { + v.visit_abi(it); + } + skip!(node.fn_token); + skip!(node.paren_token); + for el in Punctuated::pairs(&node.inputs) { + let it = el.value(); + v.visit_bare_fn_arg(it); + } + if let Some(it) = &node.variadic { + v.visit_bare_variadic(it); + } + v.visit_return_type(&node.output); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_group<'ast, V>(v: &mut V, node: &'ast crate::TypeGroup) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.group_token); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_impl_trait<'ast, V>(v: &mut V, node: &'ast crate::TypeImplTrait) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.impl_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_infer<'ast, V>(v: &mut V, node: &'ast crate::TypeInfer) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.underscore_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_macro<'ast, V>(v: &mut V, node: &'ast crate::TypeMacro) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_macro(&node.mac); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_never<'ast, V>(v: &mut V, node: &'ast crate::TypeNever) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.bang_token); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_param<'ast, V>(v: &mut V, node: &'ast crate::TypeParam) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_ident(&node.ident); + skip!(node.colon_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } + skip!(node.eq_token); + if let Some(it) = &node.default { + v.visit_type(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_param_bound<'ast, V>(v: &mut V, node: &'ast crate::TypeParamBound) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::TypeParamBound::Trait(_binding_0) => { + v.visit_trait_bound(_binding_0); + } + crate::TypeParamBound::Lifetime(_binding_0) => { + v.visit_lifetime(_binding_0); + } + crate::TypeParamBound::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_paren<'ast, V>(v: &mut V, node: &'ast crate::TypeParen) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.paren_token); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_path<'ast, V>(v: &mut V, node: &'ast crate::TypePath) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.qself { + v.visit_qself(it); + } + v.visit_path(&node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_ptr<'ast, V>(v: &mut V, node: &'ast crate::TypePtr) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.star_token); + skip!(node.const_token); + skip!(node.mutability); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_reference<'ast, V>(v: &mut V, node: &'ast crate::TypeReference) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.and_token); + if let Some(it) = &node.lifetime { + v.visit_lifetime(it); + } + skip!(node.mutability); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_slice<'ast, V>(v: &mut V, node: &'ast crate::TypeSlice) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.bracket_token); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_trait_object<'ast, V>(v: &mut V, node: &'ast crate::TypeTraitObject) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.dyn_token); + for el in Punctuated::pairs(&node.bounds) { + let it = el.value(); + v.visit_type_param_bound(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_type_tuple<'ast, V>(v: &mut V, node: &'ast crate::TypeTuple) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.paren_token); + for el in Punctuated::pairs(&node.elems) { + let it = el.value(); + v.visit_type(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_un_op<'ast, V>(v: &mut V, node: &'ast crate::UnOp) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::UnOp::Deref(_binding_0) => { + skip!(_binding_0); + } + crate::UnOp::Not(_binding_0) => { + skip!(_binding_0); + } + crate::UnOp::Neg(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_use_glob<'ast, V>(v: &mut V, node: &'ast crate::UseGlob) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.star_token); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_use_group<'ast, V>(v: &mut V, node: &'ast crate::UseGroup) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.brace_token); + for el in Punctuated::pairs(&node.items) { + let it = el.value(); + v.visit_use_tree(it); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_use_name<'ast, V>(v: &mut V, node: &'ast crate::UseName) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_use_path<'ast, V>(v: &mut V, node: &'ast crate::UsePath) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + skip!(node.colon2_token); + v.visit_use_tree(&*node.tree); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_use_rename<'ast, V>(v: &mut V, node: &'ast crate::UseRename) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + skip!(node.as_token); + v.visit_ident(&node.rename); +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_use_tree<'ast, V>(v: &mut V, node: &'ast crate::UseTree) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::UseTree::Path(_binding_0) => { + v.visit_use_path(_binding_0); + } + crate::UseTree::Name(_binding_0) => { + v.visit_use_name(_binding_0); + } + crate::UseTree::Rename(_binding_0) => { + v.visit_use_rename(_binding_0); + } + crate::UseTree::Glob(_binding_0) => { + v.visit_use_glob(_binding_0); + } + crate::UseTree::Group(_binding_0) => { + v.visit_use_group(_binding_0); + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] +pub fn visit_variadic<'ast, V>(v: &mut V, node: &'ast crate::Variadic) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + if let Some(it) = &node.pat { + v.visit_pat(&*(it).0); + skip!((it).1); + } + skip!(node.dots); + skip!(node.comma); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_variant<'ast, V>(v: &mut V, node: &'ast crate::Variant) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + v.visit_ident(&node.ident); + v.visit_fields(&node.fields); + if let Some(it) = &node.discriminant { + skip!((it).0); + v.visit_expr(&(it).1); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_vis_restricted<'ast, V>(v: &mut V, node: &'ast crate::VisRestricted) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.pub_token); + skip!(node.paren_token); + skip!(node.in_token); + v.visit_path(&*node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_visibility<'ast, V>(v: &mut V, node: &'ast crate::Visibility) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::Visibility::Public(_binding_0) => { + skip!(_binding_0); + } + crate::Visibility::Restricted(_binding_0) => { + v.visit_vis_restricted(_binding_0); + } + crate::Visibility::Inherited => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_where_clause<'ast, V>(v: &mut V, node: &'ast crate::WhereClause) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.where_token); + for el in Punctuated::pairs(&node.predicates) { + let it = el.value(); + v.visit_where_predicate(it); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +#[cfg_attr(doc_cfg, doc(cfg(any(feature = "derive", feature = "full"))))] +pub fn visit_where_predicate<'ast, V>(v: &mut V, node: &'ast crate::WherePredicate) +where + V: Visit<'ast> + ?Sized, +{ + match node { + crate::WherePredicate::Lifetime(_binding_0) => { + v.visit_predicate_lifetime(_binding_0); + } + crate::WherePredicate::Type(_binding_0) => { + v.visit_predicate_type(_binding_0); + } + } +} diff --git a/match_hir/build/common.rs b/match_hir/build/common.rs new file mode 100644 index 000000000..aab6d966a --- /dev/null +++ b/match_hir/build/common.rs @@ -0,0 +1,12 @@ +use std::{ + fs::{File, OpenOptions}, + path::Path, +}; + +pub fn create(out_dir: &str, file_name: &str) -> std::io::Result { + OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(Path::new(out_dir).join(file_name)) +} diff --git a/match_hir/build/hir.rs b/match_hir/build/hir.rs new file mode 100644 index 000000000..d168d4219 --- /dev/null +++ b/match_hir/build/hir.rs @@ -0,0 +1,87 @@ +use crate::common::create; +use std::{fs::read_to_string, io::Write}; +use syn::{ + Fields, FieldsUnnamed, Item, Path as SynPath, Type, TypePath, TypeReference, parse_file, +}; + +pub fn emit_impls(out_dir: &str) { + let contents = read_to_string("assets/hir.rs").unwrap(); + let syn_file = + parse_file(&contents).unwrap_or_else(|_| panic!("Failed to parse: {contents:?}")); + + let node_enum = syn_file + .items + .iter() + .find_map(|item| { + if let Item::Enum(item_enum) = item + && item_enum.ident == "Node" + { + Some(item_enum) + } else { + None + } + }) + .unwrap(); + + let mut type_name = create(out_dir, "type_name.rs").unwrap(); + + writeln!( + type_name, + "pub fn type_name(node: hir::Node) -> std::option::Option<&'static str> {{ + #[allow(clippy::match_same_arms)] + match node {{" + ) + .unwrap(); + + for variant in &node_enum.variants { + if let Fields::Unnamed(FieldsUnnamed { unnamed, .. }) = &variant.fields + && unnamed.len() <= 1 + && let Some(field) = unnamed.first() + && let ty = peel_refs(&field.ty) + && let Type::Path(TypePath { + qself: None, + path: + SynPath { + leading_colon: None, + segments, + .. + }, + }) = ty + && segments.len() <= 1 + && let Some(segment) = segments.first() + { + // smoelius: `Node::Err` must be handled specially. + let expr = if segment.ident == "Span" { + String::from("None") + } else { + format!("TypeNameGetter::::type_name()", segment.ident) + }; + writeln!( + type_name, + " hir::Node::{}(_) => {expr},", + variant.ident + ) + .unwrap(); + } + // smoelius: `Node::Synthetic` must be handled specially. + else if matches!(&variant.fields, Fields::Unit) { + writeln!(type_name, " hir::Node::{} => None,", variant.ident,).unwrap(); + } else { + panic!("failed to emit match arm for variant `{}`", variant.ident); + } + } + + writeln!( + type_name, + " }} +}}" + ) + .unwrap(); +} + +fn peel_refs(mut ty: &Type) -> &Type { + while let Type::Reference(TypeReference { elem, .. }) = ty { + ty = elem; + } + ty +} diff --git a/match_hir/build/main.rs b/match_hir/build/main.rs new file mode 100644 index 000000000..8ade7b893 --- /dev/null +++ b/match_hir/build/main.rs @@ -0,0 +1,16 @@ +use std::env::var; + +mod common; +mod hir; +mod visit; + +fn main() { + #[cfg_attr(dylint_lib = "env_literal", allow(env_literal))] + let out_dir = var("OUT_DIR").unwrap(); + + hir::emit_impls(&out_dir); + visit::emit_impls(&out_dir); + + println!("cargo:rerun-if-changed=assets/hir.rs"); + println!("cargo:rerun-if-changed=assets/visit.rs"); +} diff --git a/match_hir/build/visit.rs b/match_hir/build/visit.rs new file mode 100644 index 000000000..e29d16155 --- /dev/null +++ b/match_hir/build/visit.rs @@ -0,0 +1,123 @@ +use crate::common::create; +use inflections::Inflect; +use quote::ToTokens; +use std::{fs::read_to_string, io::Write}; +use syn::{FnArg, Item, PatType, TraitItem, Type, TypePath, TypeReference, parse_file}; + +// smoelius: `ToTokens` implementations do not exist for these `syn` types, even though +// `Visit::visit_...` methods do. +const NO_TO_TOKENS: &[&str] = &[ + "AttrStyle", + "Data", + "DataEnum", + "DataStruct", + "DataUnion", + "FieldMutability", + "ImplRestriction", + "LocalInit", + "MacroDelimiter", + "Span", + "QSelf", +]; + +// smoelius: Manual `IsVariable` implementations exist for these `syn` types. +const MANUAL_IS_VARIABLE: &[&str] = &[ + "Expr", + "GenericArgument", + "Ident", + "Member", + "Pat", + "Path", + "PathSegment", + "Stmt", + "Type", +]; + +pub fn emit_impls(out_dir: &str) { + let contents = read_to_string("assets/visit.rs").unwrap(); + let syn_file = + parse_file(&contents).unwrap_or_else(|_| panic!("Failed to parse: {contents:?}")); + + let visit_trait = syn_file + .items + .iter() + .find_map(|item| { + if let Item::Trait(item_trait) = item + && item_trait.ident == "Visit" + { + Some(item_trait) + } else { + None + } + }) + .unwrap(); + + let mut unify_variable = create(out_dir, "unify_variable.rs").unwrap(); + let mut unify_node = create(out_dir, "unify_node.rs").unwrap(); + let mut unify_producer = create(out_dir, "unify_producer.rs").unwrap(); + let mut unify_consumer = create(out_dir, "unify_consumer.rs").unwrap(); + let mut visitable = create(out_dir, "visitable.rs").unwrap(); + + writeln!( + unify_producer, + "impl<'ast> syn::visit::Visit<'ast> for Producer<'ast> {{" + ) + .unwrap(); + writeln!( + unify_consumer, + "impl<'ast> syn::visit::Visit<'ast> for Consumer<'_, 'ast> {{" + ) + .unwrap(); + + for trait_item in &visit_trait.items { + let Some(ty) = is_visit_fn(trait_item) else { + continue; + }; + + if NO_TO_TOKENS.contains(&ty.as_str()) { + continue; + } + + let ty_snake = ty.to_snake_case(); + + if !MANUAL_IS_VARIABLE.contains(&ty.as_str()) { + writeln!(unify_variable, "impl_is_variable!({ty});").unwrap(); + } + + writeln!(unify_node, "impl_syn_node!({ty});").unwrap(); + + for file in [&mut unify_producer, &mut unify_consumer] { + writeln!( + file, + "\ + fn visit_{ty_snake}(&mut self, node: &'ast syn::{ty}) {{ + self.visit_inner(node); + }}" + ) + .unwrap(); + } + + writeln!(visitable, "impl_visitable!({ty}, {ty_snake});").unwrap(); + } + + writeln!(unify_producer, "}}").unwrap(); + writeln!(unify_consumer, "}}").unwrap(); +} + +fn is_visit_fn(trait_item: &TraitItem) -> Option { + if let TraitItem::Fn(trait_item_fn) = trait_item + && let [_, FnArg::Typed(PatType { ty, .. })] = trait_item_fn + .sig + .inputs + .iter() + .collect::>() + .as_slice() + && let Type::Reference(TypeReference { elem, .. }) = &**ty + && let Type::Path(TypePath { qself: None, path }) = &**elem + && let Some(segment) = path.segments.last() + { + Some(segment.to_token_stream().to_string()) + } else { + None + } +} diff --git a/match_hir/clippy.toml b/match_hir/clippy.toml new file mode 100644 index 000000000..ca29cc4cb --- /dev/null +++ b/match_hir/clippy.toml @@ -0,0 +1,2 @@ +disallowed-methods = ["rustc_middle::ty::TyCtxt::hir_span"] +disallowed-types = ["proc_macro2::Span"] diff --git a/match_hir/reflective_match/Cargo.toml b/match_hir/reflective_match/Cargo.toml new file mode 100644 index 000000000..dc77dc602 --- /dev/null +++ b/match_hir/reflective_match/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "reflective_match" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +thiserror = "2.0" +dylint_linting = "5.0" + +match_hir = { path = ".." } + +[dev-dependencies] +dylint_testing = "5.0" + +[lints] +workspace = true + +[package.metadata.rust-analyzer] +rustc_private = true diff --git a/match_hir/reflective_match/src/lib.rs b/match_hir/reflective_match/src/lib.rs new file mode 100644 index 000000000..ba599e3e1 --- /dev/null +++ b/match_hir/reflective_match/src/lib.rs @@ -0,0 +1,194 @@ +#![feature(rustc_private)] +#![warn(unused_extern_crates)] + +dylint_linting::dylint_library!(); + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_session; +extern crate rustc_span; + +use match_hir::{ + __hir_ids_from_span_untyped as hir_ids_from_span_untyped, __snippet_opt as snippet_opt, Error, + Pattern, +}; +use rustc_hir::{Expr, ExprKind, HirId}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::TyCtxt; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::Symbol; +use std::str::FromStr; +use thiserror::Error as ThisError; + +#[derive(Debug, ThisError)] +struct EmptySnippet; + +impl std::fmt::Display for EmptySnippet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("empty snippet") + } +} + +#[derive(Debug, ThisError)] +struct Mismatch { + snippet: String, + expected: String, + actual: String, +} + +impl Mismatch { + fn new(tcx: TyCtxt, snippet: String, expected: HirId, actual: HirId) -> Self { + if enabled("VERBOSE") { + Self { + snippet, + expected: format!("{:#?}", tcx.hir_node(expected)), + actual: format!("{:#?}", tcx.hir_node(actual)), + } + } else { + Self { + snippet, + expected: expected.to_string(), + actual: actual.to_string(), + } + } + } +} + +impl std::fmt::Display for Mismatch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "`HirId`s do not match + snippet: {:?} + expected: {} + actual: {}", + self.snippet, self.expected, self.actual + )) + } +} + +#[allow(clippy::no_mangle_with_rust_abi)] +#[no_mangle] +pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) { + let wildcard = std::env::var("WILDCARD").ok(); + let mut lock = sess.psess.env_depinfo.lock(); + lock.insert(( + Symbol::intern("WILDCARD"), + wildcard.as_deref().map(Symbol::intern), + )); + + lint_store.register_lints(&[REFLECTIVE_MATCH]); + lint_store.register_late_pass(move |_| { + Box::<_>::new(ReflectiveMatch::new(is_enabled_value(wildcard.clone()))) + }); +} + +declare_lint! { + pub REFLECTIVE_MATCH, + Warn, + "match expressions against themselves using `match_hir`" +} + +#[derive(Default)] +struct ReflectiveMatch { + wildcard: bool, + ignored: Vec, + matched: Vec, + errors: Vec, +} + +impl_lint_pass!(ReflectiveMatch => [REFLECTIVE_MATCH]); + +impl ReflectiveMatch { + fn new(wildcard: bool) -> Self { + Self { + wildcard, + ..Default::default() + } + } +} + +impl<'tcx> LateLintPass<'tcx> for ReflectiveMatch { + fn check_expr_post(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + // smoelius: Ignore `DropTemps`. + if matches!(expr.kind, ExprKind::DropTemps(_)) { + self.ignored.push(expr.span); + return; + } + + // smoelius: `hir_ids_from_span_untyped` ignores "no-location" spans (i.e., spans with no + // associated source file) and "from expansion" spans. + if !hir_ids_from_span_untyped(cx, expr.span).contains(&expr.hir_id) { + self.ignored.push(expr.span); + return; + }; + + // smoelius: If any of `expr`'s ancestors have the same span as `expr`, ignore `expr`. + if cx + .tcx + .hir_parent_id_iter(expr.hir_id) + .any(|ancestor_id| cx.tcx.hir_span(ancestor_id) == expr.span) + { + self.ignored.push(expr.span); + return; + }; + + let snippet = snippet_opt(cx, expr.span).unwrap(); + + if snippet.is_empty() { + self.errors.push(Error::other(expr.span, EmptySnippet)); + return; + } + + let result = if self.wildcard { + let pattern = Pattern::from_str("#(_)").unwrap(); + let mut result = pattern.matches(cx, expr); + if let Ok(hir_ids) = &result { + let &[hir_id] = hir_ids.as_slice() else { + panic!(); + }; + if expr.hir_id != hir_id { + result = Err(Error::other( + expr.span, + Mismatch::new(cx.tcx, snippet, expr.hir_id, hir_id), + )); + } + } + result + } else { + let pattern = Pattern::from_str(&snippet).unwrap(); + let result = pattern.matches(cx, expr); + if let Ok(hir_ids) = &result { + assert!(hir_ids.is_empty()); + } + result + }; + + match result { + Ok(_) => self.matched.push(expr.span), + Err(error) => { + self.errors.push(error); + } + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + eprintln!("name: {:?}", cx.sess().opts.crate_name.as_ref().unwrap()); + if enabled("VERBOSE") { + eprintln!("ignored: {}", self.ignored.len()); + eprintln!("matched: {}", self.matched.len()); + } + eprintln!("errors: {}", self.errors.len()); + for error in &self.errors { + eprintln!("{error}"); + } + } +} + +fn enabled(key: &str) -> bool { + is_enabled_value(std::env::var(key).ok()) +} + +fn is_enabled_value>(value: Option) -> bool { + value.map_or(false, |value| value.as_ref() != "0") +} diff --git a/match_hir/rust-toolchain b/match_hir/rust-toolchain new file mode 100644 index 000000000..b8e5648bf --- /dev/null +++ b/match_hir/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-09-18" +components = ["llvm-tools-preview", "rustc-dev"] diff --git a/match_hir/src/binding.rs b/match_hir/src/binding.rs new file mode 100644 index 000000000..c6ce5eaca --- /dev/null +++ b/match_hir/src/binding.rs @@ -0,0 +1,24 @@ +use std::any::type_name; + +#[derive(Debug)] +pub struct Binding { + type_name: &'static str, + span: rustc_span::Span, +} + +impl Binding { + pub(crate) fn new(span: rustc_span::Span) -> Self { + Self { + type_name: type_name::(), + span, + } + } + + pub(crate) fn type_name(&self) -> &'static str { + self.type_name + } + + pub(crate) fn span(&self) -> rustc_span::Span { + self.span + } +} diff --git a/match_hir/src/clippy_utils/mod.rs b/match_hir/src/clippy_utils/mod.rs new file mode 100644 index 000000000..fac38b4d0 --- /dev/null +++ b/match_hir/src/clippy_utils/mod.rs @@ -0,0 +1,7 @@ +// smoelius: Source code in this module was copied from `clippy_utils`. + +mod snippet; +pub use snippet::snippet_opt; + +mod source; +pub use source::get_source_text; diff --git a/match_hir/src/clippy_utils/snippet.rs b/match_hir/src/clippy_utils/snippet.rs new file mode 100644 index 000000000..bcf4f16cd --- /dev/null +++ b/match_hir/src/clippy_utils/snippet.rs @@ -0,0 +1,15 @@ +use rustc_lint::LintContext; +use rustc_session::Session; +use rustc_span::Span; + +// smoelius: Everything below this comment was copied from: +// https://github.com/rust-lang/rust/blob/e0eba9cafcc8aaf3821f4b0b9777954caf049498/clippy_utils/src/source.rs#L238-L245 + +/// Converts a span to a code snippet. Returns `None` if not available. +pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option { + snippet_opt_sess(cx.sess(), span) +} + +fn snippet_opt_sess(sess: &Session, span: Span) -> Option { + sess.source_map().span_to_snippet(span).ok() +} diff --git a/match_hir/src/clippy_utils/source.rs b/match_hir/src/clippy_utils/source.rs new file mode 100644 index 000000000..9a53fe2e9 --- /dev/null +++ b/match_hir/src/clippy_utils/source.rs @@ -0,0 +1,57 @@ +use rustc_lint::LintContext; +use rustc_span::{BytePos, Pos, SourceFile, Span, SpanData, source_map::SourceMap}; +use std::{ops::Range, sync::Arc}; + +// smoelius: Everything below this comment is based on: +// https://github.com/rust-lang/rust-clippy/blob/0b3c2ed81152a927c91c02d9d94762d2c65254a2/clippy_utils/src/source.rs#L16-L62 + +/// A type which can be converted to the range portion of a `Span`. +pub trait SpanRange { + fn into_range(self) -> Range; +} +impl SpanRange for Span { + fn into_range(self) -> Range { + let data = self.data(); + data.lo..data.hi + } +} +impl SpanRange for SpanData { + fn into_range(self) -> Range { + self.lo..self.hi + } +} +impl SpanRange for Range { + fn into_range(self) -> Range { + self + } +} + +pub struct SourceFileRange { + pub sf: Arc, + pub range: Range, +} +impl SourceFileRange { + /// Attempts to get the text from the source file. This can fail if the source text isn't + /// loaded. + pub fn as_str(&self) -> Option<&str> { + self.sf.src.as_ref().and_then(|x| x.get(self.range.clone())) + } +} + +/// Gets the source file, and range in the file, of the given span. Returns `None` if the span +/// extends through multiple files, or is malformed. +pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option { + fn f(sm: &SourceMap, sp: Range) -> Option { + let start = sm.lookup_byte_offset(sp.start); + let end = sm.lookup_byte_offset(sp.end); + if !Arc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { + return None; + } + let range = start.pos.to_usize()..end.pos.to_usize(); + Some(SourceFileRange { + sf: start.sf, + range, + }) + } + f(cx.sess().source_map(), sp.into_range()) +} diff --git a/match_hir/src/error.rs b/match_hir/src/error.rs new file mode 100644 index 000000000..81e28a563 --- /dev/null +++ b/match_hir/src/error.rs @@ -0,0 +1,67 @@ +use proc_macro2::LexError; +use syn::parse::Error as ParseError; +use thiserror::Error as ThisError; + +#[derive(Debug, ThisError)] +pub struct Error { + span: rustc_span::Span, + kind: ErrorKind, +} + +impl Error { + pub fn new(span: rustc_span::Span, error: impl Into) -> Self { + Self { + span, + kind: error.into(), + } + } + + pub fn other(span: rustc_span::Span, error: impl Into>) -> Self { + Self { + span, + kind: error.into().into(), + } + } + + #[must_use] + pub fn span(&self) -> rustc_span::Span { + self.span + } + + #[must_use] + pub fn kind(&self) -> &ErrorKind { + &self.kind + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{:?}: {}", self.span, self.kind)) + } +} + +// smoelius: Please keep this list sorted by order in which the errors could occur. +#[derive(Debug, ThisError)] +#[non_exhaustive] +pub enum ErrorKind { + #[error("lex error: {0}")] + LexError(#[from] LexError), + + #[error("parse error: {0}")] + ParseError(#[from] ParseError), + + #[error("failed to get span")] + NoSpan, + + #[error("failed to get source text")] + NoSource, + + #[error("failed to match pattern")] + NoMatch, + + #[error("found no `HirId` for `{type_name}`")] + NoHirId { type_name: &'static str }, + + #[error(transparent)] + Other(#[from] Box), +} diff --git a/match_hir/src/hir_node.rs b/match_hir/src/hir_node.rs new file mode 100644 index 000000000..912d82bae --- /dev/null +++ b/match_hir/src/hir_node.rs @@ -0,0 +1,77 @@ +#![cfg_attr( + dylint_lib = "inconsistent_qualification", + allow(inconsistent_qualification) +)] + +use rustc_hir::{self as hir, HirId}; + +/// A type that knows its `HirId`. +/// +/// Similar to [`clippy_utils::HirNode`]. +/// +/// [`clippy_utils::HirNode`]: https://github.com/rust-lang/rust/blob/786f874c349b995ebed5e3d8f20db1cf65f20782/clippy_utils/src/macros.rs#L510-L539 +pub trait HirNode { + fn hir_id(&self) -> HirId; +} + +macro_rules! impl_hir_node_with_method { + ($path:path) => { + impl HirNode for $path { + fn hir_id(&self) -> HirId { + self.hir_id() + } + } + }; +} + +macro_rules! impl_hir_node_with_struct_field { + ($path:path) => { + impl HirNode for $path { + fn hir_id(&self) -> HirId { + self.hir_id + } + } + }; +} + +// smoelius: The below lists were generated manually, not automatically, and may be incomplete. + +impl_hir_node_with_method!(hir::ForeignItem<'_>); +impl_hir_node_with_method!(hir::ForeignItemId); +impl_hir_node_with_method!(hir::GenericArg<'_>); +impl_hir_node_with_method!(hir::ImplItem<'_>); +impl_hir_node_with_method!(hir::ImplItemId); +impl_hir_node_with_method!(hir::Item<'_>); +impl_hir_node_with_method!(hir::ItemId); +impl_hir_node_with_method!(hir::TraitItem<'_>); +impl_hir_node_with_method!(hir::TraitItemId); + +// smoelius: ??? warning: function cannot return without recursing +// impl_hir_node_with_method!(hir::PreciseCapturingArg<'_>); + +impl_hir_node_with_struct_field!(hir::AnonConst); +impl_hir_node_with_struct_field!(hir::Arm<'_>); +impl_hir_node_with_struct_field!(hir::AssocItemConstraint<'_>); +impl_hir_node_with_struct_field!(hir::Block<'_>); +impl_hir_node_with_struct_field!(hir::BodyId); +impl_hir_node_with_struct_field!(hir::ConstArg<'_>); +impl_hir_node_with_struct_field!(hir::ConstBlock); +impl_hir_node_with_struct_field!(hir::Expr<'_>); +impl_hir_node_with_struct_field!(hir::ExprField<'_>); +impl_hir_node_with_struct_field!(hir::FieldDef<'_>); +impl_hir_node_with_struct_field!(hir::GenericParam<'_>); +impl_hir_node_with_struct_field!(hir::InferArg); +impl_hir_node_with_struct_field!(hir::LetStmt<'_>); +impl_hir_node_with_struct_field!(hir::Lifetime); +impl_hir_node_with_struct_field!(hir::OpaqueTy<'_>); +impl_hir_node_with_struct_field!(hir::Param<'_>); +impl_hir_node_with_struct_field!(hir::Pat<'_>); +impl_hir_node_with_struct_field!(hir::PatExpr<'_>); +impl_hir_node_with_struct_field!(hir::PatField<'_>); +impl_hir_node_with_struct_field!(hir::PathSegment<'_>); +impl_hir_node_with_struct_field!(hir::PreciseCapturingNonLifetimeArg); +impl_hir_node_with_struct_field!(hir::Stmt<'_>); +impl_hir_node_with_struct_field!(hir::Ty<'_>); +impl_hir_node_with_struct_field!(hir::TyPat<'_>); +impl_hir_node_with_struct_field!(hir::Variant<'_>); +impl_hir_node_with_struct_field!(hir::WherePredicate<'_>); diff --git a/match_hir/src/lib.rs b/match_hir/src/lib.rs new file mode 100644 index 000000000..d1ccf0a80 --- /dev/null +++ b/match_hir/src/lib.rs @@ -0,0 +1,155 @@ +#![feature(rustc_private)] +#![warn(unused_extern_crates)] + +extern crate rustc_ast; +extern crate rustc_data_structures; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_session; +extern crate rustc_span; + +#[allow(unused_extern_crates)] +extern crate rustc_driver; + +use proc_macro2::TokenStream as TokenStream2; +use rustc_hir::HirId; +use rustc_lint::LateContext; +use std::str::FromStr; + +pub use syn::parse::Parse; + +mod binding; +use binding::Binding; + +mod clippy_utils; +use clippy_utils::get_source_text; +pub use clippy_utils::snippet_opt as __snippet_opt; + +mod error; +pub use error::{Error, ErrorKind}; + +mod hir_node; +pub use hir_node::HirNode; + +mod span_hir_id_map; +pub use span_hir_id_map::__hir_ids_from_span_untyped; +use span_hir_id_map::{ + __hir_ids_from_span_untyped as hir_ids_from_span_untyped, hir_ids_from_span, +}; + +mod syntax; +pub use syntax::HirToSyn; + +mod toxic; +pub use toxic::Unify; +use toxic::variables; + +mod type_name; +use type_name::type_name; + +mod visitable; +use visitable::Visitable; + +#[derive(Clone)] +pub struct Pattern { + stream: TokenStream2, + n_vars: usize, +} + +impl Pattern { + #[allow(clippy::unnecessary_wraps)] + fn new(stream: TokenStream2) -> Result { + let (stream, n_vars) = variables::mark(stream); + Ok(Self { stream, n_vars }) + } +} + +impl FromStr for Pattern { + type Err = Error; + fn from_str(s: &str) -> Result { + let stream = + TokenStream2::from_str(s).map_err(|error| Error::new(rustc_span::DUMMY_SP, error))?; + Self::new(stream) + } +} + +impl Pattern { + pub fn matches(&self, cx: &LateContext, hir: &T) -> Result, Error> + where + T: HirNode + HirToSyn, + { + let hir_id = hir.hir_id(); + + self.matches_hir_id::(cx, hir_id) + } + + pub fn matches_hir_id(&self, cx: &LateContext, hir_id: HirId) -> Result, Error> + where + T: Parse + Unify, + { + let bindings = self.matches_hir_id_inner::(cx, hir_id)?; + + // smoelius: Re the use of `first`, see the comment preceding `matches_hir_id_inner`'s + // definition. + Ok(bindings + .into_iter() + .map(|hir_ids| hir_ids.first().copied().unwrap()) + .collect()) + } + + // smoelius: Note that `matches_hir_id_inner` returns a vector of vectors to support a + // "multi-matches" interface. However, I am on the fence as to whether we should provide that + // interface. + fn matches_hir_id_inner( + &self, + cx: &LateContext, + hir_id: HirId, + ) -> Result>, Error> + where + T: Parse + Unify, + { + #[allow(clippy::disallowed_methods)] + let span = cx.tcx.hir_span(hir_id); + + if !hir_ids_from_span_untyped(cx, span).contains(&hir_id) { + return Err(Error::new(span, ErrorKind::NoSpan)); + } + + let mut bindings = Vec::with_capacity(self.n_vars); + + let scrutinee: T = reparse_as_syn(cx, span)?; + let pattern: T = + syn::parse2(self.stream.clone()).map_err(|error| Error::new(span, error))?; + + scrutinee.unify(span, &pattern, &mut bindings)?; + + assert_eq!(self.n_vars, bindings.len()); + + bindings + .into_iter() + .map(|binding| { + let hir_ids = hir_ids_from_span::(cx, binding.span()); + if hir_ids.is_empty() { + return Err(Error::new( + span, + ErrorKind::NoHirId { + type_name: binding.type_name(), + }, + )); + } + Ok(hir_ids) + }) + .collect::, _>>() + } +} + +fn reparse_as_syn(cx: &LateContext, span: rustc_span::Span) -> Result { + if let Some(source_file_range) = get_source_text(cx, span) + && let Some(text) = source_file_range.as_str() + { + syn::parse_str::(text).map_err(|error| Error::new(span, ErrorKind::ParseError(error))) + } else { + Err(Error::new(span, ErrorKind::NoSource)) + } +} diff --git a/match_hir/src/span_hir_id_map.rs b/match_hir/src/span_hir_id_map.rs new file mode 100644 index 000000000..2a1f8357e --- /dev/null +++ b/match_hir/src/span_hir_id_map.rs @@ -0,0 +1,124 @@ +use crate::type_name; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::{CRATE_HIR_ID, HirId, intravisit::Visitor}; +use rustc_lint::LateContext; +use rustc_middle::ty::TyCtxt; +use std::{cell::OnceCell, collections::BTreeMap}; + +thread_local! { + // smoelius: The `HirId`s in each `Vec` are ordered "more ancestral" to "less ancestral". In + // particular, if x is an ancestor of y, x should appear before y in the `Vec`. + // smoelius: Also, the following spans are filtered out: + // + // - "no-location" spans, i.e., spans with no associated source file + // - "from expansion" spans, i.e., spans produced by macros + // - spans that do not hold all of their children + // + // For the last bullet, if a child is determined to be larger than its parent, the parent is + // discarded before the child is inserted. + static SPAN_HIR_ID_MAP: OnceCell>> = const { OnceCell::new() }; +} + +pub(crate) fn hir_ids_from_span(cx: &LateContext, span: rustc_span::Span) -> Vec { + __hir_ids_from_span_untyped(cx, span) + .iter() + .filter(|&&hir_id| { + let node = cx.tcx.hir_node(hir_id); + type_name(node) == Some(std::any::type_name::()) + }) + .copied() + .collect() +} + +pub fn __hir_ids_from_span_untyped(cx: &LateContext, span: rustc_span::Span) -> Vec { + SPAN_HIR_ID_MAP.with(|map| { + let map = map.get_or_init(|| init(cx)); + + if let Some(hir_ids) = map.get(&span) { + hir_ids.clone() + } else { + Vec::default() + } + }) +} + +// https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/intravisit/index.html +fn init(cx: &LateContext) -> BTreeMap> { + let mut visitor = SpanHirIdVisitor { + tcx: cx.tcx, + map: BTreeMap::default(), + discarded: FxHashSet::default(), + }; + #[allow(clippy::disallowed_methods)] + let crate_span = cx.tcx.hir_span(CRATE_HIR_ID); + visitor.visit_mod(cx.tcx.hir_root_module(), crate_span, CRATE_HIR_ID); + visitor.map +} + +struct SpanHirIdVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + map: BTreeMap>, + discarded: FxHashSet, +} + +impl<'tcx> Visitor<'tcx> for SpanHirIdVisitor<'tcx> { + type NestedFilter = rustc_middle::hir::nested_filter::All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_id(&mut self, hir_id: HirId) { + let Some(span) = root_span_with_location(self.tcx, hir_id) else { + return; + }; + for parent_id in self.tcx.hir_parent_id_iter(hir_id) { + let Some(parent_span) = root_span_with_location(self.tcx, parent_id) else { + continue; + }; + // smoelius: We want to insert the span into the tree, but we also want to preserve the + // invariant that each span is contained by its ancestors in the branch. So, search + // until you find an ancestor that contains the span and then stop. The span will be + // contained in that ancestor, and that ancestor will be contained in all of its + // ancestors inductively. + if parent_span.contains(span) { + // smoelius: Ensure the parent span is in the map. + let parent_vec = self.map.entry(parent_span).or_default(); + if parent_vec.last() != Some(&parent_id) && !self.discarded.contains(&parent_id) { + parent_vec.push(parent_id); + } + break; + } + // smoelius: The parent span does not contain span. Remove the parent span and keep + // searching. + let Some(parent_vec) = self.map.get_mut(&parent_span) else { + continue; + }; + // smoelius: The parent span could have already been discarded. + if parent_vec.last() == Some(&parent_id) { + let _: Option = parent_vec.pop(); + self.discarded.insert(parent_id); + } + } + + self.map.entry(span).or_default().push(hir_id); + } +} + +fn root_span_with_location(tcx: TyCtxt, hir_id: HirId) -> Option { + #[allow(clippy::disallowed_methods)] + let span = tcx.hir_span(hir_id); + + if is_no_location_span(tcx, span) || span.from_expansion() { + return None; + } + + Some(span) +} + +fn is_no_location_span(tcx: TyCtxt, span: rustc_span::Span) -> bool { + let (source_file, _lo_line, _lo_col, _hi_line, _hi_col) = + tcx.sess.source_map().span_to_location_info(span); + + source_file.is_none() +} diff --git a/match_hir/src/syntax.rs b/match_hir/src/syntax.rs new file mode 100644 index 000000000..512e58405 --- /dev/null +++ b/match_hir/src/syntax.rs @@ -0,0 +1,36 @@ +use crate::Unify; +use rustc_ast as ast; +use rustc_hir as hir; +use rustc_span as span; +use syn::{parse::Parse, spanned::Spanned}; + +pub trait HirToSyn { + type Syn: Parse + Spanned + Unify; +} + +macro_rules! impl_hir_to_syn { + ($hir_ty:path, $syn_ty:ty) => { + impl HirToSyn for $hir_ty { + type Syn = $syn_ty; + } + }; +} + +// smoelius: The below list was generated manually, not automatically, and may be incomplete. +impl_hir_to_syn!(ast::Label, syn::Label); +impl_hir_to_syn!(hir::AnonConst, syn::Expr); +impl_hir_to_syn!(hir::Arm<'_>, syn::Arm); +impl_hir_to_syn!(hir::Block<'_>, syn::Block); +impl_hir_to_syn!(hir::ExprField<'_>, syn::FieldValue); +impl_hir_to_syn!(hir::Expr<'_>, syn::Expr); +impl_hir_to_syn!(hir::FnRetTy<'_>, syn::ReturnType); +impl_hir_to_syn!(hir::GenericArg<'_>, syn::GenericArgument); +impl_hir_to_syn!(hir::Lit, syn::Lit); +impl_hir_to_syn!(hir::ParamName, syn::Ident); +impl_hir_to_syn!(hir::Path<'_>, syn::Path); +impl_hir_to_syn!(hir::PathSegment<'_>, syn::PathSegment); +impl_hir_to_syn!(hir::Stmt<'_>, syn::Stmt); +impl_hir_to_syn!(hir::Ty<'_>, syn::Type); +impl_hir_to_syn!(hir::RangeEnd, syn::RangeLimits); +impl_hir_to_syn!(hir::UnOp, syn::UnOp); +impl_hir_to_syn!(span::symbol::Ident, syn::Ident); diff --git a/match_hir/src/toxic/mod.rs b/match_hir/src/toxic/mod.rs new file mode 100644 index 000000000..c67c023d0 --- /dev/null +++ b/match_hir/src/toxic/mod.rs @@ -0,0 +1,6 @@ +#![allow(clippy::disallowed_types)] + +mod unify; +pub use unify::Unify; + +pub mod variables; diff --git a/match_hir/src/toxic/unify.rs b/match_hir/src/toxic/unify.rs new file mode 100644 index 000000000..a58a8b377 --- /dev/null +++ b/match_hir/src/toxic/unify.rs @@ -0,0 +1,289 @@ +use super::variables::IsVariable; +use crate::{Binding, Error, ErrorKind, Visitable}; +use std::any::{Any, type_name}; +use syn::spanned::Spanned; + +trait SynNode: Any + Spanned {} + +struct NodeEntryExit<'ast> { + enter: bool, + type_name: &'static str, + node: &'ast dyn SynNode, + span: rustc_span::Span, +} + +impl std::fmt::Debug for NodeEntryExit<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "{:?}: {}({}) ({:p})", + self.span, + if self.enter { "Enter" } else { "Exit" }, + self.type_name, + std::ptr::from_ref(self.node).cast::<()>(), + )) + } +} + +pub trait Unify { + /// Arguments + /// + /// - `self` is the "scrutinee", i.e., a concrete `syn` AST with no "holes". + /// - `hir_span` is used to produce error messages. + /// - `pattern` is a `syn` AST with "holes". + /// - `bindings` records the subtrees that fill the holes. + fn unify( + &self, + span: rustc_span::Span, + pattern: &Self, + bindings: &mut Vec, + ) -> std::result::Result<(), Error>; +} + +impl Unify for T { + fn unify( + &self, + span: rustc_span::Span, + pattern: &Self, + bindings: &mut Vec, + ) -> std::result::Result<(), Error> { + let node_entry_exits = produce(span, self); + consume(&mut node_entry_exits.as_slice(), pattern, bindings) + } +} + +fn produce( + root_hir_span: rustc_span::Span, + scrutinee: &(impl SynNode + Visitable), +) -> Vec> { + let root_pm2_span = scrutinee.span(); + let mut visitor = Producer { + root_hir_span, + root_pm2_span, + nodes: Vec::new(), + }; + scrutinee.visit(&mut visitor); + visitor.nodes +} + +fn consume<'unify, 'ast>( + node_entry_exits: &'unify mut &'unify [NodeEntryExit<'ast>], + pattern: &'unify (impl SynNode + Visitable), + bindings: &'ast mut Vec, +) -> std::result::Result<(), Error> +where + 'unify: 'ast, +{ + let mut visitor = Consumer { + node_entry_exits, + pending_exits: Vec::new(), + bindings, + n_leaves: 0, + error: None, + }; + pattern.visit(&mut visitor); + assert!( + visitor.error.is_some() || visitor.pending_exits.is_empty(), + "pending exits remain: {:#?}", + visitor.pending_exits + ); + if let Some(error) = visitor.error { + Err(error) + } else { + Ok(()) + } +} + +struct Producer<'ast> { + root_hir_span: rustc_span::Span, + root_pm2_span: proc_macro2::Span, + nodes: Vec>, +} + +struct Consumer<'unify, 'ast> { + node_entry_exits: &'unify [NodeEntryExit<'ast>], + pending_exits: Vec<&'unify NodeEntryExit<'ast>>, + bindings: &'ast mut Vec, + n_leaves: usize, + error: Option, +} + +impl<'ast> Producer<'ast> { + fn visit_inner(&mut self, node: &'ast T) { + let type_name = type_name::(); + let node_pm2_span = node.span(); + let node_hir_span = shrink_hir_span(self.root_hir_span, self.root_pm2_span, node_pm2_span); + self.nodes.push(NodeEntryExit { + enter: true, + type_name, + node, + span: node_hir_span, + }); + T::visit_children(node, self); + self.nodes.push(NodeEntryExit { + enter: false, + type_name, + node, + span: node_hir_span, + }); + } +} + +impl<'ast> Consumer<'_, 'ast> { + fn visit_inner( + &mut self, + pattern: &'ast T, + ) { + // smoelius: `error` could have been set in a call to `visit_inner` in a previous sibling. + if self.error.is_some() { + return; + } + + let [ + NodeEntryExit { + enter: true, + type_name: _, + node: scrutinee, + span, + }, + .., + ] = self.node_entry_exits + else { + // smoelius: The scrutinee and pattern could both be of the same type (e.g., + // `syn::Expr`), but be different variants of that type (e.g., `syn::Expr::Block` and + // `syn::Expr::Call`), which can trigger this `else` case. Hence, this `else` case + // should not cause a panic. + self.set_error(Error::new(rustc_span::DUMMY_SP, ErrorKind::NoMatch)); + return; + }; + self.pending_exits.push(&self.node_entry_exits[0]); + pop_front(&mut self.node_entry_exits, 1); + + if pattern.is_variable() { + self.bindings.push(Binding::new::(*span)); + // smoelius: If the next `position` fails, the `assert` just after this `if`-`else` will + // (intentionally) panic. + if let Some(n) = self + .node_entry_exits + .iter() + .position(is_node_exit_for(*scrutinee)) + { + pop_front(&mut self.node_entry_exits, n); + } + } else { + let n_bindings_before = self.bindings.len(); + let n_leaves_before = self.n_leaves; + T::visit_children(pattern, self); + if self.error.is_some() { + return; + } + let n_bindings_after = self.bindings.len(); + let n_leaves_after = self.n_leaves; + + // smoelius: If the call to `T::visit_children` created no new bindings and did not + // change `self.n_leaves`, then `pattern` is a leaf and must match `scrutinee` exactly. + if n_bindings_before == n_bindings_after && n_leaves_before == n_leaves_after { + self.n_leaves += 1; + if (*scrutinee as &dyn Any).downcast_ref::() != Some(pattern) { + self.set_error(Error::new(*span, ErrorKind::NoMatch)); + return; + } + } + } + + // smoelius: There is no node for `syn`'s `Punctuated`. So when `scrutinee`'s children were + // visited, new node entries could have been uncovered. Thus, we cannot assume that the next + // element of `self.node_entry_exits` is an exit for `scrutinee`. If the next element of + // `self.node_entry_exits` is an entry for any node, the match has failed. + if let [ + NodeEntryExit { + enter: true, + type_name: _, + node: _, + span: span_sibling, + }, + .., + ] = self.node_entry_exits + { + self.set_error(Error::new(*span_sibling, ErrorKind::NoMatch)); + return; + } + + // smoelius: If the next element is not an entry, then it should be an exit specifically for + // `scrutinee`. + assert!( + matches!(self.node_entry_exits, [node_entry_exit, ..] if is_node_exit_for(*scrutinee)(node_entry_exit)), + "failed to find node exit: {:#?} {:#?}", + self.pending_exits, + self.node_entry_exits, + ); + pop_front(&mut self.node_entry_exits, 1); + self.pending_exits.pop().unwrap(); + } + + fn set_error(&mut self, error: Error) { + assert!( + self.error.is_none(), + "error was already set: {:?}", + self.error + ); + self.error = Some(error); + } +} + +// smoelius: The `proc_macro2::Span`s that `match_hir` constructs refer to text, not source files. +// Hence, their lines and columns are relative. +pub(crate) fn shrink_hir_span( + hir_span: rustc_span::Span, + pm2_span_larger: proc_macro2::Span, + pm2_span_smaller: proc_macro2::Span, +) -> rustc_span::Span { + let byte_range_larger = pm2_span_larger.byte_range(); + let byte_range_smaller = pm2_span_smaller.byte_range(); + + assert!(byte_range_larger.start <= byte_range_smaller.start); + assert!(byte_range_smaller.end <= byte_range_larger.end); + + let start_trim = u32::try_from(byte_range_smaller.start - byte_range_larger.start).unwrap(); + let end_trim = u32::try_from(byte_range_larger.end - byte_range_smaller.end).unwrap(); + + hir_span + .with_lo(hir_span.lo() + rustc_span::BytePos(start_trim)) + .with_hi(hir_span.hi() - rustc_span::BytePos(end_trim)) +} + +fn pop_front(queue: &mut &[T], n: usize) { + *queue = &queue[n..]; +} + +fn is_node_exit_for<'ast>(node: &'ast dyn SynNode) -> impl Fn(&NodeEntryExit<'ast>) -> bool { + |node_entry_exit| { + if let NodeEntryExit { + enter: false, + type_name: _, + node: other, + span: _, + } = node_entry_exit + { + std::ptr::from_ref::(node) == *other + } else { + false + } + } +} + +macro_rules! impl_is_variable { + ($ty:ident) => { + impl IsVariable for syn::$ty {} + }; +} + +macro_rules! impl_syn_node { + ($ty:ident) => { + impl SynNode for syn::$ty {} + }; +} + +include!(concat!(env!("OUT_DIR"), "/unify_variable.rs")); +include!(concat!(env!("OUT_DIR"), "/unify_node.rs")); +include!(concat!(env!("OUT_DIR"), "/unify_producer.rs")); +include!(concat!(env!("OUT_DIR"), "/unify_consumer.rs")); diff --git a/match_hir/src/toxic/variables/is_variable.rs b/match_hir/src/toxic/variables/is_variable.rs new file mode 100644 index 000000000..0a8a41623 --- /dev/null +++ b/match_hir/src/toxic/variables/is_variable.rs @@ -0,0 +1,105 @@ +use super::MARKER; + +pub(crate) trait IsVariable { + fn is_variable(&self) -> bool { + false + } +} + +impl IsVariable for syn::Expr { + fn is_variable(&self) -> bool { + if let syn::Expr::Path(syn::ExprPath { attrs, qself, path }) = self + && attrs.is_empty() + && qself.is_none() + { + path.is_variable() + } else { + false + } + } +} + +impl IsVariable for syn::Ident { + fn is_variable(&self) -> bool { + *self == MARKER + } +} + +impl IsVariable for syn::Pat { + fn is_variable(&self) -> bool { + if let syn::Pat::Ident(syn::PatIdent { + attrs, + by_ref, + mutability, + ident, + subpat, + }) = self + && attrs.is_empty() + && by_ref.is_none() + && mutability.is_none() + && subpat.is_none() + { + ident.is_variable() + } else { + false + } + } +} + +impl IsVariable for syn::Path { + fn is_variable(&self) -> bool { + if let Some(ident) = self.get_ident() { + ident.is_variable() + } else { + false + } + } +} + +impl IsVariable for syn::PathSegment { + fn is_variable(&self) -> bool { + self.ident.is_variable() && self.arguments.is_empty() + } +} + +impl IsVariable for syn::Stmt { + fn is_variable(&self) -> bool { + if let syn::Stmt::Expr(expr, _) = self { + expr.is_variable() + } else { + false + } + } +} + +impl IsVariable for syn::Type { + fn is_variable(&self) -> bool { + if let syn::Type::Path(syn::TypePath { qself, path }) = self + && qself.is_none() + { + path.is_variable() + } else { + false + } + } +} + +impl IsVariable for syn::GenericArgument { + fn is_variable(&self) -> bool { + if let syn::GenericArgument::Type(ty) = self { + ty.is_variable() + } else { + false + } + } +} + +impl IsVariable for syn::Member { + fn is_variable(&self) -> bool { + if let syn::Member::Named(ident) = self { + ident.is_variable() + } else { + false + } + } +} diff --git a/match_hir/src/toxic/variables/mod.rs b/match_hir/src/toxic/variables/mod.rs new file mode 100644 index 000000000..189d08479 --- /dev/null +++ b/match_hir/src/toxic/variables/mod.rs @@ -0,0 +1,63 @@ +use proc_macro2::{Delimiter, Group, Spacing, Span, TokenStream as TokenStream2, TokenTree}; + +mod is_variable; +pub(crate) use is_variable::IsVariable; + +const MARKER: &str = "__match_hir_variable__"; + +#[must_use] +pub(crate) fn mark(input: TokenStream2) -> (TokenStream2, usize) { + let mut iter = input.into_iter().peekable(); + let mut output = Vec::new(); + let mut n: usize = 0; + while let Some(tt) = iter.next() { + match &tt { + TokenTree::Punct(punct) => { + if punct.as_char() == '#' + && punct.spacing() == Spacing::Alone + && let Some(TokenTree::Group(group)) = iter.peek() + && group.delimiter() == Delimiter::Parenthesis + // smoelius: Currently, we only check for/permit the wildcard character (`_`) + // inside the parens. In the future, we might want to allow the variable name + // inside the parens. + && let [token] = group.stream().into_iter().collect::>().as_slice() + && let TokenTree::Ident(ident) = token + && *ident == "_" + { + #[allow(let_underscore_drop, clippy::unwrap_used)] + let _ = iter.next().unwrap(); + output.push(TokenTree::Ident(syn::Ident::new(MARKER, Span::call_site()))); + n += 1; + } else { + output.push(tt); + } + } + TokenTree::Group(group) => { + let (stream, m) = mark(group.stream()); + output.push(TokenTree::Group(Group::new(group.delimiter(), stream))); + n += m; + } + _ => { + output.push(tt); + } + } + } + (output.into_iter().collect(), n) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn mark_variables() { + let (stream, n) = super::mark(quote::quote! { + let #(_) = #(_) + 1; + }); + assert_eq!( + quote::ToTokens::to_token_stream(&stream).to_string(), + format!("let {MARKER} = {MARKER} + 1 ;") + ); + assert_eq!(2, n); + } +} diff --git a/match_hir/src/type_name.rs b/match_hir/src/type_name.rs new file mode 100644 index 000000000..8cd991be5 --- /dev/null +++ b/match_hir/src/type_name.rs @@ -0,0 +1,42 @@ +use crate::HirToSyn; +use rustc_hir as hir; +use std::marker::PhantomData; + +// smoelius: `TypeNameGetter` uses Nikolai Vazquez's trick from `impls`. See: +// https://github.com/nvzqz/impls#how-it-works + +struct TypeNameGetter(PhantomData); + +trait HirToSynUnimplemented { + fn type_name() -> Option<&'static str>; +} + +impl HirToSynUnimplemented for TypeNameGetter { + /// If `HirToSyn` is not implemented for `T`, `type_name` will resolve to this trait method. + fn type_name() -> Option<&'static str> { + None + } +} + +impl TypeNameGetter { + /// If `HirToSyn` is implemented for `T`, `type_name` will resolve to this inherent method. + #[allow(clippy::unnecessary_wraps)] + fn type_name() -> Option<&'static str> { + Some(std::any::type_name::()) + } +} + +#[test] +fn sanity_implemented() { + assert_eq!( + Some("syn::expr::Expr"), + TypeNameGetter::::type_name() + ); +} + +#[test] +fn sanity_unimplemented() { + assert_eq!(None, TypeNameGetter::::type_name()); +} + +include!(concat!(env!("OUT_DIR"), "/type_name.rs")); diff --git a/match_hir/src/visitable.rs b/match_hir/src/visitable.rs new file mode 100644 index 000000000..f39542f5d --- /dev/null +++ b/match_hir/src/visitable.rs @@ -0,0 +1,23 @@ +use paste::paste; + +pub trait Visitable { + fn visit<'ast, V: syn::visit::Visit<'ast>>(&'ast self, _visitor: &mut V) {} + fn visit_children<'ast, V: syn::visit::Visit<'ast>>(&'ast self, _visitor: &mut V) {} +} + +macro_rules! impl_visitable { + ($ty:ident, $ty_snake:ident) => { + paste! { + impl Visitable for syn::$ty { + fn visit<'ast, V: syn::visit::Visit<'ast>>(&'ast self, visitor: &mut V) { + visitor.[< visit_ $ty_snake >](self); + } + fn visit_children<'ast, V: syn::visit::Visit<'ast>>(&'ast self, visitor: &mut V) { + syn::visit::[< visit_ $ty_snake >](visitor, self); + } + } + } + }; +} + +include!(concat!(env!("OUT_DIR"), "/visitable.rs")); diff --git a/match_hir/tests/meta.rs b/match_hir/tests/meta.rs new file mode 100644 index 000000000..c9677502d --- /dev/null +++ b/match_hir/tests/meta.rs @@ -0,0 +1,35 @@ +use assert_cmd::Command; +use snapbox::assert_data_eq; +use std::{fs::read_to_string, path::Path}; + +#[test] +fn self_reflective_match_exact() { + self_reflective_match(false); +} + +#[test] +fn self_reflective_match_wildcard() { + self_reflective_match(true); +} + +fn self_reflective_match(wildcard: bool) { + Command::new("cargo") + .arg("build") + .current_dir("reflective_match") + .assert() + .success(); + + let mut command = Command::new("cargo"); + command.args(["dylint", "--path", "reflective_match", "--", "--quiet"]); + if wildcard { + command.env("WILDCARD", "1"); + } + let assert = command.assert().success(); + let stderr_expected = read_to_string(Path::new("tests").join(format!( + "reflective_match_{}.stderr", + if wildcard { "wildcard" } else { "exact" } + ))) + .unwrap(); + let stderr_actual = std::str::from_utf8(&assert.get_output().stderr).unwrap(); + assert_data_eq!(stderr_actual, &stderr_expected); +} diff --git a/match_hir/tests/reflective_match_exact.stderr b/match_hir/tests/reflective_match_exact.stderr new file mode 100644 index 000000000..3f96330a5 --- /dev/null +++ b/match_hir/tests/reflective_match_exact.stderr @@ -0,0 +1,8 @@ +... +name: "build_script_main" +errors: 0 +name: "match_hir" +errors: 3 +src/error.rs:48:14: 48:21 (#0): parse error: unexpected end of input, expected an expression +src/error.rs:51:16: 51:23 (#0): parse error: unexpected end of input, expected an expression +src/error.rs:66:11: 66:18 (#0): parse error: unexpected end of input, expected an expression diff --git a/match_hir/tests/reflective_match_wildcard.stderr b/match_hir/tests/reflective_match_wildcard.stderr new file mode 100644 index 000000000..1a512c718 --- /dev/null +++ b/match_hir/tests/reflective_match_wildcard.stderr @@ -0,0 +1,12 @@ +... +name: "build_script_main" +errors: 0 +name: "match_hir" +errors: 4 +src/error.rs:62:13: 62:49 (#0): `HirId`s do not match + snippet: "/"found no `HirId` for `{type_name}`/"" + expected: HirId(DefId(0:[..] ~ match_hir[[..]]::error::{impl#6}::fmt).[..]) + actual: HirId(DefId(0:[..] ~ match_hir[[..]]::error::{impl#6}::fmt).[..]) +src/error.rs:48:14: 48:21 (#0): parse error: unexpected end of input, expected an expression +src/error.rs:51:16: 51:23 (#0): parse error: unexpected end of input, expected an expression +src/error.rs:66:11: 66:18 (#0): parse error: unexpected end of input, expected an expression