mirror of https://github.com/smithy-lang/smithy-rs
Remove `cargo-check-external-types` (#1820)
This tool now has its own repository: https://github.com/awslabs/cargo-check-external-types
This commit is contained in:
parent
bf3fbc2e1d
commit
046edd54ab
|
@ -51,6 +51,7 @@ ARG cargo_deny_version=0.12.2
|
|||
ARG cargo_udeps_version=0.1.29
|
||||
ARG cargo_hack_version=0.5.14
|
||||
ARG cargo_minimal_versions_version=0.1.4
|
||||
ARG cargo_check_external_types_version=0.1.4
|
||||
ENV RUSTUP_HOME=/opt/rustup \
|
||||
CARGO_HOME=/opt/cargo \
|
||||
PATH=/opt/cargo/bin/:${PATH} \
|
||||
|
@ -97,14 +98,14 @@ RUN set -eux; \
|
|||
cargo install cargo-deny --locked --version ${cargo_deny_version}; \
|
||||
cargo +${rust_nightly_version} install cargo-udeps --locked --version ${cargo_udeps_version}; \
|
||||
cargo install cargo-hack --locked --version ${cargo_hack_version}; \
|
||||
cargo install cargo-minimal-versions --version ${cargo_minimal_versions_version}; \
|
||||
cargo install cargo-minimal-versions --locked --version ${cargo_minimal_versions_version}; \
|
||||
cargo install cargo-check-external-types --locked --version ${cargo_check_external_types_version}; \
|
||||
if [[ "${checkout_smithy_rs_tools}" == "true" ]]; then \
|
||||
git clone https://github.com/awslabs/smithy-rs.git; \
|
||||
cd smithy-rs; \
|
||||
git checkout ${smithy_rs_commit_hash}; \
|
||||
fi; \
|
||||
cargo install --locked --path tools/publisher; \
|
||||
cargo install --locked --path tools/cargo-check-external-types; \
|
||||
cargo install --locked --path tools/changelogger; \
|
||||
cargo install --locked --path tools/crate-hasher; \
|
||||
cargo install --locked --path tools/sdk-lints; \
|
||||
|
|
|
@ -1,630 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-check-external-types"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"clap",
|
||||
"owo-colors",
|
||||
"pest",
|
||||
"pretty_assertions",
|
||||
"rustdoc-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"test_bin",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-attributes",
|
||||
"tracing-subscriber",
|
||||
"wildmatch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_ci"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||
dependencies = [
|
||||
"supports-color",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"ctor",
|
||||
"diff",
|
||||
"output_vt100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc-types"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3a260c376ebec8b6fcd30f518b253772873c5dd8564b45e384aad8a79c62aa6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "supports-color"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4872ced36b91d47bae8a214a683fe54e7078875b399dfa251df346c9b547d1f9"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"is_ci",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test_bin"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e7a7de15468c6e65dd7db81cf3822c1ec94c71b2a3c1a976ea8e4696c91115c"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"matchers",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wildmatch"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86"
|
||||
|
||||
[[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-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
@ -1,27 +0,0 @@
|
|||
[package]
|
||||
name = "cargo-check-external-types"
|
||||
version = "0.1.3"
|
||||
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "John DiSanti <jdisanti@amazon.com>"]
|
||||
description = "Static analysis tool to detect external types exposed in a library's public API."
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/awslabs/smithy-rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
cargo_metadata = "0.14"
|
||||
clap = { version = "~3.1.18", features = ["derive"] }
|
||||
owo-colors = { version = "3", features = ["supports-colors"] }
|
||||
pest = "2" # For pretty error formatting
|
||||
rustdoc-types = "0.12"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
toml = "0.5"
|
||||
tracing = "0.1"
|
||||
tracing-attributes = "0.1"
|
||||
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] }
|
||||
wildmatch = "2"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.1"
|
||||
test_bin = "0.4"
|
|
@ -1,175 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
|
@ -1,61 +0,0 @@
|
|||
cargo-check-external-types
|
||||
==========================
|
||||
|
||||
Static analysis tool that detects external types used in a Rust library's public API.
|
||||
Configuration can be provided to allow certain external types so that this tool can
|
||||
be used in continuous integration so that types don't unintentionally make it into
|
||||
the library's API. It can also output a Markdown table of the external types it found.
|
||||
|
||||
Example Output
|
||||
--------------
|
||||
|
||||
The test suite has a Rust library that [relies on some external types](test-workspace/test-crate/src/lib.rs).
|
||||
When the tool is run against this library without any configuration,
|
||||
[it emits errors](tests/default-config-expected-output.txt)
|
||||
for each occurrence of an external type in the public API.
|
||||
|
||||
When [a config file](tests/allow-some-types.toml) is provided,
|
||||
the allowed external types [no longer show up in the output](tests/allow-some-types-expected-output.txt).
|
||||
|
||||
When the output format is set to `markdown-table`, then
|
||||
a [table of external types](tests/output-format-markdown-table-expected-output.md) is output.
|
||||
|
||||
How to Use
|
||||
----------
|
||||
|
||||
_Important:_ This tool requires a nightly build of Rust to be installed since it relies on rustdoc JSON output.
|
||||
It was last tested against nightly-2022-07-25.
|
||||
|
||||
To install, run the following from this README path:
|
||||
|
||||
```bash
|
||||
cargo install --locked cargo-check-external-types
|
||||
```
|
||||
|
||||
Then, in your library crate path, run:
|
||||
```bash
|
||||
cargo +nightly check-external-types
|
||||
```
|
||||
|
||||
This will produce errors if any external types are used in a public API at all. That's not terribly useful
|
||||
on its own, so the tool can be given a config file to allow certain types. For example, we can allow
|
||||
any type in `bytes` with:
|
||||
|
||||
```toml
|
||||
allowed_external_types = [
|
||||
"bytes::*",
|
||||
]
|
||||
```
|
||||
|
||||
Save that file somewhere in your project (in this example, we choose the name `external-types.toml`), and then
|
||||
run the command with:
|
||||
|
||||
```bash
|
||||
cargo +nightly check-external-types --config external-types.toml
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This tool is distributed under the terms of Apache License Version 2.0.
|
||||
See the [LICENSE](LICENSE) file for more information.
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
cargo clippy
|
||||
cargo "+${RUST_NIGHTLY_VERSION}" test
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use crate::here;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use rustdoc_types::{Crate, FORMAT_VERSION};
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Output};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CrateFormatVersion {
|
||||
format_version: u32,
|
||||
}
|
||||
|
||||
/// Runs the `cargo rustdoc` command required to produce Rustdoc's JSON output with a nightly compiler.
|
||||
pub struct CargoRustDocJson {
|
||||
/// Name of the crate (as specified in the Cargo.toml file)
|
||||
crate_name: String,
|
||||
/// Path of the crate to examine
|
||||
crate_path: PathBuf,
|
||||
/// Expected `target/` directory where the output will be
|
||||
target_path: PathBuf,
|
||||
/// Features to enable
|
||||
features: Vec<String>,
|
||||
}
|
||||
|
||||
impl CargoRustDocJson {
|
||||
pub fn new(
|
||||
crate_name: impl Into<String>,
|
||||
crate_path: impl Into<PathBuf>,
|
||||
target_path: impl Into<PathBuf>,
|
||||
features: Vec<String>,
|
||||
) -> Self {
|
||||
CargoRustDocJson {
|
||||
crate_name: crate_name.into(),
|
||||
crate_path: crate_path.into(),
|
||||
target_path: target_path.into(),
|
||||
features,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Result<Crate> {
|
||||
let cargo = std::env::var("CARGO")
|
||||
.ok()
|
||||
.unwrap_or_else(|| "cargo".to_string());
|
||||
|
||||
let mut command = Command::new(&cargo);
|
||||
command.current_dir(&self.crate_path).arg("rustdoc");
|
||||
if !self.features.is_empty() {
|
||||
command.arg("--no-default-features").arg("--features");
|
||||
command.arg(&self.features.join(","));
|
||||
}
|
||||
command
|
||||
.arg("--")
|
||||
.arg("--document-private-items")
|
||||
.arg("-Z")
|
||||
.arg("unstable-options")
|
||||
.arg("--output-format")
|
||||
.arg("json");
|
||||
let output = command
|
||||
.output()
|
||||
.context(here!("failed to run nightly rustdoc"))?;
|
||||
handle_failure("rustdoc", &output)?;
|
||||
|
||||
let output_file_name = self
|
||||
.target_path
|
||||
.canonicalize()
|
||||
.context(here!())?
|
||||
.join(format!("doc/{}.json", self.crate_name.replace('-', "_")));
|
||||
|
||||
let json = fs::read_to_string(output_file_name).context(here!())?;
|
||||
let format_version: CrateFormatVersion = serde_json::from_str(&json)
|
||||
.context("Failed to find `format_version` in rustdoc JSON output.")
|
||||
.context(here!())?;
|
||||
if format_version.format_version != FORMAT_VERSION {
|
||||
bail!(
|
||||
"The version of rustdoc being used produces JSON format version {0}, but \
|
||||
this tool requires format version {1}. This can happen if the locally \
|
||||
installed version of rustdoc doesn't match the rustdoc JSON types from \
|
||||
the `rustdoc-types` crate.\n\n\
|
||||
If this occurs with the latest Rust nightly and the latest version of this \
|
||||
tool, then this is a bug, and the tool needs to be upgraded to the latest \
|
||||
format version.\n\n\
|
||||
Otherwise, you'll need to determine a Rust nightly version that matches \
|
||||
this tool's supported format version (or vice versa).",
|
||||
format_version.format_version,
|
||||
FORMAT_VERSION
|
||||
);
|
||||
}
|
||||
let package: Crate = serde_json::from_str(&json)
|
||||
.context("Failed to parse rustdoc output.")
|
||||
.context(here!())?;
|
||||
Ok(package)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_failure(operation_name: &str, output: &Output) -> Result<(), anyhow::Error> {
|
||||
if !output.status.success() {
|
||||
return Err(capture_error(operation_name, output));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn capture_error(operation_name: &str, output: &Output) -> anyhow::Error {
|
||||
let message = format!(
|
||||
"Failed to {name}:\nStatus: {status}\nStdout: {stdout}\nStderr: {stderr}\n",
|
||||
name = operation_name,
|
||||
status = if let Some(code) = output.status.code() {
|
||||
format!("{}", code)
|
||||
} else {
|
||||
"Killed by signal".to_string()
|
||||
},
|
||||
stdout = String::from_utf8_lossy(&output.stdout),
|
||||
stderr = String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
anyhow::Error::msg(message)
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use serde::de::{SeqAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::fmt;
|
||||
use wildmatch::WildMatch;
|
||||
|
||||
/// Struct reprepsentation of the TOML config files that specify which external types are allowed.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Config {
|
||||
/// Whether or not to allow types from `alloc`. Defaults to true.
|
||||
#[serde(default = "default_allow_std")]
|
||||
pub allow_alloc: bool,
|
||||
|
||||
/// Whether or not to allow types from `core`. Defaults to true.
|
||||
#[serde(default = "default_allow_std")]
|
||||
pub allow_core: bool,
|
||||
|
||||
/// Whether or not to allow types from `std`. Defaults to true.
|
||||
#[serde(default = "default_allow_std")]
|
||||
pub allow_std: bool,
|
||||
|
||||
/// List of globs for allowed external types
|
||||
///
|
||||
/// For example, to allow every type in a crate:
|
||||
/// ```toml
|
||||
/// allowed_external_types = [
|
||||
/// "crate_name::*"
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// Or, to selectively allow just a module of that crate
|
||||
/// ```toml
|
||||
/// allowed_external_types = [
|
||||
/// "crate_name::path::to_module::*"
|
||||
/// ]
|
||||
/// ```
|
||||
#[serde(deserialize_with = "deserialize_vec_wild_match")]
|
||||
pub allowed_external_types: Vec<WildMatch>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Returns true if the given `type_name` is allowed by this config for the given `root_crate_name`.
|
||||
pub fn allows_type(&self, root_crate_name: &str, type_name: &str) -> bool {
|
||||
let type_crate_name = &type_name[0..type_name.find("::").unwrap_or(type_name.len())];
|
||||
match type_crate_name {
|
||||
_ if type_crate_name == root_crate_name => true,
|
||||
"alloc" => self.allow_alloc,
|
||||
"core" => self.allow_core,
|
||||
"std" => self.allow_std,
|
||||
_ => self
|
||||
.allowed_external_types
|
||||
.iter()
|
||||
.any(|glob| glob.matches(type_name)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
allow_alloc: default_allow_std(),
|
||||
allow_core: default_allow_std(),
|
||||
allow_std: default_allow_std(),
|
||||
allowed_external_types: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn default_allow_std() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
struct VecWildMatchDeserializer;
|
||||
|
||||
impl<'de> Visitor<'de> for VecWildMatchDeserializer {
|
||||
type Value = Vec<WildMatch>;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("list of glob strings")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
let mut result = Vec::new();
|
||||
while let Some(value) = seq.next_element::<&str>()? {
|
||||
result.push(WildMatch::new(value));
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_vec_wild_match<'de, D>(de: D) -> Result<Vec<WildMatch>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de.deserialize_any(VecWildMatchDeserializer)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Config;
|
||||
use wildmatch::WildMatch;
|
||||
|
||||
#[test]
|
||||
fn deserialize_config() {
|
||||
let config = r#"
|
||||
allow_std = false
|
||||
allowed_external_types = [
|
||||
"test::*",
|
||||
"another_test::something::*::something",
|
||||
]
|
||||
"#;
|
||||
let config: Config = toml::from_str(config).unwrap();
|
||||
assert!(config.allow_alloc);
|
||||
assert!(config.allow_core);
|
||||
assert!(!config.allow_std);
|
||||
assert!(config.allowed_external_types[0].matches("test::something"));
|
||||
assert!(!config.allowed_external_types[0].matches("other::something"));
|
||||
assert!(config.allowed_external_types[1].matches("another_test::something::foo::something"));
|
||||
assert!(!config.allowed_external_types[1].matches("another_test::other::foo::something"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_allows_type() {
|
||||
let config = Config {
|
||||
allowed_external_types: vec![WildMatch::new("one::*"), WildMatch::new("two::*")],
|
||||
..Default::default()
|
||||
};
|
||||
assert!(config.allows_type("root", "alloc::System"));
|
||||
assert!(config.allows_type("root", "std::vec::Vec"));
|
||||
assert!(config.allows_type("root", "std::path::Path"));
|
||||
|
||||
assert!(config.allows_type("root", "root::thing"));
|
||||
assert!(config.allows_type("root", "one::thing"));
|
||||
assert!(config.allows_type("root", "two::thing"));
|
||||
assert!(!config.allows_type("root", "three::thing"));
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use owo_colors::{OwoColorize, Stream};
|
||||
use pest::Position;
|
||||
use rustdoc_types::Span;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Where the error occurred relative to the [`Path`](crate::path::Path).
|
||||
///
|
||||
/// For example, if the path is a path to a function, then this could point to something
|
||||
/// specific about that function, such as a specific function argument that is in error.
|
||||
///
|
||||
/// There is overlap in this enum with [`ComponentType`](crate::path::ComponentType) since
|
||||
/// some paths are specific enough to locate the external type.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ErrorLocation {
|
||||
AssocType,
|
||||
ArgumentNamed(String),
|
||||
ClosureInput,
|
||||
ClosureOutput,
|
||||
ConstGeneric,
|
||||
Constant,
|
||||
EnumTupleEntry,
|
||||
GenericArg,
|
||||
GenericDefaultBinding,
|
||||
ImplementedTrait,
|
||||
QualifiedSelfType,
|
||||
QualifiedSelfTypeAsTrait,
|
||||
ReExport,
|
||||
ReturnValue,
|
||||
Static,
|
||||
StructField,
|
||||
TraitBound,
|
||||
TypeDef,
|
||||
WhereBound,
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorLocation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s = match self {
|
||||
Self::AssocType => "associated type",
|
||||
Self::ArgumentNamed(name) => return write!(f, "argument named `{}` of", name),
|
||||
Self::ClosureInput => "closure input of",
|
||||
Self::ClosureOutput => "closure output of",
|
||||
Self::ConstGeneric => "const generic of",
|
||||
Self::Constant => "constant",
|
||||
Self::EnumTupleEntry => "enum tuple entry of",
|
||||
Self::GenericArg => "generic arg of",
|
||||
Self::GenericDefaultBinding => "generic default binding of",
|
||||
Self::ImplementedTrait => "implemented trait of",
|
||||
Self::QualifiedSelfType => "qualified self type",
|
||||
Self::QualifiedSelfTypeAsTrait => "qualified type `as` trait",
|
||||
Self::ReExport => "re-export named",
|
||||
Self::ReturnValue => "return value of",
|
||||
Self::Static => "static value",
|
||||
Self::StructField => "struct field of",
|
||||
Self::TraitBound => "trait bound of",
|
||||
Self::TypeDef => "typedef type of",
|
||||
Self::WhereBound => "where bound of",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type for validation errors that get displayed to the user on the CLI.
|
||||
#[derive(Debug)]
|
||||
pub enum ValidationError {
|
||||
UnapprovedExternalTypeRef {
|
||||
type_name: String,
|
||||
what: ErrorLocation,
|
||||
in_what_type: String,
|
||||
location: Option<Span>,
|
||||
sort_key: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl ValidationError {
|
||||
pub fn unapproved_external_type_ref(
|
||||
type_name: impl Into<String>,
|
||||
what: &ErrorLocation,
|
||||
in_what_type: impl Into<String>,
|
||||
location: Option<&Span>,
|
||||
) -> Self {
|
||||
let type_name = type_name.into();
|
||||
let in_what_type = in_what_type.into();
|
||||
let sort_key = format!(
|
||||
"{}:{}:{}:{}",
|
||||
location_sort_key(location),
|
||||
type_name,
|
||||
what,
|
||||
in_what_type
|
||||
);
|
||||
Self::UnapprovedExternalTypeRef {
|
||||
type_name,
|
||||
what: what.clone(),
|
||||
in_what_type,
|
||||
location: location.cloned(),
|
||||
sort_key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_name(&self) -> &str {
|
||||
match self {
|
||||
Self::UnapprovedExternalTypeRef { type_name, .. } => type_name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn location(&self) -> Option<&Span> {
|
||||
match self {
|
||||
Self::UnapprovedExternalTypeRef { location, .. } => location.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_key(&self) -> &str {
|
||||
match self {
|
||||
Self::UnapprovedExternalTypeRef { sort_key, .. } => sort_key.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt_headline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::UnapprovedExternalTypeRef { type_name, .. } => {
|
||||
let inner = format!(
|
||||
"Unapproved external type `{}` referenced in public API",
|
||||
type_name
|
||||
);
|
||||
write!(
|
||||
f,
|
||||
"{} {}",
|
||||
"error:"
|
||||
.if_supports_color(Stream::Stdout, |text| text.red())
|
||||
.if_supports_color(Stream::Stdout, |text| text.bold()),
|
||||
inner.if_supports_color(Stream::Stdout, |text| text.bold())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subtext(&self) -> String {
|
||||
match self {
|
||||
Self::UnapprovedExternalTypeRef {
|
||||
what, in_what_type, ..
|
||||
} => format!("in {} `{}`", what, in_what_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn location_sort_key(location: Option<&Span>) -> String {
|
||||
if let Some(location) = location {
|
||||
format!(
|
||||
"{}:{:07}:{:07}",
|
||||
location.filename.to_string_lossy(),
|
||||
location.begin.0,
|
||||
location.begin.1
|
||||
)
|
||||
} else {
|
||||
"none".into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ValidationError {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ValidationError {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.sort_key().partial_cmp(other.sort_key())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ValidationError {}
|
||||
|
||||
impl PartialEq for ValidationError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.sort_key() == other.sort_key()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ValidationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.fmt_headline(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pretty printer for error context.
|
||||
///
|
||||
/// This makes validation errors look similar to the compiler errors from rustc.
|
||||
pub struct ErrorPrinter {
|
||||
workspace_root: PathBuf,
|
||||
file_cache: HashMap<PathBuf, String>,
|
||||
}
|
||||
|
||||
impl ErrorPrinter {
|
||||
pub fn new(workspace_root: impl Into<PathBuf>) -> Self {
|
||||
Self {
|
||||
workspace_root: workspace_root.into(),
|
||||
file_cache: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_file_contents(&mut self, path: &Path) -> Result<&str> {
|
||||
if !self.file_cache.contains_key(path) {
|
||||
let full_file_name = self.workspace_root.join(path).canonicalize()?;
|
||||
let contents = std::fs::read_to_string(&full_file_name)
|
||||
.context("failed to load source file for error context")
|
||||
.context(full_file_name.to_string_lossy().to_string())?;
|
||||
self.file_cache.insert(path.to_path_buf(), contents);
|
||||
}
|
||||
Ok(self.file_cache.get(path).unwrap())
|
||||
}
|
||||
|
||||
pub fn pretty_print_error_context(&mut self, location: &Span, subtext: String) {
|
||||
match self.get_file_contents(&location.filename) {
|
||||
Ok(file_contents) => {
|
||||
let begin = Self::position_from_line_col(file_contents, location.begin);
|
||||
let end = Self::position_from_line_col(file_contents, location.end);
|
||||
|
||||
// HACK: Using Pest to do the pretty error context formatting for lack of
|
||||
// knowledge of a smaller library tailored to this use-case
|
||||
let variant = pest::error::ErrorVariant::<()>::CustomError { message: subtext };
|
||||
let err_context = match (begin, end) {
|
||||
(Some(b), Some(e)) => {
|
||||
Some(pest::error::Error::new_from_span(variant, b.span(&e)))
|
||||
}
|
||||
(Some(b), None) => Some(pest::error::Error::new_from_pos(variant, b)),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(err_context) = err_context {
|
||||
println!(
|
||||
"{}\n",
|
||||
err_context.with_path(&location.filename.to_string_lossy())
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("error: {subtext}");
|
||||
println!(
|
||||
" --> {}:{}:{}",
|
||||
location.filename.to_string_lossy(),
|
||||
location.begin.0,
|
||||
location.begin.1 + 1
|
||||
);
|
||||
println!(" | Failed to load {:?}", location.filename);
|
||||
println!(" | relative to {:?}", self.workspace_root);
|
||||
println!(" | to provide error message context.");
|
||||
println!(" | Cause: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn position_from_line_col(contents: &str, (line, col): (usize, usize)) -> Option<Position> {
|
||||
let (mut cl, mut cc) = (1, 1);
|
||||
let content_bytes = contents.as_bytes();
|
||||
for (index, &byte) in content_bytes.iter().enumerate() {
|
||||
if cl == line && cc == col {
|
||||
return Position::new(contents, index);
|
||||
}
|
||||
|
||||
cc += 1;
|
||||
if byte == b'\n' {
|
||||
cl += 1;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
pub mod cargo;
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod path;
|
||||
pub mod visitor;
|
||||
|
||||
/// A macro for attaching info to error messages pointing to the line of code responsible for the error.
|
||||
/// [Thanks to dtolnay for this macro](https://github.com/dtolnay/anyhow/issues/22#issuecomment-542309452)
|
||||
#[macro_export]
|
||||
macro_rules! here {
|
||||
() => {
|
||||
concat!("error at ", file!(), ":", line!(), ":", column!())
|
||||
};
|
||||
($message:tt) => {
|
||||
concat!($message, " (", here!(), ")")
|
||||
};
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use anyhow::{Context, Result};
|
||||
use cargo_check_external_types::cargo::CargoRustDocJson;
|
||||
use cargo_check_external_types::error::ErrorPrinter;
|
||||
use cargo_check_external_types::here;
|
||||
use cargo_check_external_types::visitor::Visitor;
|
||||
use cargo_metadata::{CargoOpt, Metadata};
|
||||
use clap::Parser;
|
||||
use owo_colors::{OwoColorize, Stream};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::str::FromStr;
|
||||
use tracing_subscriber::prelude::*;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OutputFormat {
|
||||
Errors,
|
||||
MarkdownTable,
|
||||
}
|
||||
|
||||
impl fmt::Display for OutputFormat {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::Errors => "errors",
|
||||
Self::MarkdownTable => "markdown-table",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for OutputFormat {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"errors" => Ok(OutputFormat::Errors),
|
||||
"markdown-table" => Ok(OutputFormat::MarkdownTable),
|
||||
_ => Err(anyhow!(
|
||||
"invalid output format: {}. Expected `errors` or `markdown-table`.",
|
||||
s
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(clap::Args, Debug)]
|
||||
struct CheckExternalTypesArgs {
|
||||
/// Enables all crate features
|
||||
#[clap(long)]
|
||||
all_features: bool,
|
||||
/// Disables default features
|
||||
#[clap(long)]
|
||||
no_default_features: bool,
|
||||
/// Comma delimited list of features to enable in the crate
|
||||
#[clap(long, use_value_delimiter = true)]
|
||||
features: Option<Vec<String>>,
|
||||
/// Path to the Cargo manifest
|
||||
manifest_path: Option<PathBuf>,
|
||||
|
||||
/// Path to config toml to read
|
||||
#[clap(long)]
|
||||
config: Option<PathBuf>,
|
||||
/// Enable verbose output for debugging
|
||||
#[clap(short, long)]
|
||||
verbose: bool,
|
||||
/// Format to output results in
|
||||
#[clap(long, default_value_t = OutputFormat::Errors)]
|
||||
output_format: OutputFormat,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, bin_name = "cargo")]
|
||||
enum Args {
|
||||
CheckExternalTypes(CheckExternalTypesArgs),
|
||||
}
|
||||
|
||||
enum Error {
|
||||
ValidationErrors,
|
||||
Failure(anyhow::Error),
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for Error {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
Error::Failure(err)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
process::exit(match run_main() {
|
||||
Ok(_) => 0,
|
||||
Err(Error::ValidationErrors) => 1,
|
||||
Err(Error::Failure(err)) => {
|
||||
println!("{:#}", dbg!(err));
|
||||
2
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn run_main() -> Result<(), Error> {
|
||||
let Args::CheckExternalTypes(args) = Args::parse();
|
||||
if args.verbose {
|
||||
let filter_layer = EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_new("debug"))
|
||||
.unwrap();
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.without_time()
|
||||
.with_ansi(true)
|
||||
.with_level(true)
|
||||
.with_target(false)
|
||||
.pretty();
|
||||
tracing_subscriber::registry()
|
||||
.with(filter_layer)
|
||||
.with(fmt_layer)
|
||||
.init();
|
||||
}
|
||||
|
||||
let config = if let Some(config_path) = &args.config {
|
||||
let contents = fs::read_to_string(config_path).context("failed to read config file")?;
|
||||
toml::from_str(&contents).context("failed to parse config file")?
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let mut cargo_metadata_cmd = cargo_metadata::MetadataCommand::new();
|
||||
if args.all_features {
|
||||
cargo_metadata_cmd.features(CargoOpt::AllFeatures);
|
||||
}
|
||||
if args.no_default_features {
|
||||
cargo_metadata_cmd.features(CargoOpt::NoDefaultFeatures);
|
||||
}
|
||||
if let Some(features) = args.features {
|
||||
cargo_metadata_cmd.features(CargoOpt::SomeFeatures(features));
|
||||
}
|
||||
let crate_path = if let Some(manifest_path) = args.manifest_path {
|
||||
cargo_metadata_cmd.manifest_path(&manifest_path);
|
||||
manifest_path
|
||||
.canonicalize()
|
||||
.context(here!())?
|
||||
.parent()
|
||||
.expect("parent path")
|
||||
.to_path_buf()
|
||||
} else {
|
||||
std::env::current_dir()
|
||||
.context(here!())?
|
||||
.canonicalize()
|
||||
.context(here!())?
|
||||
};
|
||||
let cargo_metadata = cargo_metadata_cmd.exec().context(here!())?;
|
||||
let cargo_features = resolve_features(&cargo_metadata)?;
|
||||
|
||||
eprintln!("Running rustdoc to produce json doc output...");
|
||||
let package = CargoRustDocJson::new(
|
||||
&*cargo_metadata
|
||||
.root_package()
|
||||
.as_ref()
|
||||
.map(|package| Cow::Borrowed(package.name.as_str()))
|
||||
.unwrap_or_else(|| crate_path.file_name().expect("file name").to_string_lossy()),
|
||||
&crate_path,
|
||||
&cargo_metadata.target_directory,
|
||||
cargo_features,
|
||||
)
|
||||
.run()
|
||||
.context(here!())?;
|
||||
|
||||
eprintln!("Examining all public types...");
|
||||
let errors = Visitor::new(config, package)?.visit_all()?;
|
||||
match args.output_format {
|
||||
OutputFormat::Errors => {
|
||||
let mut error_printer = ErrorPrinter::new(&cargo_metadata.workspace_root);
|
||||
for error in &errors {
|
||||
println!("{}", error);
|
||||
if let Some(location) = error.location() {
|
||||
error_printer.pretty_print_error_context(location, error.subtext())
|
||||
}
|
||||
}
|
||||
if !errors.is_empty() {
|
||||
println!(
|
||||
"{} {} emitted",
|
||||
errors.len(),
|
||||
"errors".if_supports_color(Stream::Stdout, |text| text.red())
|
||||
);
|
||||
return Err(Error::ValidationErrors);
|
||||
}
|
||||
}
|
||||
OutputFormat::MarkdownTable => {
|
||||
println!("| Crate | Type | Used In |");
|
||||
println!("| --- | --- | --- |");
|
||||
let mut rows = Vec::new();
|
||||
for error in &errors {
|
||||
let type_name = error.type_name();
|
||||
let crate_name = &type_name[0..type_name.find("::").unwrap_or(type_name.len())];
|
||||
let location = error.location().unwrap();
|
||||
rows.push(format!(
|
||||
"| {} | {} | {}:{}:{} |",
|
||||
crate_name,
|
||||
type_name,
|
||||
location.filename.to_string_lossy(),
|
||||
location.begin.0,
|
||||
location.begin.1
|
||||
));
|
||||
}
|
||||
rows.sort();
|
||||
rows.into_iter().for_each(|row| println!("{}", row));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_features(metadata: &Metadata) -> Result<Vec<String>> {
|
||||
let root_package = metadata
|
||||
.root_package()
|
||||
.ok_or_else(|| anyhow!("No root package found"))?;
|
||||
if let Some(resolve) = &metadata.resolve {
|
||||
let root_node = resolve
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|&n| n.id == root_package.id)
|
||||
.ok_or_else(|| anyhow!("Failed to find node for root package"))?;
|
||||
Ok(root_node.features.clone())
|
||||
} else {
|
||||
bail!("Cargo metadata didn't have resolved nodes");
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use rustdoc_types::{Item, Span};
|
||||
use std::fmt;
|
||||
|
||||
/// Component type for components in a [`Path`].
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ComponentType {
|
||||
AssocConst,
|
||||
AssocType,
|
||||
Constant,
|
||||
Crate,
|
||||
Enum,
|
||||
EnumVariant,
|
||||
Function,
|
||||
Method,
|
||||
Module,
|
||||
ReExport,
|
||||
Static,
|
||||
Struct,
|
||||
StructField,
|
||||
Trait,
|
||||
TypeDef,
|
||||
Union,
|
||||
}
|
||||
|
||||
/// Represents one component in a [`Path`].
|
||||
#[derive(Clone, Debug)]
|
||||
struct Component {
|
||||
typ: ComponentType,
|
||||
name: String,
|
||||
span: Option<Span>,
|
||||
}
|
||||
|
||||
impl Component {
|
||||
fn new(typ: ComponentType, name: String, span: Option<Span>) -> Self {
|
||||
Self { typ, name, span }
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the full path to an item being visited by [`Visitor`](crate::visitor::Visitor).
|
||||
///
|
||||
/// This is equivalent to the type path of that item, which has to be re-assembled since
|
||||
/// it is lost in the flat structure of the Rustdoc JSON output.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Path {
|
||||
stack: Vec<Component>,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn new(crate_name: &str) -> Self {
|
||||
Self {
|
||||
stack: vec![Component::new(
|
||||
ComponentType::Crate,
|
||||
crate_name.into(),
|
||||
None,
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, typ: ComponentType, item: &Item) {
|
||||
self.push_raw(typ, item.name.as_ref().expect("name"), item.span.as_ref());
|
||||
}
|
||||
|
||||
pub fn push_raw(&mut self, typ: ComponentType, name: &str, span: Option<&Span>) {
|
||||
self.stack
|
||||
.push(Component::new(typ, name.into(), span.cloned()));
|
||||
}
|
||||
|
||||
/// Returns the span (file + beginning and end positions) of the last [`Component`] in the stack.
|
||||
pub fn last_span(&self) -> Option<&Span> {
|
||||
self.stack.last().and_then(|c| c.span.as_ref())
|
||||
}
|
||||
|
||||
/// Returns the [`ComponentType`] of the last [`Component`] in the path.
|
||||
pub fn last_typ(&self) -> Option<ComponentType> {
|
||||
self.stack.last().map(|c| c.typ)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Path {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let names: Vec<&str> = self
|
||||
.stack
|
||||
.iter()
|
||||
.map(|component| component.name.as_str())
|
||||
.collect();
|
||||
write!(f, "{}", names.join("::"))
|
||||
}
|
||||
}
|
|
@ -1,579 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::{ErrorLocation, ValidationError};
|
||||
use crate::here;
|
||||
use crate::path::{ComponentType, Path};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use rustdoc_types::{
|
||||
Crate, FnDecl, GenericArgs, GenericBound, GenericParamDef, GenericParamDefKind, Generics, Id,
|
||||
Item, ItemEnum, ItemSummary, Struct, Term, Trait, Type, Union, Variant, Visibility,
|
||||
WherePredicate,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use tracing::debug;
|
||||
use tracing_attributes::instrument;
|
||||
|
||||
macro_rules! unstable_rust_feature {
|
||||
($name:expr, $documentation_uri:expr) => {
|
||||
panic!(
|
||||
"unstable Rust feature '{}' (see {}) is not supported by cargo-check-external-types",
|
||||
$name, $documentation_uri
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum VisibilityCheck {
|
||||
/// Check to make sure the item is public before visiting it
|
||||
Default,
|
||||
/// Assume the item is public and examine it.
|
||||
/// This is useful for visiting private items that are publically re-exported
|
||||
AssumePublic,
|
||||
}
|
||||
|
||||
/// Visits all items in the Rustdoc JSON output to discover external types in public APIs
|
||||
/// and track them as validation errors if the [`Config`] doesn't allow them.
|
||||
pub struct Visitor {
|
||||
config: Config,
|
||||
root_crate_id: u32,
|
||||
root_crate_name: String,
|
||||
index: HashMap<Id, Item>,
|
||||
paths: HashMap<Id, ItemSummary>,
|
||||
errors: RefCell<BTreeSet<ValidationError>>,
|
||||
}
|
||||
|
||||
impl Visitor {
|
||||
pub fn new(config: Config, package: Crate) -> Result<Self> {
|
||||
Ok(Visitor {
|
||||
config,
|
||||
root_crate_id: Self::root_crate_id(&package)?,
|
||||
root_crate_name: Self::root_crate_name(&package)?,
|
||||
index: package.index,
|
||||
paths: package.paths,
|
||||
errors: RefCell::new(BTreeSet::new()),
|
||||
})
|
||||
}
|
||||
|
||||
/// This is the entry point for visiting the entire Rustdoc JSON tree, starting
|
||||
/// from the root module (the only module where `is_crate` is true).
|
||||
pub fn visit_all(self) -> Result<BTreeSet<ValidationError>> {
|
||||
let root_path = Path::new(&self.root_crate_name);
|
||||
let root_module = self
|
||||
.index
|
||||
.values()
|
||||
.filter_map(|item| {
|
||||
if let ItemEnum::Module(module) = &item.inner {
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.find(|module| module.is_crate)
|
||||
.ok_or_else(|| anyhow!("failed to find crate root module"))?;
|
||||
|
||||
for id in &root_module.items {
|
||||
let item = self.item(id).context(here!())?;
|
||||
self.visit_item(&root_path, item, VisibilityCheck::Default)?;
|
||||
}
|
||||
Ok(self.errors.take())
|
||||
}
|
||||
|
||||
/// Returns true if the given item is public. In some cases, this must be determined
|
||||
/// by examining the surrounding context. For example, enum variants are public if the
|
||||
/// enum is public, even if their visibility is set to `Visibility::Default`.
|
||||
fn is_public(path: &Path, item: &Item) -> bool {
|
||||
match item.visibility {
|
||||
Visibility::Public => true,
|
||||
Visibility::Default => match &item.inner {
|
||||
// Enum variants are public if the enum is public
|
||||
ItemEnum::Variant(_) => matches!(path.last_typ(), Some(ComponentType::Enum)),
|
||||
// Struct fields inside of enum variants are public if the enum is public
|
||||
ItemEnum::StructField(_) => {
|
||||
matches!(path.last_typ(), Some(ComponentType::EnumVariant))
|
||||
}
|
||||
// Trait items are public if the trait is public
|
||||
_ => matches!(path.last_typ(), Some(ComponentType::Trait)),
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, item), fields(path = %path, name = ?item.name, id = %item.id.0))]
|
||||
fn visit_item(
|
||||
&self,
|
||||
path: &Path,
|
||||
item: &Item,
|
||||
visibility_check: VisibilityCheck,
|
||||
) -> Result<()> {
|
||||
if visibility_check == VisibilityCheck::Default && !Self::is_public(path, item) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut path = path.clone();
|
||||
match &item.inner {
|
||||
ItemEnum::AssocConst { type_, .. } => {
|
||||
path.push(ComponentType::AssocConst, item);
|
||||
self.visit_type(&path, &ErrorLocation::StructField, type_)
|
||||
.context(here!())?;
|
||||
}
|
||||
ItemEnum::AssocType {
|
||||
bounds,
|
||||
default,
|
||||
generics,
|
||||
} => {
|
||||
path.push(ComponentType::AssocType, item);
|
||||
if let Some(typ) = default {
|
||||
self.visit_type(&path, &ErrorLocation::AssocType, typ).context(here!())?;
|
||||
}
|
||||
self.visit_generic_bounds(&path, bounds).context(here!())?;
|
||||
self.visit_generics(&path, generics).context(here!())?;
|
||||
}
|
||||
ItemEnum::Constant(constant) => {
|
||||
path.push(ComponentType::Constant, item);
|
||||
self.visit_type(&path, &ErrorLocation::Constant, &constant.type_).context(here!())?;
|
||||
}
|
||||
ItemEnum::Enum(enm) => {
|
||||
path.push(ComponentType::Enum, item);
|
||||
self.visit_generics(&path, &enm.generics).context(here!())?;
|
||||
for id in &enm.impls {
|
||||
self.visit_impl(&path, self.item(id).context(here!())?)?;
|
||||
}
|
||||
for id in &enm.variants {
|
||||
self.visit_item(&path, self.item(id).context(here!())?, VisibilityCheck::Default).context(here!())?;
|
||||
}
|
||||
}
|
||||
ItemEnum::ForeignType => unstable_rust_feature!(
|
||||
"extern_types",
|
||||
"https://doc.rust-lang.org/beta/unstable-book/language-features/extern-types.html"
|
||||
),
|
||||
ItemEnum::Function(function) => {
|
||||
path.push(ComponentType::Function, item);
|
||||
self.visit_fn_decl(&path, &function.decl).context(here!())?;
|
||||
self.visit_generics(&path, &function.generics).context(here!())?;
|
||||
}
|
||||
ItemEnum::Import(import) => {
|
||||
if let Some(target_id) = &import.id {
|
||||
if self.in_root_crate(target_id) {
|
||||
// Override the visibility check for re-exported items
|
||||
self.visit_item(
|
||||
&path,
|
||||
self.item(target_id).context(here!())?,
|
||||
VisibilityCheck::AssumePublic
|
||||
).context(here!())?;
|
||||
}
|
||||
path.push_raw(ComponentType::ReExport, &import.name, item.span.as_ref());
|
||||
self.check_external(&path, &ErrorLocation::ReExport, target_id)
|
||||
.context(here!())?;
|
||||
}
|
||||
}
|
||||
ItemEnum::Method(method) => {
|
||||
path.push(ComponentType::Method, item);
|
||||
self.visit_fn_decl(&path, &method.decl).context(here!())?;
|
||||
self.visit_generics(&path, &method.generics).context(here!())?;
|
||||
}
|
||||
ItemEnum::Module(module) => {
|
||||
if !module.is_crate {
|
||||
path.push(ComponentType::Module, item);
|
||||
}
|
||||
for id in &module.items {
|
||||
let module_item = self.item(id).context(here!())?;
|
||||
// Re-exports show up twice in the doc json: once as an `ItemEnum::Import`,
|
||||
// and once as the type as if it were originating from the root crate (but
|
||||
// with a different crate ID). We only want to examine the `ItemEnum::Import`
|
||||
// for re-exports since it includes the correct span where the re-export occurs,
|
||||
// and we don't want to examine the innards of the re-export.
|
||||
if module_item.crate_id == self.root_crate_id {
|
||||
self.visit_item(&path, module_item, VisibilityCheck::Default).context(here!())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemEnum::OpaqueTy(_) => unstable_rust_feature!("type_alias_impl_trait", "https://doc.rust-lang.org/beta/unstable-book/language-features/type-alias-impl-trait.html"),
|
||||
ItemEnum::Static(sttc) => {
|
||||
path.push(ComponentType::Static, item);
|
||||
self.visit_type(&path, &ErrorLocation::Static, &sttc.type_).context(here!())?;
|
||||
}
|
||||
ItemEnum::Struct(strct) => {
|
||||
path.push(ComponentType::Struct, item);
|
||||
self.visit_struct(&path, strct).context(here!())?;
|
||||
}
|
||||
ItemEnum::StructField(typ) => {
|
||||
path.push(ComponentType::StructField, item);
|
||||
self.visit_type(&path, &ErrorLocation::StructField, typ)
|
||||
.context(here!())?;
|
||||
}
|
||||
ItemEnum::Trait(trt) => {
|
||||
path.push(ComponentType::Trait, item);
|
||||
self.visit_trait(&path, trt).context(here!())?;
|
||||
}
|
||||
ItemEnum::Typedef(typedef) => {
|
||||
path.push(ComponentType::TypeDef, item);
|
||||
self.visit_type(&path, &ErrorLocation::TypeDef, &typedef.type_)
|
||||
.context(here!())?;
|
||||
self.visit_generics(&path, &typedef.generics).context(here!())?;
|
||||
}
|
||||
ItemEnum::TraitAlias(_) => unstable_rust_feature!(
|
||||
"trait_alias",
|
||||
"https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html"
|
||||
),
|
||||
ItemEnum::Union(unn) => {
|
||||
path.push(ComponentType::Union, item);
|
||||
self.visit_union(&path, unn).context(here!())?;
|
||||
}
|
||||
ItemEnum::Variant(variant) => {
|
||||
path.push(ComponentType::EnumVariant, item);
|
||||
self.visit_variant(&path, variant).context(here!())?;
|
||||
}
|
||||
ItemEnum::ExternCrate { .. }
|
||||
| ItemEnum::Impl(_)
|
||||
| ItemEnum::Macro(_)
|
||||
| ItemEnum::PrimitiveType(_)
|
||||
| ItemEnum::ProcMacro(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, strct), fields(path = %path))]
|
||||
fn visit_struct(&self, path: &Path, strct: &Struct) -> Result<()> {
|
||||
self.visit_generics(path, &strct.generics)?;
|
||||
for id in &strct.fields {
|
||||
let field = self.item(id).context(here!())?;
|
||||
self.visit_item(path, field, VisibilityCheck::Default)?;
|
||||
}
|
||||
for id in &strct.impls {
|
||||
self.visit_impl(path, self.item(id).context(here!())?)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, unn), fields(path = %path))]
|
||||
fn visit_union(&self, path: &Path, unn: &Union) -> Result<()> {
|
||||
self.visit_generics(path, &unn.generics)?;
|
||||
for id in &unn.fields {
|
||||
let field = self.item(id).context(here!())?;
|
||||
self.visit_item(path, field, VisibilityCheck::Default)?;
|
||||
}
|
||||
for id in &unn.impls {
|
||||
self.visit_impl(path, self.item(id).context(here!())?)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, trt), fields(path = %path))]
|
||||
fn visit_trait(&self, path: &Path, trt: &Trait) -> Result<()> {
|
||||
self.visit_generics(path, &trt.generics)?;
|
||||
self.visit_generic_bounds(path, &trt.bounds)?;
|
||||
for id in &trt.items {
|
||||
let item = self.item(id).context(here!())?;
|
||||
self.visit_item(path, item, VisibilityCheck::Default)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, item), fields(path = %path, id = %item.id.0))]
|
||||
fn visit_impl(&self, path: &Path, item: &Item) -> Result<()> {
|
||||
if let ItemEnum::Impl(imp) = &item.inner {
|
||||
// Ignore blanket implementations
|
||||
if imp.blanket_impl.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
self.visit_generics(path, &imp.generics)?;
|
||||
for id in &imp.items {
|
||||
self.visit_item(
|
||||
path,
|
||||
self.item(id).context(here!())?,
|
||||
VisibilityCheck::Default,
|
||||
)?;
|
||||
}
|
||||
if let Some(trait_) = &imp.trait_ {
|
||||
self.visit_type(path, &ErrorLocation::ImplementedTrait, trait_)
|
||||
.context(here!())?;
|
||||
}
|
||||
} else {
|
||||
unreachable!("should be passed an Impl item");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, decl), fields(path = %path))]
|
||||
fn visit_fn_decl(&self, path: &Path, decl: &FnDecl) -> Result<()> {
|
||||
for (index, (name, typ)) in decl.inputs.iter().enumerate() {
|
||||
if index == 0 && name == "self" {
|
||||
continue;
|
||||
}
|
||||
self.visit_type(path, &ErrorLocation::ArgumentNamed(name.into()), typ)
|
||||
.context(here!())?;
|
||||
}
|
||||
if let Some(output) = &decl.output {
|
||||
self.visit_type(path, &ErrorLocation::ReturnValue, output)
|
||||
.context(here!())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, typ), fields(path = %path))]
|
||||
fn visit_type(&self, path: &Path, what: &ErrorLocation, typ: &Type) -> Result<()> {
|
||||
match typ {
|
||||
Type::ResolvedPath {
|
||||
id,
|
||||
args,
|
||||
param_names,
|
||||
..
|
||||
} => {
|
||||
self.check_external(path, what, id).context(here!())?;
|
||||
if let Some(args) = args {
|
||||
self.visit_generic_args(path, args)?;
|
||||
}
|
||||
self.visit_generic_bounds(path, param_names)?;
|
||||
}
|
||||
Type::Generic(_) => {}
|
||||
Type::Primitive(_) => {}
|
||||
Type::FunctionPointer(fp) => {
|
||||
self.visit_fn_decl(path, &fp.decl)?;
|
||||
self.visit_generic_param_defs(path, &fp.generic_params)?;
|
||||
}
|
||||
Type::Tuple(types) => {
|
||||
for typ in types {
|
||||
self.visit_type(path, &ErrorLocation::EnumTupleEntry, typ)?;
|
||||
}
|
||||
}
|
||||
Type::Slice(typ) => self.visit_type(path, what, typ).context(here!())?,
|
||||
Type::Array { type_, .. } => self.visit_type(path, what, type_).context(here!())?,
|
||||
Type::ImplTrait(impl_trait) => {
|
||||
for bound in impl_trait {
|
||||
match bound {
|
||||
GenericBound::TraitBound {
|
||||
trait_,
|
||||
generic_params,
|
||||
..
|
||||
} => {
|
||||
self.visit_type(path, what, trait_)?;
|
||||
self.visit_generic_param_defs(path, generic_params)?;
|
||||
}
|
||||
GenericBound::Outlives(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Infer => {
|
||||
unimplemented!(
|
||||
"visit_type for Type::Infer: not sure what Rust code triggers this. \
|
||||
If you encounter this, please report it with a link to the code it happens with."
|
||||
)
|
||||
}
|
||||
Type::RawPointer { type_, .. } => {
|
||||
self.visit_type(path, what, type_).context(here!())?
|
||||
}
|
||||
Type::BorrowedRef { type_, .. } => {
|
||||
self.visit_type(path, what, type_).context(here!())?
|
||||
}
|
||||
Type::QualifiedPath {
|
||||
self_type, trait_, ..
|
||||
} => {
|
||||
self.visit_type(path, &ErrorLocation::QualifiedSelfType, self_type)?;
|
||||
self.visit_type(path, &ErrorLocation::QualifiedSelfTypeAsTrait, trait_)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, args), fields(path = %path))]
|
||||
fn visit_generic_args(&self, path: &Path, args: &GenericArgs) -> Result<()> {
|
||||
match args {
|
||||
GenericArgs::AngleBracketed { args, bindings } => {
|
||||
for arg in args {
|
||||
match arg {
|
||||
rustdoc_types::GenericArg::Type(typ) => {
|
||||
self.visit_type(path, &ErrorLocation::GenericArg, typ)?
|
||||
}
|
||||
rustdoc_types::GenericArg::Lifetime(_)
|
||||
| rustdoc_types::GenericArg::Const(_)
|
||||
| rustdoc_types::GenericArg::Infer => {}
|
||||
}
|
||||
}
|
||||
for binding in bindings {
|
||||
match &binding.binding {
|
||||
rustdoc_types::TypeBindingKind::Equality(term) => {
|
||||
if let Term::Type(typ) = term {
|
||||
self.visit_type(path, &ErrorLocation::GenericDefaultBinding, typ)
|
||||
.context(here!())?;
|
||||
}
|
||||
}
|
||||
rustdoc_types::TypeBindingKind::Constraint(bounds) => {
|
||||
self.visit_generic_bounds(path, bounds)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GenericArgs::Parenthesized { inputs, output } => {
|
||||
for input in inputs {
|
||||
self.visit_type(path, &ErrorLocation::ClosureInput, input)
|
||||
.context(here!())?;
|
||||
}
|
||||
if let Some(output) = output {
|
||||
self.visit_type(path, &ErrorLocation::ClosureOutput, output)
|
||||
.context(here!())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, bounds), fields(path = %path))]
|
||||
fn visit_generic_bounds(&self, path: &Path, bounds: &[GenericBound]) -> Result<()> {
|
||||
for bound in bounds {
|
||||
if let GenericBound::TraitBound {
|
||||
trait_,
|
||||
generic_params,
|
||||
..
|
||||
} = bound
|
||||
{
|
||||
self.visit_type(path, &ErrorLocation::TraitBound, trait_)
|
||||
.context(here!())?;
|
||||
self.visit_generic_param_defs(path, generic_params)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, params), fields(path = %path))]
|
||||
fn visit_generic_param_defs(&self, path: &Path, params: &[GenericParamDef]) -> Result<()> {
|
||||
for param in params {
|
||||
match ¶m.kind {
|
||||
GenericParamDefKind::Type {
|
||||
bounds,
|
||||
default,
|
||||
synthetic: _,
|
||||
} => {
|
||||
self.visit_generic_bounds(path, bounds)?;
|
||||
if let Some(typ) = default {
|
||||
self.visit_type(path, &ErrorLocation::GenericDefaultBinding, typ)
|
||||
.context(here!())?;
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Const { type_, .. } => {
|
||||
self.visit_type(path, &ErrorLocation::ConstGeneric, type_)
|
||||
.context(here!())?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, generics), fields(path = %path))]
|
||||
fn visit_generics(&self, path: &Path, generics: &Generics) -> Result<()> {
|
||||
self.visit_generic_param_defs(path, &generics.params)?;
|
||||
for where_pred in &generics.where_predicates {
|
||||
match where_pred {
|
||||
WherePredicate::BoundPredicate {
|
||||
type_,
|
||||
bounds,
|
||||
generic_params,
|
||||
} => {
|
||||
self.visit_type(path, &ErrorLocation::WhereBound, type_)
|
||||
.context(here!())?;
|
||||
self.visit_generic_bounds(path, bounds)?;
|
||||
self.visit_generic_param_defs(path, generic_params)?;
|
||||
}
|
||||
WherePredicate::RegionPredicate { bounds, .. } => {
|
||||
self.visit_generic_bounds(path, bounds)?;
|
||||
}
|
||||
WherePredicate::EqPredicate { lhs, .. } => {
|
||||
self.visit_type(path, &ErrorLocation::WhereBound, lhs)
|
||||
.context(here!())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, path, variant), fields(path = %path))]
|
||||
fn visit_variant(&self, path: &Path, variant: &Variant) -> Result<()> {
|
||||
match variant {
|
||||
Variant::Plain => {}
|
||||
Variant::Tuple(types) => {
|
||||
for typ in types {
|
||||
self.visit_type(path, &ErrorLocation::EnumTupleEntry, typ)?;
|
||||
}
|
||||
}
|
||||
Variant::Struct(ids) => {
|
||||
for id in ids {
|
||||
self.visit_item(
|
||||
path,
|
||||
self.item(id).context(here!())?,
|
||||
VisibilityCheck::Default,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_external(&self, path: &Path, what: &ErrorLocation, id: &Id) -> Result<()> {
|
||||
if let Ok(type_name) = self.type_name(id) {
|
||||
if !self.config.allows_type(&self.root_crate_name, &type_name) {
|
||||
self.add_error(ValidationError::unapproved_external_type_ref(
|
||||
self.type_name(id)?,
|
||||
what,
|
||||
path.to_string(),
|
||||
path.last_span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
// Crates like `pin_project` do some shenanigans to create and reference types that don't end up
|
||||
// in the doc index, but that should only happen within the root crate.
|
||||
else if !id.0.starts_with(&format!("{}:", self.root_crate_id)) {
|
||||
unreachable!("A type is referencing another type that is not in the index, and that type is from another crate.");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_error(&self, error: ValidationError) {
|
||||
debug!("detected error {:?}", error);
|
||||
self.errors.borrow_mut().insert(error);
|
||||
}
|
||||
|
||||
fn item(&self, id: &Id) -> Result<&Item> {
|
||||
self.index
|
||||
.get(id)
|
||||
.ok_or_else(|| anyhow!("Failed to find item in index for ID {:?}", id))
|
||||
.context(here!())
|
||||
}
|
||||
|
||||
fn item_summary(&self, id: &Id) -> Option<&ItemSummary> {
|
||||
self.paths.get(id)
|
||||
}
|
||||
|
||||
fn type_name(&self, id: &Id) -> Result<String> {
|
||||
Ok(self.item_summary(id).context(here!())?.path.join("::"))
|
||||
}
|
||||
|
||||
fn root_crate_id(package: &Crate) -> Result<u32> {
|
||||
Ok(Self::root(package)?.crate_id)
|
||||
}
|
||||
|
||||
/// Returns true if the given `id` belongs to the root crate
|
||||
fn in_root_crate(&self, id: &Id) -> bool {
|
||||
id.0.starts_with(&format!("{}:", self.root_crate_id))
|
||||
}
|
||||
|
||||
fn root_crate_name(package: &Crate) -> Result<String> {
|
||||
Ok(Self::root(package)?
|
||||
.name
|
||||
.as_ref()
|
||||
.expect("root should always have a name")
|
||||
.clone())
|
||||
}
|
||||
|
||||
fn root(package: &Crate) -> Result<&Item> {
|
||||
package
|
||||
.index
|
||||
.get(&package.root)
|
||||
.ok_or_else(|| anyhow!("root not found in index"))
|
||||
.context(here!())
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Cargo.lock
|
|
@ -1,2 +0,0 @@
|
|||
[workspace]
|
||||
members = ["external-lib", "test-crate", "test-reexports-crate"]
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "external-lib"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
//! This crate exports a bunch of types for testing cargo-check-external-types against `test-crate`
|
||||
|
||||
pub struct SomeStruct;
|
||||
pub struct SomeOtherStruct;
|
||||
|
||||
pub trait SimpleTrait {
|
||||
fn something(&self) -> u32;
|
||||
}
|
||||
|
||||
impl SimpleTrait for () {
|
||||
fn something(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SimpleGenericTrait<T> {
|
||||
fn something(&self, thing: T) -> u32;
|
||||
}
|
||||
|
||||
pub trait AssociatedGenericTrait {
|
||||
type Input;
|
||||
type Output;
|
||||
type Error;
|
||||
|
||||
fn something(&self, input: Self::Input) -> Self::Output;
|
||||
|
||||
fn something_result(&self, input: Self::Input) -> Result<Self::Output, Self::Error>;
|
||||
}
|
||||
|
||||
pub struct SimpleNewType(pub u32);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ReprCType {
|
||||
i: i32,
|
||||
f: f32,
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "test-crate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
external-lib = { path = "../external-lib" }
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#![feature(generic_associated_types)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
//! This crate is used to test the cargo-check-external-types by exercising the all possible
|
||||
//! exposure of external types in a public API.
|
||||
|
||||
pub mod test_union;
|
||||
|
||||
use external_lib::{
|
||||
AssociatedGenericTrait,
|
||||
SimpleNewType,
|
||||
SimpleTrait,
|
||||
SomeOtherStruct,
|
||||
SomeStruct,
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
|
||||
};
|
||||
|
||||
pub struct LocalStruct;
|
||||
|
||||
pub fn fn_with_local_struct(_local: LocalStruct) -> LocalStruct {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn not_pub_external_in_fn_input(_one: &SomeStruct, _two: impl SimpleTrait) {}
|
||||
|
||||
pub fn external_in_fn_input(_one: &SomeStruct, _two: impl SimpleTrait) {}
|
||||
|
||||
fn not_pub_external_in_fn_output() -> SomeStruct {
|
||||
unimplemented!()
|
||||
}
|
||||
pub fn external_in_fn_output() -> SomeStruct {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn external_opaque_type_in_output() -> impl SimpleTrait {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn not_pub_external_in_fn_output_generic() -> Option<SomeStruct> {
|
||||
unimplemented!()
|
||||
}
|
||||
pub fn external_in_fn_output_generic() -> Option<SomeStruct> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Try to trick cargo-check-external-types here by putting something in a private module and re-exporting it
|
||||
mod private_module {
|
||||
use external_lib::SomeStruct;
|
||||
|
||||
pub fn something(_one: &SomeStruct) {}
|
||||
}
|
||||
pub use private_module::something;
|
||||
|
||||
pub struct StructWithExternalFields {
|
||||
pub field: SomeStruct,
|
||||
pub optional_field: Option<SomeStruct>,
|
||||
}
|
||||
|
||||
impl StructWithExternalFields {
|
||||
pub fn new(_field: impl Into<SomeStruct>, _optional_field: Option<SomeOtherStruct>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TraitReferencingExternals {
|
||||
fn something(&self, a: SomeStruct) -> LocalStruct;
|
||||
fn optional_something(&self, a: Option<SomeStruct>) -> LocalStruct;
|
||||
fn otherthing(&self) -> SomeStruct;
|
||||
fn optional_otherthing(&self) -> Option<SomeStruct>;
|
||||
}
|
||||
|
||||
pub enum EnumWithExternals<T = SomeStruct> {
|
||||
NormalTuple(LocalStruct),
|
||||
NormalStruct {
|
||||
v: LocalStruct,
|
||||
},
|
||||
TupleEnum(SomeStruct, Box<dyn SimpleTrait>),
|
||||
StructEnum {
|
||||
some_struct: SomeStruct,
|
||||
simple_trait: Box<dyn SimpleTrait>,
|
||||
},
|
||||
GenericTupleEnum(T),
|
||||
GenericStructEnum {
|
||||
t: T,
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> EnumWithExternals<T> {
|
||||
pub fn thing(_t: LocalStruct) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
pub fn another_thing<S: SimpleTrait>(_s: S) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub static SOME_STRUCT: SomeStruct = SomeStruct;
|
||||
pub const SOME_CONST: SomeStruct = SomeStruct;
|
||||
|
||||
pub mod some_pub_mod {
|
||||
use external_lib::SomeStruct;
|
||||
|
||||
pub static OPTIONAL_STRUCT: Option<SomeStruct> = None;
|
||||
pub const OPTIONAL_CONST: Option<SomeStruct> = None;
|
||||
}
|
||||
|
||||
pub type NotExternalReferencing = u32;
|
||||
pub type ExternalReferencingTypedef = SomeStruct;
|
||||
pub type OptionalExternalReferencingTypedef = Option<SomeStruct>;
|
||||
pub type DynExternalReferencingTypedef = Box<dyn SimpleTrait>;
|
||||
pub type ExternalReferencingRawPtr = *const SomeStruct;
|
||||
|
||||
pub fn fn_with_external_trait_bounds<I, O, E, T>(_thing: T)
|
||||
where
|
||||
I: Into<SomeStruct>,
|
||||
O: Into<SomeOtherStruct>,
|
||||
E: std::error::Error,
|
||||
T: AssociatedGenericTrait<Input = I, Output = O, Error = E>,
|
||||
{
|
||||
}
|
||||
|
||||
pub trait SomeTraitWithExternalDefaultTypes {
|
||||
type Thing: SimpleTrait;
|
||||
type OtherThing: AssociatedGenericTrait<
|
||||
Input = SomeStruct,
|
||||
Output = u32,
|
||||
Error = SomeOtherStruct,
|
||||
>;
|
||||
|
||||
fn something(&self, input: Self::Thing) -> Self::OtherThing;
|
||||
}
|
||||
|
||||
pub trait SomeTraitWithGenericAssociatedType {
|
||||
type MyGAT<T>
|
||||
where
|
||||
T: SimpleTrait;
|
||||
|
||||
fn some_fn<T: SimpleTrait>(&self, thing: Self::MyGAT<T>);
|
||||
}
|
||||
|
||||
pub struct AssocConstStruct;
|
||||
|
||||
impl AssocConstStruct {
|
||||
pub const SOME_CONST: u32 = 5;
|
||||
|
||||
pub const OTHER_CONST: SimpleNewType = SimpleNewType(5);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use external_lib::{ReprCType, SimpleTrait};
|
||||
|
||||
#[repr(C)]
|
||||
pub union SimpleUnion {
|
||||
pub repr_c: ReprCType,
|
||||
pub something_else: u64,
|
||||
}
|
||||
|
||||
impl SimpleUnion {
|
||||
pub fn repr_c(&self) -> &ReprCType {
|
||||
&self.repr_c
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union GenericUnion<T: Copy + SimpleTrait> {
|
||||
pub repr_c: T,
|
||||
pub something_else: u64,
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "test-reexports-crate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
external-lib = { path = "../external-lib" }
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
pub use external_lib::AssociatedGenericTrait;
|
||||
pub use external_lib::ReprCType;
|
||||
pub use external_lib::SimpleTrait;
|
||||
|
||||
pub mod Something {
|
||||
pub use external_lib::SimpleGenericTrait;
|
||||
pub use external_lib::SimpleNewType;
|
||||
}
|
||||
|
||||
pub use external_lib::SomeOtherStruct;
|
||||
pub use external_lib::SomeStruct;
|
|
@ -1,39 +0,0 @@
|
|||
error: Unapproved external type `external_lib::AssociatedGenericTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:125:1
|
||||
|
|
||||
125 | pub fn fn_with_external_trait_bounds<I, O, E, T>(_thing: T)
|
||||
| ...
|
||||
132 | }␊
|
||||
| ^
|
||||
|
|
||||
= in trait bound of `test_crate::fn_with_external_trait_bounds`
|
||||
|
||||
error: Unapproved external type `external_lib::AssociatedGenericTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:136:5
|
||||
|
|
||||
136 | type OtherThing: AssociatedGenericTrait<
|
||||
| ...
|
||||
140 | >;␊
|
||||
| ^^
|
||||
|
|
||||
= in trait bound of `test_crate::SomeTraitWithExternalDefaultTypes::OtherThing`
|
||||
|
||||
error: Unapproved external type `external_lib::ReprCType` referenced in public API
|
||||
--> test-crate/src/test_union.rs:10:5
|
||||
|
|
||||
10 | pub repr_c: ReprCType,
|
||||
| ^-------------------^
|
||||
|
|
||||
= in struct field of `test_crate::test_union::SimpleUnion::repr_c`
|
||||
|
||||
error: Unapproved external type `external_lib::ReprCType` referenced in public API
|
||||
--> test-crate/src/test_union.rs:15:5
|
||||
|
|
||||
15 | pub fn repr_c(&self) -> &ReprCType {
|
||||
| ...
|
||||
17 | }␊
|
||||
| ^
|
||||
|
|
||||
= in return value of `test_crate::test_union::SimpleUnion::repr_c`
|
||||
|
||||
4 errors emitted
|
|
@ -1,6 +0,0 @@
|
|||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
allowed_external_types = [
|
||||
"external_lib::S*",
|
||||
]
|
|
@ -1,369 +0,0 @@
|
|||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:38:1
|
||||
|
|
||||
38 | pub fn external_in_fn_input(_one: &SomeStruct, _two: impl SimpleTrait) {}
|
||||
| ^-----------------------------------------------------------------------^
|
||||
|
|
||||
= in argument named `_two` of `test_crate::external_in_fn_input`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:38:1
|
||||
|
|
||||
38 | pub fn external_in_fn_input(_one: &SomeStruct, _two: impl SimpleTrait) {}
|
||||
| ^-----------------------------------------------------------------------^
|
||||
|
|
||||
= in trait bound of `test_crate::external_in_fn_input`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:38:1
|
||||
|
|
||||
38 | pub fn external_in_fn_input(_one: &SomeStruct, _two: impl SimpleTrait) {}
|
||||
| ^-----------------------------------------------------------------------^
|
||||
|
|
||||
= in argument named `_one` of `test_crate::external_in_fn_input`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:43:1
|
||||
|
|
||||
43 | pub fn external_in_fn_output() -> SomeStruct {
|
||||
| ...
|
||||
45 | }␊
|
||||
| ^
|
||||
|
|
||||
= in return value of `test_crate::external_in_fn_output`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:47:1
|
||||
|
|
||||
47 | pub fn external_opaque_type_in_output() -> impl SimpleTrait {
|
||||
| ...
|
||||
49 | }␊
|
||||
| ^
|
||||
|
|
||||
= in return value of `test_crate::external_opaque_type_in_output`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:54:1
|
||||
|
|
||||
54 | pub fn external_in_fn_output_generic() -> Option<SomeStruct> {
|
||||
| ...
|
||||
56 | }␊
|
||||
| ^
|
||||
|
|
||||
= in generic arg of `test_crate::external_in_fn_output_generic`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:62:5
|
||||
|
|
||||
62 | pub fn something(_one: &SomeStruct) {}
|
||||
| ^------------------------------------^
|
||||
|
|
||||
= in argument named `_one` of `test_crate::something`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:67:5
|
||||
|
|
||||
67 | pub field: SomeStruct,
|
||||
| ^-------------------^
|
||||
|
|
||||
= in struct field of `test_crate::StructWithExternalFields::field`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:68:5
|
||||
|
|
||||
68 | pub optional_field: Option<SomeStruct>,
|
||||
| ^------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::StructWithExternalFields::optional_field`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeOtherStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:72:5
|
||||
|
|
||||
72 | pub fn new(_field: impl Into<SomeStruct>, _optional_field: Option<SomeOtherStruct>) -> Self {
|
||||
| ...
|
||||
74 | }␊
|
||||
| ^
|
||||
|
|
||||
= in generic arg of `test_crate::StructWithExternalFields::new`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:72:5
|
||||
|
|
||||
72 | pub fn new(_field: impl Into<SomeStruct>, _optional_field: Option<SomeOtherStruct>) -> Self {
|
||||
| ...
|
||||
74 | }␊
|
||||
| ^
|
||||
|
|
||||
= in generic arg of `test_crate::StructWithExternalFields::new`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:78:5
|
||||
|
|
||||
78 | fn something(&self, a: SomeStruct) -> LocalStruct;
|
||||
| ^------------------------------------------------^
|
||||
|
|
||||
= in argument named `a` of `test_crate::TraitReferencingExternals::something`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:79:5
|
||||
|
|
||||
79 | fn optional_something(&self, a: Option<SomeStruct>) -> LocalStruct;
|
||||
| ^-----------------------------------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::TraitReferencingExternals::optional_something`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:80:5
|
||||
|
|
||||
80 | fn otherthing(&self) -> SomeStruct;
|
||||
| ^---------------------------------^
|
||||
|
|
||||
= in return value of `test_crate::TraitReferencingExternals::otherthing`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:81:5
|
||||
|
|
||||
81 | fn optional_otherthing(&self) -> Option<SomeStruct>;
|
||||
| ^--------------------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::TraitReferencingExternals::optional_otherthing`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:84:1
|
||||
|
|
||||
84 | pub enum EnumWithExternals<T = SomeStruct> {
|
||||
| ...
|
||||
98 | }␊
|
||||
| ^
|
||||
|
|
||||
= in generic default binding of `test_crate::EnumWithExternals`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:89:5
|
||||
|
|
||||
89 | TupleEnum(SomeStruct, Box<dyn SimpleTrait>),
|
||||
| ^-----------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::EnumWithExternals::TupleEnum`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:89:5
|
||||
|
|
||||
89 | TupleEnum(SomeStruct, Box<dyn SimpleTrait>),
|
||||
| ^-----------------------------------------^
|
||||
|
|
||||
= in enum tuple entry of `test_crate::EnumWithExternals::TupleEnum`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:91:9
|
||||
|
|
||||
91 | some_struct: SomeStruct,
|
||||
| ^---------------------^
|
||||
|
|
||||
= in struct field of `test_crate::EnumWithExternals::StructEnum::some_struct`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:92:9
|
||||
|
|
||||
92 | simple_trait: Box<dyn SimpleTrait>,
|
||||
| ^--------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::EnumWithExternals::StructEnum::simple_trait`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:104:5
|
||||
|
|
||||
104 | pub fn another_thing<S: SimpleTrait>(_s: S) -> Self {
|
||||
| ...
|
||||
106 | }␊
|
||||
| ^
|
||||
|
|
||||
= in trait bound of `test_crate::EnumWithExternals::another_thing`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:109:1
|
||||
|
|
||||
109 | pub static SOME_STRUCT: SomeStruct = SomeStruct;
|
||||
| ^----------------------------------------------^
|
||||
|
|
||||
= in static value `test_crate::SOME_STRUCT`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:110:1
|
||||
|
|
||||
110 | pub const SOME_CONST: SomeStruct = SomeStruct;
|
||||
| ^--------------------------------------------^
|
||||
|
|
||||
= in constant `test_crate::SOME_CONST`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:115:5
|
||||
|
|
||||
115 | pub static OPTIONAL_STRUCT: Option<SomeStruct> = None;
|
||||
| ^----------------------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::some_pub_mod::OPTIONAL_STRUCT`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:116:5
|
||||
|
|
||||
116 | pub const OPTIONAL_CONST: Option<SomeStruct> = None;
|
||||
| ^--------------------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::some_pub_mod::OPTIONAL_CONST`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:120:1
|
||||
|
|
||||
120 | pub type ExternalReferencingTypedef = SomeStruct;
|
||||
| ^-----------------------------------------------^
|
||||
|
|
||||
= in typedef type of `test_crate::ExternalReferencingTypedef`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:121:1
|
||||
|
|
||||
121 | pub type OptionalExternalReferencingTypedef = Option<SomeStruct>;
|
||||
| ^---------------------------------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::OptionalExternalReferencingTypedef`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:122:1
|
||||
|
|
||||
122 | pub type DynExternalReferencingTypedef = Box<dyn SimpleTrait>;
|
||||
| ^------------------------------------------------------------^
|
||||
|
|
||||
= in generic arg of `test_crate::DynExternalReferencingTypedef`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:123:1
|
||||
|
|
||||
123 | pub type ExternalReferencingRawPtr = *const SomeStruct;
|
||||
| ^-----------------------------------------------------^
|
||||
|
|
||||
= in typedef type of `test_crate::ExternalReferencingRawPtr`
|
||||
|
||||
error: Unapproved external type `external_lib::AssociatedGenericTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:125:1
|
||||
|
|
||||
125 | pub fn fn_with_external_trait_bounds<I, O, E, T>(_thing: T)
|
||||
| ...
|
||||
132 | }␊
|
||||
| ^
|
||||
|
|
||||
= in trait bound of `test_crate::fn_with_external_trait_bounds`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeOtherStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:125:1
|
||||
|
|
||||
125 | pub fn fn_with_external_trait_bounds<I, O, E, T>(_thing: T)
|
||||
| ...
|
||||
132 | }␊
|
||||
| ^
|
||||
|
|
||||
= in generic arg of `test_crate::fn_with_external_trait_bounds`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:125:1
|
||||
|
|
||||
125 | pub fn fn_with_external_trait_bounds<I, O, E, T>(_thing: T)
|
||||
| ...
|
||||
132 | }␊
|
||||
| ^
|
||||
|
|
||||
= in generic arg of `test_crate::fn_with_external_trait_bounds`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:135:5
|
||||
|
|
||||
135 | type Thing: SimpleTrait;
|
||||
| ^----------------------^
|
||||
|
|
||||
= in trait bound of `test_crate::SomeTraitWithExternalDefaultTypes::Thing`
|
||||
|
||||
error: Unapproved external type `external_lib::AssociatedGenericTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:136:5
|
||||
|
|
||||
136 | type OtherThing: AssociatedGenericTrait<
|
||||
| ...
|
||||
140 | >;␊
|
||||
| ^^
|
||||
|
|
||||
= in trait bound of `test_crate::SomeTraitWithExternalDefaultTypes::OtherThing`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeOtherStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:136:5
|
||||
|
|
||||
136 | type OtherThing: AssociatedGenericTrait<
|
||||
| ...
|
||||
140 | >;␊
|
||||
| ^^
|
||||
|
|
||||
= in generic default binding of `test_crate::SomeTraitWithExternalDefaultTypes::OtherThing`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-crate/src/lib.rs:136:5
|
||||
|
|
||||
136 | type OtherThing: AssociatedGenericTrait<
|
||||
| ...
|
||||
140 | >;␊
|
||||
| ^^
|
||||
|
|
||||
= in generic default binding of `test_crate::SomeTraitWithExternalDefaultTypes::OtherThing`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:146:5
|
||||
|
|
||||
146 | type MyGAT<T>
|
||||
| ...
|
||||
148 | T: SimpleTrait;␊
|
||||
| ^-----------------^
|
||||
|
|
||||
= in trait bound of `test_crate::SomeTraitWithGenericAssociatedType::MyGAT`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/lib.rs:150:5
|
||||
|
|
||||
150 | fn some_fn<T: SimpleTrait>(&self, thing: Self::MyGAT<T>);
|
||||
| ^-------------------------------------------------------^
|
||||
|
|
||||
= in trait bound of `test_crate::SomeTraitWithGenericAssociatedType::some_fn`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleNewType` referenced in public API
|
||||
--> test-crate/src/lib.rs:158:5
|
||||
|
|
||||
158 | pub const OTHER_CONST: SimpleNewType = SimpleNewType(5);
|
||||
| ^------------------------------------------------------^
|
||||
|
|
||||
= in struct field of `test_crate::AssocConstStruct::OTHER_CONST`
|
||||
|
||||
error: Unapproved external type `external_lib::ReprCType` referenced in public API
|
||||
--> test-crate/src/test_union.rs:10:5
|
||||
|
|
||||
10 | pub repr_c: ReprCType,
|
||||
| ^-------------------^
|
||||
|
|
||||
= in struct field of `test_crate::test_union::SimpleUnion::repr_c`
|
||||
|
||||
error: Unapproved external type `external_lib::ReprCType` referenced in public API
|
||||
--> test-crate/src/test_union.rs:15:5
|
||||
|
|
||||
15 | pub fn repr_c(&self) -> &ReprCType {
|
||||
| ...
|
||||
17 | }␊
|
||||
| ^
|
||||
|
|
||||
= in return value of `test_crate::test_union::SimpleUnion::repr_c`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-crate/src/test_union.rs:21:1
|
||||
|
|
||||
21 | pub union GenericUnion<T: Copy + SimpleTrait> {
|
||||
| ...
|
||||
24 | }␊
|
||||
| ^
|
||||
|
|
||||
= in trait bound of `test_crate::test_union::GenericUnion`
|
||||
|
||||
42 errors emitted
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use cargo_check_external_types::cargo::handle_failure;
|
||||
use pretty_assertions::assert_str_eq;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Output;
|
||||
use test_bin::get_test_bin;
|
||||
|
||||
/// Returns (stdout, stderr)
|
||||
pub fn output_text(output: &Output) -> (String, String) {
|
||||
(
|
||||
String::from_utf8_lossy(&output.stdout).to_string(),
|
||||
String::from_utf8_lossy(&output.stderr).to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
fn run_with_args(in_path: impl AsRef<Path>, args: &[&str]) -> String {
|
||||
let mut cmd = get_test_bin("cargo-check-external-types");
|
||||
cmd.current_dir(in_path.as_ref());
|
||||
cmd.arg("check-external-types");
|
||||
for &arg in args {
|
||||
cmd.arg(arg);
|
||||
}
|
||||
let output = cmd
|
||||
.output()
|
||||
.expect("failed to start cargo-check-external-types");
|
||||
match output.status.code() {
|
||||
Some(1) => { /* expected */ }
|
||||
_ => handle_failure("cargo-check-external-types", &output).unwrap(),
|
||||
}
|
||||
let (stdout, _) = output_text(&output);
|
||||
stdout
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_default_config() {
|
||||
let expected_output = fs::read_to_string("tests/default-config-expected-output.txt").unwrap();
|
||||
let actual_output = run_with_args("test-workspace/test-crate", &[]);
|
||||
assert_str_eq!(expected_output, actual_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_some_allowed_types() {
|
||||
let expected_output = fs::read_to_string("tests/allow-some-types-expected-output.txt").unwrap();
|
||||
let actual_output = run_with_args(
|
||||
"test-workspace/test-crate",
|
||||
&["--config", "../../tests/allow-some-types.toml"],
|
||||
);
|
||||
assert_str_eq!(expected_output, actual_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_output_format_markdown_table() {
|
||||
let expected_output =
|
||||
fs::read_to_string("tests/output-format-markdown-table-expected-output.md").unwrap();
|
||||
let actual_output = run_with_args(
|
||||
"test-workspace/test-crate",
|
||||
&["--output-format", "markdown-table"],
|
||||
);
|
||||
assert_str_eq!(expected_output, actual_output);
|
||||
}
|
||||
|
||||
// Make sure that the visitor doesn't attempt to visit the inner items of re-exported external types.
|
||||
// Rustdoc doesn't include these inner items in its JSON output, which leads to obtuse crashes if they're
|
||||
// referenced. It's also just the wrong behavior to look into the type being re-exported, since if it's
|
||||
// approved, then it doesn't matter what it referenced. If it's not approved, then the re-export itself
|
||||
// is the violation.
|
||||
#[test]
|
||||
fn test_reexports() {
|
||||
let expected_output = fs::read_to_string("tests/test-reexports-expected-output.md").unwrap();
|
||||
let actual_output = run_with_args("test-workspace/test-reexports-crate", &[]);
|
||||
assert_str_eq!(expected_output, actual_output);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
| Crate | Type | Used In |
|
||||
| --- | --- | --- |
|
||||
| external_lib | external_lib::AssociatedGenericTrait | test-crate/src/lib.rs:125:0 |
|
||||
| external_lib | external_lib::AssociatedGenericTrait | test-crate/src/lib.rs:136:4 |
|
||||
| external_lib | external_lib::ReprCType | test-crate/src/test_union.rs:10:4 |
|
||||
| external_lib | external_lib::ReprCType | test-crate/src/test_union.rs:15:4 |
|
||||
| external_lib | external_lib::SimpleNewType | test-crate/src/lib.rs:158:4 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:104:4 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:122:0 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:135:4 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:146:4 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:150:4 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:38:0 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:38:0 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:47:0 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:89:4 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:92:8 |
|
||||
| external_lib | external_lib::SimpleTrait | test-crate/src/test_union.rs:21:0 |
|
||||
| external_lib | external_lib::SomeOtherStruct | test-crate/src/lib.rs:125:0 |
|
||||
| external_lib | external_lib::SomeOtherStruct | test-crate/src/lib.rs:136:4 |
|
||||
| external_lib | external_lib::SomeOtherStruct | test-crate/src/lib.rs:72:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:109:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:110:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:115:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:116:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:120:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:121:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:123:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:125:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:136:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:38:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:43:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:54:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:62:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:67:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:68:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:72:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:78:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:79:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:80:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:81:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:84:0 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:89:4 |
|
||||
| external_lib | external_lib::SomeStruct | test-crate/src/lib.rs:91:8 |
|
|
@ -1,57 +0,0 @@
|
|||
error: Unapproved external type `external_lib::AssociatedGenericTrait` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:6:1
|
||||
|
|
||||
6 | pub use external_lib::AssociatedGenericTrait;
|
||||
| ^-------------------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::AssociatedGenericTrait`
|
||||
|
||||
error: Unapproved external type `external_lib::ReprCType` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:7:1
|
||||
|
|
||||
7 | pub use external_lib::ReprCType;
|
||||
| ^------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::ReprCType`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:8:1
|
||||
|
|
||||
8 | pub use external_lib::SimpleTrait;
|
||||
| ^--------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::SimpleTrait`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleGenericTrait` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:11:5
|
||||
|
|
||||
11 | pub use external_lib::SimpleGenericTrait;
|
||||
| ^---------------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::Something::SimpleGenericTrait`
|
||||
|
||||
error: Unapproved external type `external_lib::SimpleNewType` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:12:5
|
||||
|
|
||||
12 | pub use external_lib::SimpleNewType;
|
||||
| ^----------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::Something::SimpleNewType`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeOtherStruct` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:15:1
|
||||
|
|
||||
15 | pub use external_lib::SomeOtherStruct;
|
||||
| ^------------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::SomeOtherStruct`
|
||||
|
||||
error: Unapproved external type `external_lib::SomeStruct` referenced in public API
|
||||
--> test-reexports-crate/src/lib.rs:16:1
|
||||
|
|
||||
16 | pub use external_lib::SomeStruct;
|
||||
| ^-------------------------------^
|
||||
|
|
||||
= in re-export named `test_reexports_crate::SomeStruct`
|
||||
|
||||
7 errors emitted
|
|
@ -22,7 +22,6 @@ function test_tool {
|
|||
popd &>/dev/null
|
||||
}
|
||||
|
||||
test_tool "tools/cargo-check-external-types" "${RUST_NIGHTLY_VERSION}"
|
||||
test_tool "tools/changelogger" "${RUST_STABLE_VERSION}"
|
||||
test_tool "tools/ci-cdk/canary-runner" "${RUST_STABLE_VERSION}"
|
||||
test_tool "tools/crate-hasher" "${RUST_STABLE_VERSION}"
|
||||
|
|
Loading…
Reference in New Issue