diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 87499be332..8dd43fcc76 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -40,12 +40,12 @@ jobs: run: cargo build --verbose - name: Run tests run: | - cargo test --test non_transitive_graph_tests - cargo test --test call_chain_analysis_tests - cargo test --test control_flow_tests - cargo test --test new_alias_analysis_tests - cargo test --test async_tests - cargo test --test inline_elision_tests + cargo test -p dfpp --test non_transitive_graph_tests + cargo test -p dfpp --test call_chain_analysis_tests + cargo test -p dfpp --test control_flow_tests + cargo test -p dfpp --test new_alias_analysis_tests + cargo test -p dfpp --test async_tests + cargo test -p dfpp --test inline_elision_tests intergration-tests: name: Integration Tests @@ -77,7 +77,7 @@ jobs: cd forge raco pkg install --auto || raco setup forge - name: Run Tests - run: cargo test --test external_annotation_tests + run: cargo test -p dfpp --test external_annotation_tests format-check: name: Format Control @@ -91,8 +91,11 @@ jobs: with: path: ~/.rustup key: ${{ runner.os }}-rust-toolchain-${{ hashFiles('rust-toolchain.toml') }} - - name: Perform Check + - name: Check main repo run: cargo fmt --check + - name: Check properties + run: cargo fmt --check + working-directory: props linting: name: Clippy @@ -116,3 +119,6 @@ jobs: key: ${{ runner.os }}-rust-deps-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} - name: Here come the complaints run: cargo clippy --all -- -D warnings + - name: Complaints about properties + run: cargo clippy --all -- -D warnings + working-directory: props diff --git a/.gitignore b/.gitignore index a3a395ad7e..34bf2360dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target/ +target/ /rust-dfpp-patch @@ -7,4 +7,9 @@ flow-graph.json # Local cargo configuration .cargo/config.toml *.eqs -*.info.json \ No newline at end of file +*.info.json + +props/Cargo.lock + +# Delete this if we want to include a rustfmt configuration +.rustfmt.toml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cfcf06d9a0..31d3a6fbce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,23 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -28,9 +45,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -52,9 +69,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -62,9 +79,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -95,11 +112,35 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "bumpalo" -version = "3.12.2" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byteorder" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "camino" @@ -134,9 +175,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -146,13 +190,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "time 0.1.45", "wasm-bindgen", @@ -161,9 +205,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.19" +version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" dependencies = [ "clap_builder", "clap_derive", @@ -172,9 +216,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" dependencies = [ "anstream", "anstyle", @@ -197,19 +241,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "colorchoice" @@ -219,26 +253,26 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ - "atty", + "is-terminal", "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "console" -version = "0.15.5" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -248,74 +282,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" +name = "dashmap" +version = "5.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" dependencies = [ - "cc", - "codespan-reporting", + "cfg-if", + "hashbrown 0.14.0", + "lock_api", "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", + "parking_lot_core", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.94" +name = "deranged" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +name = "dfcheck" +version = "0.1.0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "anyhow", + "dfgraph", + "dfpp", + "indexical", + "itertools", + "log", + "serde_json", + "simple_logger", ] [[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +name = "dfgraph" +version = "0.1.0" dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", + "indexical", + "internment", + "itertools", + "log", + "serde", ] [[package]] name = "dfpp" version = "0.0.1" dependencies = [ + "anyhow", "camino", "chrono", "clap", - "dialoguer", + "dfgraph", + "dfpp", "dot", "flowistry", "humantime", - "indicatif", + "itertools", "lazy_static", "log", "nom", @@ -324,11 +347,10 @@ dependencies = [ "ordermap", "petgraph", "pretty", - "ringbuffer", "rustc_plugin 0.6.0-nightly-2023-04-12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_utils 0.6.0-nightly-2023-04-12 (registry+https://github.com/rust-lang/crates.io-index)", "serde", - "serde-lexpr", + "serde_bare", "serde_json", "serial_test", "simple_logger", @@ -336,6 +358,20 @@ dependencies = [ "trait_enum", ] +[[package]] +name = "dfpp-explorer" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "dfpp", + "dialoguer", + "indicatif", + "petgraph", + "ringbuffer", + "serde-lexpr", +] + [[package]] name = "dialoguer" version = "0.10.4" @@ -354,17 +390,29 @@ name = "dot" version = "0.1.4-dev" source = "git+https://github.com/JustusAdam/dot-rust?rev=ff2b42ceda98c639c8ea3cbfc56b83d6e06e8106#ff2b42ceda98c639c8ea3cbfc56b83d6e06e8106" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -383,12 +431,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "fixedbitset" @@ -415,6 +460,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "749cff877dc1af878a0b31a41dd221a753634401ea0ef2f87b62d3171522485a" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.28" @@ -501,11 +552,40 @@ dependencies = [ "thread_local", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "heck" @@ -524,9 +604,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "humantime" @@ -536,9 +616,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -550,33 +630,52 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", +] + +[[package]] +name = "index_vec" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74086667896a940438f2118212f313abba4aff3831fef6f4b17d02add5c8bb60" + +[[package]] +name = "indexical" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89754b11302aa9343b63a6f93ff37b406e28f06364711f26eb09a1cdd6456037" +dependencies = [ + "bitvec", + "fxhash", + "index_vec", + "splitmut", + "take_mut", ] [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg", - "hashbrown", + "equivalent", + "hashbrown 0.14.0", ] [[package]] name = "indicatif" -version = "0.17.3" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" dependencies = [ "console", + "instant", "number_prefix", - "portable-atomic 0.3.20", + "portable-atomic", "unicode-width", ] @@ -589,6 +688,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "internment" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161079c3ad892faa215fcfcf3fd7a6a3c9288df2b06a2c2bad7fbfad4f01d69d" +dependencies = [ + "hashbrown 0.12.3", + "parking_lot", + "serde", +] + [[package]] name = "intervaltree" version = "0.2.7" @@ -599,39 +709,36 @@ dependencies = [ ] [[package]] -name = "io-lifetimes" -version = "1.0.10" +name = "is-terminal" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "libc", + "hermit-abi 0.3.2", + "rustix", "windows-sys 0.48.0", ] [[package]] -name = "is-terminal" -version = "0.4.7" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", + "either", ] [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.62" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -665,30 +772,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -696,12 +794,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" @@ -717,9 +812,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -736,21 +831,11 @@ dependencies = [ "syn", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -772,9 +857,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "ordermap" @@ -794,22 +879,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.5", ] [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", "indexmap", @@ -817,9 +902,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -829,18 +914,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "portable-atomic" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" -dependencies = [ - "portable-atomic 1.3.1", -] - -[[package]] -name = "portable-atomic" -version = "1.3.1" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbda379e6e462c97ea6afe9f6233619b202bbc4968d7caa6917788d2070a044" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" [[package]] name = "pretty" @@ -856,30 +932,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "redox_syscall" @@ -887,7 +960,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -942,13 +1015,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.38.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" dependencies = [ - "bitflags", + "bitflags 2.4.0", "errno", - "io-lifetimes", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -956,21 +1028,15 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" @@ -983,9 +1049,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.160" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -1000,11 +1066,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_bare" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51c55386eed0f1ae957b091dc2ca8122f287b60c79c774cbe3d5f2b69fded660" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -1013,9 +1088,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -1024,9 +1099,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -1064,31 +1139,37 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "simple_logger" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166fea527c36d9b8a0a88c0c6d4c5077c699d9ffb5cf890b231a3f08c35f3d40" +checksum = "48047e77b528151aaf841a10a9025f9459da80ba820e425ff7eb005708a76dc7" dependencies = [ "atty", "colored", "log", - "time 0.3.11", + "time 0.3.27", "winapi", ] [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "splitmut" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "c85070f382340e8b23a75808e83573ddf65f9ad9143df9573ca37c1ed2ee956a" [[package]] name = "strsim" @@ -1098,35 +1179,38 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.15" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" -version = "3.5.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", + "windows-sys 0.48.0", ] [[package]] @@ -1146,33 +1230,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "time" -version = "0.3.11" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" dependencies = [ + "deranged", "itoa", "libc", "num_threads", + "serde", + "time-core", "time-macros", ] +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + [[package]] name = "time-macros" -version = "0.2.4" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" +dependencies = [ + "time-core", +] [[package]] name = "toml" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -1182,18 +1278,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap", "serde", @@ -1210,21 +1306,21 @@ checksum = "130dd741d3c71f76d031e58caffff3624eaaa2db9bd8c4b05406a71885300fc7" [[package]] name = "typed-arena" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" @@ -1238,17 +1334,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1256,9 +1364,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", @@ -1271,9 +1379,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1281,9 +1389,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", @@ -1294,9 +1402,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "winapi" @@ -1314,15 +1422,6 @@ 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" @@ -1335,22 +1434,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.48.5", ] [[package]] @@ -1368,7 +1452,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -1388,17 +1472,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1409,9 +1493,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -1421,9 +1505,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -1433,9 +1517,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -1445,9 +1529,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -1457,9 +1541,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -1469,9 +1553,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -1481,19 +1565,28 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.1" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zeroize" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 4c8b3ab2dd..c57ce446ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,73 +1,14 @@ -[package] -name = "dfpp" -version = "0.0.1" -edition = "2021" -publish = false -description = "A linter for user-defined privacy properties for Rust code" - -[package.metadata.rust-analyzer] -rustc_private = true - -[dependencies] -#flowistry = { git = "https://github.com/willcrichton/flowistry", rev = "1759ef8" } -#flowistry = { path = "../flowistry/crates/flowistry" } -flowistry = { git = "https://github.com/brownsys/flowistry", rev = "f3b27bb1e06a13c599ea56beca7aa047f7d291e5" } - -#rustc_plugin = { path = "../rustc_plugin/crates/rustc_plugin" } -#rustc_utils = { path = "../rustc_plugin/crates/rustc_utils"} -rustc_utils = "=0.6.0-nightly-2023-04-12" -rustc_plugin = "=0.6.0-nightly-2023-04-12" - -clap = { version = "4", features = ["derive", "cargo", "env"] } -serde = { version = "1", features = ["derive"] } -lazy_static = "1" -ordermap = "0.3" -trait_enum = "0.5" -pretty = "0.11" -nom = "7" -log = "0.4" -simple_logger = "2" -petgraph = "0.6" -num-derive = "0.4" -num-traits = "0.2" - -humantime = "2" -indicatif = "0.17" -serde-lexpr = "0.1" - -#dot = "0.1" -dot = { git = "https://github.com/JustusAdam/dot-rust", rev = "ff2b42ceda98c639c8ea3cbfc56b83d6e06e8106"} -#dot = {path = "../../clones/dot-rust" } - -serde_json = "1" -toml = "0.7" - -dialoguer = { version = "0.10", features = ["history", "fuzzy-select"] } -ringbuffer = "0.13" - -# This is just for pinning this dependency -camino = "= 1.0.9" -serial_test = "2.0.0" - -[build-dependencies] -chrono = "0.4" - -[[bin]] -name = "cargo-dfpp" - -[[bin]] -name = "dfpp" - -[[bin]] -name = "dfpp-explorer" -path = "explorer/main.rs" +[workspace] +members = ["crates/*"] +exclude = ["props", "crates/dfpp/tests", "crates/dfcheck/tests"] +[workspace.dependencies] +indexical = "0.2.2" +serde = "1.0.188" [profile.release] debug = true - [replace] - "rustc_utils:0.6.0-nightly-2023-04-12" = { git = "https://github.com/JustusAdam/rustc_plugin", rev = "344ecb3bc056c641eaf9d06792571b3d81c8eb33" } "rustc_plugin:0.6.0-nightly-2023-04-12" = { git = "https://github.com/JustusAdam/rustc_plugin", rev = "344ecb3bc056c641eaf9d06792571b3d81c8eb33" } \ No newline at end of file diff --git a/crates/dfcheck/Cargo.toml b/crates/dfcheck/Cargo.toml new file mode 100644 index 0000000000..7cd14bafc6 --- /dev/null +++ b/crates/dfcheck/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dfcheck" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +dfgraph = { path = "../dfgraph" } +anyhow = "1.0.72" +log = "0.4" +itertools = "0.11.0" +indexical = { workspace = true } +serde_json = "1" +simple_logger = "2" + +[dev-dependencies] +dfpp = { path = "../dfpp", features = ["test"] } \ No newline at end of file diff --git a/crates/dfcheck/src/context.rs b/crates/dfcheck/src/context.rs new file mode 100644 index 0000000000..857bbfaa5e --- /dev/null +++ b/crates/dfcheck/src/context.rs @@ -0,0 +1,175 @@ +use dfgraph::{ + Annotation, CallSite, Ctrl, DataSink, DataSource, HashMap, Identifier, MarkerAnnotation, + MarkerRefinement, ProgramDescription, +}; + +use indexical::ToIndex; +use itertools::Itertools; + +use super::flows_to::CtrlFlowsTo; + +/// User-defined PDG markers. +pub type Marker = Identifier; + +type MarkerIndex = HashMap>; +type FlowsTo = HashMap; + +/// Data structures to be analyzed by user-defined properties. +#[derive(Debug)] +pub struct Context { + marker_to_ids: MarkerIndex, + desc: ProgramDescription, + flows_to: FlowsTo, +} + +impl Context { + /// Construct a [`Context`] from a [`ProgramDescription`]. + /// + /// This also precomputes some data structures like an index over markers. + pub fn new(desc: ProgramDescription) -> Self { + Context { + marker_to_ids: Self::build_index_on_markers(&desc), + flows_to: Self::build_flows_to(&desc), + desc, + } + } + + fn build_index_on_markers(desc: &ProgramDescription) -> MarkerIndex { + desc.annotations + .iter() + .flat_map(|(id, (annots, _))| { + annots.iter().filter_map(move |annot| match annot { + Annotation::Label(MarkerAnnotation { marker, refinement }) => { + Some((*marker, (*id, refinement.clone()))) + } + _ => None, + }) + }) + .into_group_map() + } + + fn build_flows_to(desc: &ProgramDescription) -> FlowsTo { + desc.controllers + .iter() + .map(|(id, c)| (*id, CtrlFlowsTo::build(c))) + .collect() + } + + /// Returns true if `src` has a data-flow to `sink` in the controller `ctrl_id` + pub fn flows_to(&self, ctrl_id: &Identifier, src: &DataSource, sink: &DataSink) -> bool { + let ctrl_flows = &self.flows_to[ctrl_id]; + ctrl_flows + .flows_to + .row_set(&src.to_index(&ctrl_flows.sources)) + .contains(sink) + } + + /// Returns an iterator over all objects marked with `marker`. + pub fn marked( + &self, + marker: Marker, + ) -> impl Iterator + '_ { + self.marker_to_ids + .get(&marker) + .into_iter() + .flat_map(|v| v.iter()) + } + + /// Returns an iterator over all sinks marked with `marker` out of the provided `dsts`. + pub fn marked_sinks<'a>( + &'a self, + dsts: impl IntoIterator + 'a, + marker: Marker, + ) -> impl Iterator + 'a { + dsts.into_iter().filter(move |dst| match dst { + DataSink::Argument { function, arg_slot } => self + .marker_to_ids + .get(&marker) + .map(|markers| { + markers.iter().any(|(id, refinement)| { + id == &function.function + && (refinement.on_self() + || refinement.on_argument().contains(*arg_slot as u32).unwrap()) + }) + }) + .unwrap_or(false), + _ => false, + }) + } + + /// Returns an iterator over all the call sites marked with `marker` out of the provided `dsts`. + pub fn marked_callsites<'a>( + &'a self, + dsts: impl IntoIterator + 'a, + marker: Marker, + ) -> impl Iterator + 'a { + self.marked_sinks(dsts, marker) + .filter_map(|sink| match sink { + DataSink::Argument { function, .. } => Some(function), + _ => None, + }) + } + + /// Returns an iterator over the data sources within controller `c` that have type `t`. + pub fn srcs_with_type<'a>( + &self, + c: &'a Ctrl, + t: &'a Identifier, + ) -> impl Iterator + 'a { + c.types + .0 + .iter() + .filter_map(move |(src, ids)| ids.contains(t).then_some(src)) + } + + /// Returns the input [`ProgramDescription`]. + pub fn desc(&self) -> &ProgramDescription { + &self.desc + } + + /// Returns all the [`Annotation::OType`]s for a controller `id`. + pub fn otypes(&self, id: &Identifier) -> Vec { + let inner = || -> Option<_> { + self.desc() + .annotations + .get(id)? + .0 + .iter() + .filter_map(|annot| match annot { + Annotation::OType(ids) => Some(ids.clone()), + _ => None, + }) + .next() + }; + inner().unwrap_or_default() + } + + /// Returns true if `id` identifies a function with name `name`. + pub fn is_function(&self, id: Identifier, name: &str) -> bool { + match id.as_str().split_once('_') { + Some((id_name, _)) => id_name == name, + None => false, + } + } +} + +#[test] +fn test_context() { + let ctx = crate::test_utils::test_ctx(); + let input = Marker::new_intern("input"); + let sink = Marker::new_intern("sink"); + assert!(ctx + .marked(input) + .any(|(id, _)| id.as_str().starts_with("Foo"))); + + let desc = ctx.desc(); + let controller = desc + .controllers + .keys() + .find(|id| ctx.is_function(**id, "controller")) + .unwrap(); + let ctrl = &desc.controllers[controller]; + + assert_eq!(ctx.marked_sinks(ctrl.data_sinks(), input).count(), 0); + assert_eq!(ctx.marked_sinks(ctrl.data_sinks(), sink).count(), 2); +} diff --git a/crates/dfcheck/src/flows_to.rs b/crates/dfcheck/src/flows_to.rs new file mode 100644 index 0000000000..ea30adf8e9 --- /dev/null +++ b/crates/dfcheck/src/flows_to.rs @@ -0,0 +1,119 @@ +use dfgraph::{Ctrl, DataSink, DataSource, DataSourceIndex}; + +use indexical::{impls::BitvecArcIndexMatrix as IndexMatrix, IndexedDomain, ToIndex}; +use itertools::Itertools; + +use std::{fmt, sync::Arc}; + +/// The transitive closure of the [`Ctrl::data_flow`] relation. +/// +/// Implemented efficiently using an [`IndexedDomain`] over the +/// [`DataSource`] and [`DataSink`] types. +pub struct CtrlFlowsTo { + /// The indexes of [`DataSource`]s in the controller. + pub sources: Arc>, + + /// The indexes of [`DataSink`]s in the controller. + pub sinks: Arc>, + + /// The transitive closure of the [`Ctrl::data_flow`] relation. + /// + /// See the [`IndexMatrix`] documentation for details on how to + /// query this representation of the relation. + pub flows_to: IndexMatrix, +} + +impl CtrlFlowsTo { + /// Constructs the transitive closure from a [`Ctrl`]. + pub fn build(ctrl: &Ctrl) -> Self { + // Collect all sources and sinks into indexed domains. + let sources = Arc::new(IndexedDomain::from_iter(ctrl.data_flow.0.keys().cloned())); + let sinks = Arc::new(IndexedDomain::from_iter( + ctrl.data_flow.0.values().flatten().dedup().cloned(), + )); + + // Connect each function-argument sink to its corresponding function sources. + // This lets us compute the transitive closure by following through the `sink_to_source` map. + let mut sink_to_source = IndexMatrix::new(&sources); + for (sink_idx, sink) in sinks.as_vec().iter_enumerated() { + for (src_idx, src) in sources.as_vec().iter_enumerated() { + if let (DataSource::FunctionCall(f1), DataSink::Argument { function: f2, .. }) = + (src, sink) + { + if f1 == f2 { + sink_to_source.insert(sink_idx, src_idx); + } + } + } + } + + // Initialize the `flows_to` relation with the data provided by `Ctrl::data_flow`. + let mut flows_to = IndexMatrix::new(&sinks); + for (src, sinks) in &ctrl.data_flow.0 { + let src = src.to_index(&sources); + for sink in sinks { + flows_to.insert(src, sink); + } + } + + // Compute the transitive closure to a fixpoint. + loop { + let mut changed = false; + + for (src_idx, _src) in sources.as_vec().iter_enumerated() { + for sink_idx in flows_to.row_set(&src_idx).indices().collect::>() { + for trans_src_idx in sink_to_source.row_set(&sink_idx).indices() { + for trans_sink_idx in flows_to + .row_set(&trans_src_idx) + .indices() + .collect::>() + { + changed |= flows_to.insert(src_idx, trans_sink_idx); + } + } + } + } + + if !changed { + break; + } + } + + CtrlFlowsTo { + sources, + sinks, + flows_to, + } + } +} + +impl fmt::Debug for CtrlFlowsTo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.flows_to.fmt(f) + } +} + +#[test] +fn test_flows_to() { + let ctx = crate::test_utils::test_ctx(); + let controller = ctx + .desc() + .controllers + .keys() + .find(|id| ctx.is_function(**id, "controller")) + .unwrap(); + let src = DataSource::Argument(0); + let get_sink = |name| { + ctx.desc().controllers[&controller] + .data_sinks() + .find(|sink| match sink { + DataSink::Argument { function, .. } => ctx.is_function(function.function, name), + _ => false, + }) + .unwrap() + }; + let sink1 = get_sink("sink1"); + let sink2 = get_sink("sink2"); + assert!(ctx.flows_to(&controller, &src, sink1)); + assert!(!ctx.flows_to(&controller, &src, sink2)); +} diff --git a/crates/dfcheck/src/lib.rs b/crates/dfcheck/src/lib.rs new file mode 100644 index 0000000000..29d8c64b96 --- /dev/null +++ b/crates/dfcheck/src/lib.rs @@ -0,0 +1,46 @@ +//! This crate is the engine of the property checker. It consumes +//! a PDG output by `dfpp` and checks user-defined properties on the PDG. +//! +//! *Note:* This crate defines both the interface to the property checkers +//! (via [`Context`]) and the implementation of the engine (via [`cli`]). A +//! future version of this crate should ideally separate those out so +//! property checkers do not need to depend on the checker implementation. + +#![warn(missing_docs)] + +use anyhow::Result; +use dfgraph::ProgramDescription; +use std::env; +use std::fs::File; +use std::sync::Arc; + +pub use self::{context::*, flows_to::CtrlFlowsTo}; +pub use dfgraph; + +mod context; +mod flows_to; +#[cfg(test)] +mod test_utils; + +/// Top-level entry point into the property checker engine. +/// +/// A user-defined checker should call this function in its `main`, +/// and provide a callback that receives the loaded [`Context`]. +pub fn cli(cb: impl FnOnce(Arc)) { + let inner = move || -> Result<()> { + simple_logger::init_with_env().unwrap(); + + let mut args = env::args().skip(1); + let graph_path = args.next().unwrap(); + + let desc = { + let mut f = File::open(graph_path)?; + serde_json::from_reader::<_, ProgramDescription>(&mut f)? + }; + let cx = Arc::new(Context::new(desc)); + cb(cx); + + Ok(()) + }; + inner().unwrap(); +} diff --git a/crates/dfcheck/src/test_utils.rs b/crates/dfcheck/src/test_utils.rs new file mode 100644 index 0000000000..a68417c9d1 --- /dev/null +++ b/crates/dfcheck/src/test_utils.rs @@ -0,0 +1,13 @@ +use crate::Context; +use dfpp::test_utils::PreFrg; +use std::sync::OnceLock; + +static TEST_CTX: OnceLock = OnceLock::new(); + +pub fn test_ctx() -> &'static Context { + TEST_CTX.get_or_init(|| { + dfpp::test_utils::run_dfpp_with_flow_graph_dump("tests/test-crate"); + let desc = PreFrg::from_file_at("tests/test-crate").0; + Context::new(desc) + }) +} diff --git a/crates/dfcheck/tests/test-crate/.gitignore b/crates/dfcheck/tests/test-crate/.gitignore new file mode 100644 index 0000000000..cbd81b791f --- /dev/null +++ b/crates/dfcheck/tests/test-crate/.gitignore @@ -0,0 +1,2 @@ +/analysis_result.frg +/Cargo.lock \ No newline at end of file diff --git a/crates/dfcheck/tests/test-crate/Cargo.toml b/crates/dfcheck/tests/test-crate/Cargo.toml new file mode 100644 index 0000000000..22ef43c3f8 --- /dev/null +++ b/crates/dfcheck/tests/test-crate/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test-crate" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/dfcheck/tests/test-crate/src/lib.rs b/crates/dfcheck/tests/test-crate/src/lib.rs new file mode 100644 index 0000000000..407bcc2066 --- /dev/null +++ b/crates/dfcheck/tests/test-crate/src/lib.rs @@ -0,0 +1,17 @@ +#![feature(register_tool)] +#![register_tool(dfpp)] + +#[dfpp::marker(input)] +pub struct Foo; + +#[dfpp::label{ sink, arguments = [0] }] +fn sink1(_f: Foo) {} + +#[dfpp::label{ sink, arguments = [0] }] +fn sink2(_f: Foo) {} + +#[dfpp::analyze] +fn controller(a: Foo, b: Foo) { + sink1(a); + sink2(b); +} diff --git a/crates/dfgraph/Cargo.toml b/crates/dfgraph/Cargo.toml new file mode 100644 index 0000000000..e6589d3e76 --- /dev/null +++ b/crates/dfgraph/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dfgraph" +version = "0.1.0" +edition = "2021" + +[package.metadata.rust-analyzer] +rustc_private = true + +[features] +rustc = [] + +[dependencies] +serde = { workspace = true, features = ["derive"] } +log = "0.4" +internment = { version = "0.7.1", features = ["serde"] } +indexical = { workspace = true } +itertools = "0.11.0" diff --git a/crates/dfgraph/src/global_location.rs b/crates/dfgraph/src/global_location.rs new file mode 100644 index 0000000000..08db79abd3 --- /dev/null +++ b/crates/dfgraph/src/global_location.rs @@ -0,0 +1,311 @@ +//! Unique identifiers for a point in the MIR program execution that span cross +//! function boundaries. +//! +//! The idea of a global location is to capture the call chain up to a specific +//! location. +//! +//! # Example +//! +//! Consider the following code: +//! +//! ```ignore +//! fn bar() { +//! let x = 1; +//! } +//! +//! #[dfpp::analyze] +//! fn foo { +//! bar(); +//! bar(); +//! } +//! ``` +//! +//! The MIR location of `let x = 1` would likely be something like `bb0[0]` i.e. +//! the 0th statement in basic block 0. However if we construct a flow graph of +//! `foo` that traverses into the called functions (e.g. `bar`), this location +//! is no longer unique. In fact the location of the call to `bar` in `foo` +//! probably also has the MIR location `bb0[0]`. In addition the same function +//! can occur twice so we need to be able to disambiguate a location based on +//! the call chain of getting to the location. +//! +//! So in this example when we inline the first call of `bar` at `bb0[0]` the +//! global location for `let x = 1` for that call is `bb0[0]@bb0[0]` (This is +//! what the `impl Display for GlobalLocation` shows). When the second call is +//! inlined the second `let x = 1` would be `bb0[0]@bb1[0]`. +//! +//! In addition we also capture for every location the `BodyId` of the body the +//! location occurs in, so we can later find the body and the code at that +//! location. +//! +//! # Construction +//! +//! [`GlobalLocation::single`] is used to construct global locations that are +//! not nested in a call chain (such as the location of `let x = 1` within +//! `bar`). A nested location (such as nesting this one behind the call to `bar` +//! in `foo`) is done using [`GlobalLocation::relativize`]. +//! +//! In the example we would first construct global locations for all locations +//! in `bar` with (pseudocode) `bar_bb0[0] = `[`GlobalLocation::single(bb0[0], +//! bar_id)`](GlobalLocation::single) and then make the relative locations to +//! foo with [`bar_bb0[0].relativize(bb0[0], foo_id)`](GlobalLocation::relativize) and +//! [`bar_bb0[0].relativize(bb1[0], foo_id)`](GlobalLocation::relativize) for the first and second +//! inlining respectively. +//! +//! # Representation +//! +//! It is organized from the outside-in, i.e., the top-level function call is the +//! outermost location which calls `next` at `location` going one level deeper +//! and so forth. You may access the innermost location using +//! `GlobalLocation::innermost_location_and_body`. +//! +//! The innermost location is what you'd want to look up if you are wanting to +//! see the actual statement or terminator that this location refers to. + +#[cfg(feature = "rustc")] +use crate::rustc::{hir, mir}; +use crate::rustc_proxies; +use internment::Intern; +use serde::{Deserialize, Serialize}; +use std::{cmp::Ordering, fmt, ops::Deref}; + +#[cfg(feature = "rustc")] +pub type BodyId = hir::BodyId; +#[cfg(not(feature = "rustc"))] +pub type BodyId = rustc_proxies::BodyId; + +#[cfg(feature = "rustc")] +pub type Location = mir::Location; +#[cfg(not(feature = "rustc"))] +pub type Location = rustc_proxies::Location; + +/// The payload type of a global location. +/// +/// You will probably want to operate on the interned wrapper type [`GlobalLocation`]. +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, Serialize, Deserialize)] +pub struct GlobalLocationS { + #[cfg(feature = "rustc")] + #[serde(with = "rustc_proxies::BodyId")] + /// The id of the body in which this location is located. + pub function: hir::BodyId, + #[cfg(not(feature = "rustc"))] + /// The id of the body in which this location is located. + pub function: rustc_proxies::BodyId, + + #[cfg(feature = "rustc")] + #[serde(with = "rustc_proxies::Location")] + /// The location itself + pub location: mir::Location, + #[cfg(not(feature = "rustc"))] + /// The location itself + pub location: rustc_proxies::Location, +} + +impl GlobalLocationS { + pub fn relativize(self, location: GlobalLocation) -> GlobalLocation { + let mut location = location.to_owned(); + location.0.insert(0, self); + GlobalLocation::into_intern(location) + } +} + +#[derive(PartialEq, Eq, Hash, Debug, Clone, Deserialize, Serialize)] +pub struct RawGlobalLocation(Vec); + +impl RawGlobalLocation { + pub fn as_slice(&self) -> &[GlobalLocationS] { + &self.0 + } + + pub fn outermost(&self) -> GlobalLocationS { + *self.as_slice().first().unwrap() + } + + /// Get the `function` field of the underlying location. + pub fn outermost_function(&self) -> BodyId { + self.outermost().function + } + + /// Get the `location` field of the underlying location. + pub fn outermost_location(&self) -> Location { + self.outermost().location + } + + pub fn innermost(&self) -> GlobalLocationS { + *self.as_slice().last().unwrap() + } + + pub fn innermost_location(&self) -> Location { + self.innermost().location + } + + pub fn innermost_function(&self) -> BodyId { + self.innermost().function + } + + /// It this location is top-level (i.e. `self.next() == None`), then return + /// the `location` field. + pub fn as_local(&self) -> Option { + if self.is_at_root() { + Some(self.outermost_location()) + } else { + None + } + } + /// This location is at the top level (e.g. not-nested e.g. `self.next() == + /// None`). + pub fn is_at_root(&self) -> bool { + self.as_slice().len() == 1 + } + + pub fn iter_parents(&self) -> impl Iterator { + let slc = self.as_slice(); + (1..slc.len()).map(|i| &slc[0..i]) + } + + pub fn iter(&self) -> impl Iterator + '_ { + self.as_slice().iter().copied() + } +} + +impl PartialOrd for RawGlobalLocation { + fn partial_cmp(&self, other: &Self) -> Option { + for (slf, othr) in self.as_slice().iter().zip(other.as_slice().iter()) { + if slf.function != othr.function { + return slf.function.hir_id.partial_cmp(&othr.function.hir_id); + } + if slf.location == othr.location { + return slf.location.partial_cmp(&othr.location); + } + } + + self.as_slice().len().partial_cmp(&other.as_slice().len()) + } +} + +impl Ord for RawGlobalLocation { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } +} + +impl From<&'_ RawGlobalLocation> for RawGlobalLocation { + fn from(value: &'_ RawGlobalLocation) -> Self { + value.clone() + } +} + +impl fmt::Display for RawGlobalLocation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + crate::utils::write_sep(f, "@", self.as_slice().iter().rev(), |elem, f| { + write!( + f, + "{:?}[{}]", + elem.location.block, elem.location.statement_index + ) + }) + } +} + +/// The interned version of a global location. See the [module level documentation](super) +/// information on usage and rational. +/// +/// To construct these values use [`GlobalLocation::single`] and +/// [`GlobalLocation::relativize`]. +/// +/// INVARIANT: `self.0.len() > 0` +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)] +pub struct GlobalLocation(Intern); + +impl Deref for GlobalLocation { + type Target = RawGlobalLocation; + + fn deref(&self) -> &Self::Target { + self.0.as_ref() + } +} + +impl fmt::Debug for GlobalLocation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.as_ref().fmt(f) + } +} + +impl fmt::Display for GlobalLocation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.as_ref().fmt(f) + } +} + +impl GlobalLocation { + /// The naming here might be misleading, this id is *not stable across tool + /// runs*, but because of the interner it is guaranteed that for any two + /// locations `g1` and `g2`, `g1.stable_id() == g2.stable_id()` iff `g1 == + /// g2`. + pub fn stable_id(self) -> usize { + self.0.as_ref() as *const RawGlobalLocation as usize + } + + pub fn to_owned(&self) -> RawGlobalLocation { + (*self.0).to_owned() + } + + pub fn parent(self) -> Option { + if self.is_at_root() { + None + } else { + let mut this = self.to_owned(); + this.0.pop(); + Some(Self::into_intern(this)) + } + } + + pub fn into_intern(path: RawGlobalLocation) -> Self { + GlobalLocation(Intern::new(path)) + } + + pub fn intern(path: &RawGlobalLocation) -> Self { + GlobalLocation(Intern::from_ref(path)) + } + + pub fn single(location: Location, function: BodyId) -> Self { + Self::into_intern(RawGlobalLocation(vec![GlobalLocationS { + location, + function, + }])) + } +} + +#[cfg(all(test, not(feature = "rustc")))] +mod test { + use crate::rustc_proxies::{BasicBlock, DefIndex, HirId, ItemLocalId, LocalDefId, OwnerId}; + + use super::*; + + #[test] + fn test_global_location() { + let location = Location { + block: BasicBlock { private: 0 }, + statement_index: 0, + }; + + let function = BodyId { + hir_id: HirId { + owner: OwnerId { + def_id: LocalDefId { + local_def_index: DefIndex { private: 0 }, + }, + }, + local_id: ItemLocalId { private: 0 }, + }, + }; + + let g1 = GlobalLocation::single(location, function); + let g2 = GlobalLocation::single(location, function); + + // Locations are structurally equal + assert_eq!(g1, g2); + + // Interning ensures the pointers are the same + assert_eq!(g1.stable_id(), g2.stable_id()); + } +} diff --git a/src/desc.rs b/crates/dfgraph/src/lib.rs similarity index 64% rename from src/desc.rs rename to crates/dfgraph/src/lib.rs index d56e0b2e7b..1898ff10af 100644 --- a/src/desc.rs +++ b/crates/dfgraph/src/lib.rs @@ -1,20 +1,40 @@ -//! Type definitions and helper functions for a Forge-friendly representation of -//! flow analysis results and annotations we discovered. +//! This crate defines the program dependence graph (PDG) generated by Paralegal. //! -//! Analyses that create these types are in [`ana`](crate::ana) and serializers for -//! emitting forge from them in [`crate::frg`]. -//! -//! The top-level type is [`ProgramDescription`] +//! The top-level type is [`ProgramDescription`]. This type references multiple +//! types defined within the Rust compiler such as MIR locations. To avoid requiring +//! a `rustc_private` dependency on dfgraph clients, we provide proxies in the +//! [`rustc_proxies`] module for all Rustc types within the PDG. + +#![cfg_attr(feature = "rustc", feature(rustc_private))] + +#[cfg(feature = "rustc")] +pub(crate) mod rustc { + extern crate rustc_driver; + pub extern crate rustc_hir as hir; + pub extern crate rustc_index as index; + pub extern crate rustc_middle as middle; + pub extern crate rustc_span as span; + pub use hir::def_id; + pub use middle::mir; +} + +pub mod global_location; +#[cfg(feature = "rustc")] +mod rustc_impls; +pub mod rustc_proxies; +mod tiny_bitset; +pub mod utils; -use std::hash::Hash; +use global_location::GlobalLocation; +use indexical::define_index_type; +use internment::Intern; +use itertools::Itertools; +use log::warn; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{borrow::Cow, hash::Hash, iter}; -use crate::{ - ir::{IsGlobalLocation, RawGlobalLocation}, - rust::DefId, - serde, - utils::{identifier_for_item, TinyBitSet}, - HashMap, HashSet, Symbol, TyCtxt, -}; +pub use crate::tiny_bitset::TinyBitSet; +pub use std::collections::{HashMap, HashSet}; pub type Endpoint = Identifier; pub type TypeDescriptor = Identifier; @@ -25,7 +45,7 @@ pub type Function = Identifier; /// Usually you'd expect one of those annotation types in any given situation. /// For convenience the match methods [`Self::as_label_ann`], /// [`Self::as_otype_ann`] and [`Self::as_exception_annotation`] are provided. These are particularly useful in conjunction with e.g. [`Iterator::filter_map`] -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, serde::Deserialize, serde::Serialize)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Deserialize, Serialize)] pub enum Annotation { Label(MarkerAnnotation), OType(Vec), @@ -33,6 +53,7 @@ pub enum Annotation { } impl Annotation { + /// If this is an [`Annotation::Label`], returns the underlying [`MarkerAnnotation`]. pub fn as_label_ann(&self) -> Option<&MarkerAnnotation> { match self { Annotation::Label(l) => Some(l), @@ -40,10 +61,12 @@ impl Annotation { } } + /// Returns true if this is an [`Annotation::Label`]. pub fn is_label_ann(&self) -> bool { matches!(self, Annotation::Label(_)) } + /// If this is an [`Annotation::OType`], returns the underlying [`TypeDescriptor`]. pub fn as_otype_ann(&self) -> Option<&[TypeDescriptor]> { match self { Annotation::OType(t) => Some(t), @@ -51,6 +74,7 @@ impl Annotation { } } + /// If this is an [`Annotation::Exception`], returns the underlying [`ExceptionAnnotation`]. pub fn as_exception_annotation(&self) -> Option<&ExceptionAnnotation> { match self { Annotation::Exception(e) => Some(e), @@ -61,7 +85,7 @@ impl Annotation { pub type VerificationHash = u128; -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Serialize, Deserialize)] pub struct ExceptionAnnotation { /// The value of the verification hash we found in the annotation. Is `None` /// if there was no verification hash in the annotation. @@ -69,11 +93,10 @@ pub struct ExceptionAnnotation { } /// A label annotation and its refinements. -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Serialize, Deserialize)] pub struct MarkerAnnotation { /// The (unchanged) name of the label as provided by the user - #[serde(with = "crate::serializers::ser_sym")] - pub marker: Symbol, + pub marker: Identifier, #[serde(flatten)] pub refinement: MarkerRefinement, } @@ -85,20 +108,17 @@ fn const_false() -> bool { /// Refinements in the label targeting. The default (no refinement provided) is /// `on_argument == vec![]` and `on_return == false`, which is also what is /// returned from [`Self::empty`]. -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, serde::Deserialize, serde::Serialize)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Deserialize, Serialize)] pub struct MarkerRefinement { - #[serde(default, with = "crate::utils::tiny_bitset::pretty")] + #[serde(default, with = "crate::tiny_bitset::pretty")] on_argument: TinyBitSet, #[serde(default = "const_false")] on_return: bool, } -/// Refinements as the parser discovers them. Are then merged onto the aggregate [`AnnotationRefinement`] with [`AnnotationRefinement::merge_kind`]. -#[derive(Clone, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Deserialize, Serialize)] pub enum MarkerRefinementKind { - /// Corresponds to [`AnnotationRefinement::on_argument`] - Argument(#[serde(with = "crate::utils::tiny_bitset::pretty")] TinyBitSet), - /// Corresponds to [`AnnotationRefinement::on_return`] + Argument(#[serde(with = "crate::tiny_bitset::pretty")] TinyBitSet), Return, } @@ -153,7 +173,7 @@ impl MarkerRefinement { } } -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Serialize, Deserialize)] pub enum ObjectType { Function(usize), Type, @@ -192,11 +212,13 @@ impl ObjectType { pub type AnnotationMap = HashMap, ObjectType)>; -/// A Forge friendly representation of the dataflow graphs we calculated and the -/// annotations we found. -#[derive(serde::Serialize, serde::Deserialize)] +/// The annotated program dependence graph. +#[derive(Serialize, Deserialize, Debug)] pub struct ProgramDescription { + /// Mapping from function names to dependencies within the function. pub controllers: HashMap, + + /// Mapping from objects to annotations on those objects. pub annotations: AnnotationMap, } @@ -290,79 +312,93 @@ impl ProgramDescription { } } -#[derive( - Hash, Eq, PartialEq, Ord, Debug, PartialOrd, Clone, serde::Serialize, serde::Deserialize, Copy, -)] -pub struct Identifier(#[serde(with = "crate::serializers::ser_sym")] Symbol); +/// An identifier for any kind of object (functions, markers, etc.). +/// +/// Implemented as an interned string, so identifiers are cheap to reuse. +#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize, Copy)] +pub struct Identifier(Intern); impl Identifier { - pub fn new(s: Symbol) -> Self { - Identifier(s) - } + /// Returns the underlying string from an identifier. pub fn as_str(&self) -> &str { self.0.as_str() } + + /// Interns the input string into an identifier. + /// + /// Note: this requires locking the global intern arena. See [`internment::Intern`] for details. pub fn new_intern(s: &str) -> Self { - Self::new(Symbol::intern(s)) + Identifier(Intern::from_ref(s)) + } +} + +impl std::fmt::Debug for Identifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + self.0.as_ref().fmt(f) } } impl std::fmt::Display for Identifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - self.0.fmt(f) + self.0.as_ref().fmt(f) } } /// Because we need these kinds of associations so often I made a separate type /// for it. Also allows us to serialize it more conveniently. +#[derive(Debug)] pub struct Relation(pub HashMap>); -impl serde::Serialize - for Relation -{ +impl Serialize for Relation { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { self.0.iter().collect::>().serialize(serializer) } } -impl< - 'de, - X: serde::Deserialize<'de> + std::hash::Hash + std::cmp::Eq, - Y: serde::Deserialize<'de> + std::hash::Hash + std::cmp::Eq, - > serde::Deserialize<'de> for Relation +impl<'de, X: Deserialize<'de> + Hash + Eq, Y: Deserialize<'de> + Hash + Eq> Deserialize<'de> + for Relation { fn deserialize(deserializer: D) -> Result where - D: serde::Deserializer<'de>, + D: Deserializer<'de>, { - as serde::Deserialize<'de>>::deserialize(deserializer) + as Deserialize<'de>>::deserialize(deserializer) .map(|v| Self(v.into_iter().collect())) } } impl Relation { + /// Constructs an empty relation. pub fn empty() -> Self { Relation(HashMap::new()) } } -/// [`GlobalLocation`](crate::ir::GlobalLocation). -#[derive(Hash, Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +/// A global location in the program where a function is being called. +#[derive(Hash, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] pub struct CallSite { - pub location: RawGlobalLocation, + /// The location of the call. + pub location: GlobalLocation, + + /// The name of the function being called. pub function: Function, } -impl CallSite { - pub fn new(loc: &L, function: DefId, tcx: TyCtxt<'_>) -> Self { - Self { - location: loc.as_raw(), - function: identifier_for_item(tcx, function), - } - } +/// Create a hash for this object that is no longer than six hex digits +pub fn short_hash_pls(t: T) -> u64 { + // Six digits in hex + hash_pls(t) % 0x1_000_000 +} + +/// Calculate a hash for this object +pub fn hash_pls(t: T) -> u64 { + use std::hash::Hasher; + let mut hasher = std::collections::hash_map::DefaultHasher::default(); + t.hash(&mut hasher); + hasher.finish() } impl std::string::ToString for CallSite { @@ -370,7 +406,7 @@ impl std::string::ToString for CallSite { format!( "cs_{}_{:x}", self.function.as_str(), - crate::utils::short_hash_pls(&self.location), + short_hash_pls(self.location), ) } } @@ -379,22 +415,31 @@ impl std::string::ToString for CallSite { /// /// Convenience match functions are provided (for use e.g. in /// [`Iterator::filter_map`]) with [`Self::as_function_call`] and [`Self::as_argument`]. -#[derive(Hash, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize, Debug)] +#[derive(Hash, Eq, PartialEq, Clone, Serialize, Deserialize, Debug)] pub enum DataSource { /// The result of a function call in the controller body. Can be the return /// value or a mutable argument that was passed to the call. FunctionCall(CallSite), + /// An argument to the controller function. Argument(usize), } +define_index_type! { + /// Index over [`DataSource`], for use with `indexical` index sets. + pub struct DataSourceIndex for DataSource = u32; +} + impl DataSource { + /// If this is a [`DataSource::FunctionCall`], then returns the underlying [`CallSite`]. pub fn as_function_call(&self) -> Option<&CallSite> { match self { DataSource::FunctionCall(i) => Some(i), _ => None, } } + + /// If this is a [`DataSource::Argument`], then returns the underlying argument index. pub fn as_argument(&self) -> Option { match self { DataSource::Argument(a) => Some(*a), @@ -406,13 +451,14 @@ impl DataSource { /// A representation of something that can receive data from the flow. /// /// [`Self::as_argument`] is provided for convenience of matching. -#[derive(Hash, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize, Debug)] +#[derive(Hash, PartialEq, Eq, Clone, Serialize, Deserialize, Debug)] pub enum DataSink { Argument { function: CallSite, arg_slot: usize }, Return, } impl DataSink { + /// If this is a `DataSink::Argument`, then returns that branch's fields. pub fn as_argument(&self) -> Option<(&CallSite, usize)> { match self { DataSink::Argument { function, arg_slot } => Some((function, *arg_slot)), @@ -421,15 +467,27 @@ impl DataSink { } } -/// Annotations on types in a controller. Only types that have annotations are -/// present in this map, meaning that it is guaranteed that for any key `k` -/// `map.get(k).is_empty() == false`. +define_index_type! { + /// Index over [`DataSink`], for use with `indexical` index sets. + pub struct DataSinkIndex for DataSink = u32; +} + pub type CtrlTypes = Relation; -#[derive(serde::Deserialize, serde::Serialize)] +/// Dependencies within a controller function. +#[derive(Serialize, Deserialize, Debug)] pub struct Ctrl { + /// Non-transitive data dependencies between sources and sinks. pub data_flow: Relation, + + /// Transitive control dependencies between sources and call sites. pub ctrl_flow: Relation, + + /// Annotations on types in a controller. + /// + /// Only types that have annotations are present in this map, meaning + /// that it is guaranteed that for any key `k` that + /// `map.get(k).is_empty() == false`. pub types: CtrlTypes, } @@ -444,20 +502,24 @@ impl Default for Ctrl { } impl Ctrl { - /// Extend the type annotations - pub fn add_types)>>( + /// Returns an iterator over all the data sinks in the `data_flow` relation. + pub fn data_sinks(&self) -> impl Iterator + '_ { + self.data_flow.0.values().flatten().unique() + } + + /*** Below are constructor methods intended for use within dfpp. ***/ + + /// Extend the `types` map with the input iterator. + pub fn add_types( &mut self, - i: I, + i: impl IntoIterator)>, ) { - i.into_iter().for_each(|(ident, set)| { - self.types - .0 - .entry(ident) - .or_insert_with(HashSet::new) - .extend(set.into_iter()) - }) + for (ident, set) in i { + self.types.0.entry(ident).or_default().extend(set); + } } + /// Construct an empty controller with the given [`CtrlTypes`]. pub fn with_input_types(types: CtrlTypes) -> Self { Ctrl { data_flow: Relation::empty(), @@ -465,20 +527,24 @@ impl Ctrl { types, } } - pub fn add_data_flow(&mut self, from: std::borrow::Cow, to: DataSink) { + + /// Add one data flow between `from` and `to`. + pub fn add_data_flow(&mut self, from: Cow, to: DataSink) { let m = &mut self.data_flow.0; if let Some(e) = m.get_mut(&from) { e.insert(to); } else { - m.insert(from.into_owned(), std::iter::once(to).collect()); + m.insert(from.into_owned(), iter::once(to).collect()); } } - pub fn add_ctrl_flow(&mut self, from: std::borrow::Cow, to: CallSite) { + + /// Add one control flow between `from` and `to`. + pub fn add_ctrl_flow(&mut self, from: Cow, to: CallSite) { let m = &mut self.ctrl_flow.0; if let Some(e) = m.get_mut(&from) { e.insert(to); } else { - m.insert(from.into_owned(), std::iter::once(to).collect()); + m.insert(from.into_owned(), iter::once(to).collect()); } } } diff --git a/crates/dfgraph/src/rustc_impls.rs b/crates/dfgraph/src/rustc_impls.rs new file mode 100644 index 0000000000..2515f41754 --- /dev/null +++ b/crates/dfgraph/src/rustc_impls.rs @@ -0,0 +1,67 @@ +use super::rustc_proxies::*; +use super::*; +use crate::rustc::{def_id, hir, mir, span}; + +pub fn bbref_to_u32(r: &mir::BasicBlock) -> u32 { + r.as_u32() +} + +impl From for mir::BasicBlock { + fn from(bb: BasicBlock) -> mir::BasicBlock { + mir::BasicBlock::from_u32(bb.private) + } +} + +impl From for mir::Location { + fn from( + Location { + block, + statement_index, + }: Location, + ) -> mir::Location { + mir::Location { + block, + statement_index, + } + } +} + +impl From for Location { + fn from( + mir::Location { + block, + statement_index, + }: mir::Location, + ) -> Location { + Location { + block, + statement_index, + } + } +} + +pub fn item_local_id_as_u32(i: &hir::ItemLocalId) -> u32 { + i.as_u32() +} + +impl From for hir::ItemLocalId { + fn from(proxy: ItemLocalId) -> hir::ItemLocalId { + hir::ItemLocalId::from_u32(proxy.private) + } +} + +pub fn def_index_as_u32(i: &def_id::DefIndex) -> u32 { + i.as_u32() +} + +impl From for def_id::DefIndex { + fn from(proxy: DefIndex) -> def_id::DefIndex { + def_id::DefIndex::from_u32(proxy.private) + } +} + +impl Identifier { + pub fn new(s: span::Symbol) -> Self { + Identifier::new_intern(s.as_str()) + } +} diff --git a/crates/dfgraph/src/rustc_proxies.rs b/crates/dfgraph/src/rustc_proxies.rs new file mode 100644 index 0000000000..dc902acca8 --- /dev/null +++ b/crates/dfgraph/src/rustc_proxies.rs @@ -0,0 +1,128 @@ +//! Proxies for Rustc types used within the PDG. +//! +//! Each type has an identical set of fields to the corresponding Rustc type. +//! Paralegal serializes the PDG into these types, which are read by downstream property checkers. + +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "rustc")] +use crate::{ + rustc::{def_id, hir, mir}, + rustc_impls::*, +}; + +/// Generates a struct that is a proxy for a Rustc type. +/// +/// This works by telling Serde to the proxy struct as "remote" for the Rustc type. +/// Each field of the struct is either the actual Rustc type if the "rustc" feature is enabled, +/// or the proxy type otherwise. +macro_rules! proxy_struct { + ($( + $(#[$attr:meta])* + $name:ident($rustc:expr) { + $($field:ident : $rustc_ty:ty => $proxy_ty:ty , $proxy_str:expr),* + } + )*) => { + $( + #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)] + #[cfg_attr(feature = "rustc", serde(remote = $rustc))] + $(#[$attr])* + pub struct $name { + $( + #[cfg(feature = "rustc")] + #[serde(with = $proxy_str)] + pub $field: $rustc_ty, + #[cfg(not(feature = "rustc"))] + pub $field: $proxy_ty, + )* + } + )* + } +} + +/// Generates a struct that is a proxy for a Rustc index type. +macro_rules! proxy_index { + ($( + $(#[$attr:meta])* + $name:ident($rustc:expr) from $fn:expr + );*) => { + $( + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Serialize, Deserialize)] + #[cfg_attr(feature = "rustc", serde(remote = $rustc))] + $(#[$attr])* + pub struct $name { + #[cfg_attr(feature = "rustc", serde(getter = $fn))] + pub(crate) private: u32 + } + + #[cfg(not(feature = "rustc"))] + impl $name { + pub fn index(self) -> usize { + self.private as usize + } + } + )* + } +} + +proxy_index! { + /// Proxy for `mir::BasicBlock` + BasicBlock("mir::BasicBlock") from "bbref_to_u32"; + + /// Proxy for `hir::ItemLocalId` + ItemLocalId("hir::ItemLocalId") from "item_local_id_as_u32"; + + /// Proxy for `def_id::DefIndex` + DefIndex("def_id::DefIndex") from "def_index_as_u32" +} + +proxy_struct! { + /// Proxy for `mir::Location` + #[derive(PartialOrd, Ord)] + Location("mir::Location") { + block: mir::BasicBlock => BasicBlock, "BasicBlock", + statement_index: usize => usize, "usize" + } + + /// Proxy for `def_id::LocalDefId` + LocalDefId("def_id::LocalDefId") { + local_def_index: def_id::DefIndex => DefIndex, "DefIndex" + } + + /// Proxy for `hir_id::OwnerHid` + OwnerId("hir::hir_id::OwnerId") { + def_id: def_id::LocalDefId => LocalDefId, "LocalDefId" + } + + /// Proxy for `hir::HirId` + HirId("hir::HirId") { + owner: hir::OwnerId => OwnerId, "OwnerId", + local_id: hir::ItemLocalId => ItemLocalId, "ItemLocalId" + } + + /// Proxy for `hir::BodyId` + BodyId("hir::BodyId") { + hir_id: hir::HirId => HirId, "HirId" + } +} + +impl HirId { + fn index(self) -> (usize, usize) { + ( + self.owner.def_id.local_def_index.index(), + self.local_id.index(), + ) + } +} + +impl Ord for HirId { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + (self.index()).cmp(&(other.index())) + } +} + +impl PartialOrd for HirId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} diff --git a/src/utils/tiny_bitset.rs b/crates/dfgraph/src/tiny_bitset.rs similarity index 90% rename from src/utils/tiny_bitset.rs rename to crates/dfgraph/src/tiny_bitset.rs index 5117d6135b..c64c9ea05d 100644 --- a/src/utils/tiny_bitset.rs +++ b/crates/dfgraph/src/tiny_bitset.rs @@ -1,3 +1,4 @@ +/// A bit-set implemented with a [`u16`], supporting domains up to 16 elements. #[derive( Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Copy, serde::Serialize, serde::Deserialize, )] @@ -152,3 +153,17 @@ pub mod pretty { ) } } + +#[test] +fn test_tiny_bitset() { + let mut s = TinyBitSet::new_empty(); + s.set(5); + assert_eq!(s.contains(5), Some(true)); + assert_eq!(s.contains(0), Some(false)); + assert_eq!(s.contains(16), None); + + let before = s.0; + s.set(16); + let after = s.0; + assert_eq!(before, after); +} diff --git a/crates/dfgraph/src/utils.rs b/crates/dfgraph/src/utils.rs new file mode 100644 index 0000000000..08f379e39e --- /dev/null +++ b/crates/dfgraph/src/utils.rs @@ -0,0 +1,23 @@ +use std::fmt; + +pub fn write_sep< + E, + I: IntoIterator, + F: FnMut(E, &mut fmt::Formatter<'_>) -> fmt::Result, +>( + fmt: &mut fmt::Formatter<'_>, + sep: &str, + it: I, + mut f: F, +) -> fmt::Result { + let mut first = true; + for e in it { + if first { + first = false; + } else { + fmt.write_str(sep)?; + } + f(e, fmt)?; + } + Ok(()) +} diff --git a/crates/dfpp-explorer/Cargo.toml b/crates/dfpp-explorer/Cargo.toml new file mode 100644 index 0000000000..9520aca540 --- /dev/null +++ b/crates/dfpp-explorer/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "dfpp-explorer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dfpp = { path = "../dfpp" } +petgraph = "0.6" +clap = { version = "=4.3.24", features = ["derive", "cargo", "env"] } +indicatif = "0.17" +serde-lexpr = "0.1" +dialoguer = { version = "0.10", features = ["history", "fuzzy-select"] } +ringbuffer = "0.13" + +[build-dependencies] +chrono = "0.4" \ No newline at end of file diff --git a/crates/dfpp-explorer/build.rs b/crates/dfpp-explorer/build.rs new file mode 100644 index 0000000000..91628a3380 --- /dev/null +++ b/crates/dfpp-explorer/build.rs @@ -0,0 +1,68 @@ +use std::path::PathBuf; +use std::process::Command; +extern crate chrono; +use std::env; + +const COMPILER_DEPENDENT_BINARIES: &[&str] = &["dfpp-explorer"]; + +fn add_link_arg_for_compiler_binaries(s: impl std::fmt::Display) { + for bin in COMPILER_DEPENDENT_BINARIES { + println!("cargo:rustc-link-arg-bin={bin}={s}"); + } +} + +fn add_link_search_path_for_compiler_binaries(s: impl std::fmt::Display) { + add_link_arg_for_compiler_binaries(format!("-Wl,-rpath,{s}")) +} + +/// The "SYSROOT" path for the toolchain we're compiling against. +/// ($RUSTUP_HOME/toolchains/$RUSTUP_TOOLCHAIN) +fn rustup_toolchain_path() -> PathBuf { + let rustup_home = env::var("RUSTUP_HOME").unwrap(); + let rustup_tc = env::var("RUSTUP_TOOLCHAIN").unwrap(); + [&rustup_home, "toolchains", &rustup_tc] + .into_iter() + .collect() +} + +/// Taken from Kani +/// () +/// this code links the rustc libraries directly with the compiled binaries. +pub fn link_rustc_lib() { + // Add rustup to the rpath in order to properly link with the correct rustc version. + let mut rustup_lib = rustup_toolchain_path(); + rustup_lib.push("lib"); + add_link_search_path_for_compiler_binaries(rustup_lib.display()); + + // While we hard-code the above for development purposes, for a release/install we look + // in a relative location for a symlink to the local rust toolchain + let origin = if cfg!(target_os = "macos") { + "@loader_path" + } else { + "$ORIGIN" + }; + add_link_search_path_for_compiler_binaries(format!("{origin}/../toolchain/lib")); + if cfg!(target_os = "linux") { + println!("cargo:rustc-link-search=native={}", rustup_lib.display()); + } +} + +fn main() { + link_rustc_lib(); + println!( + "cargo:rustc-env=COMMIT_HASH={}", + Command::new("git") + .args(["log", "-n", "1", "--pretty=format:\"%H\""]) + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap_or("unknown".to_owned()) + ); + println!( + "cargo:rustc-env=BUILD_TIME={}", + chrono::Local::now().format("%a %b %e %T %Y") + ); + + let toolchain_path = rustup_toolchain_path(); + println!("cargo:rustc-env=SYSROOT_PATH={}", toolchain_path.display()); +} diff --git a/explorer/command.rs b/crates/dfpp-explorer/src/command.rs similarity index 97% rename from explorer/command.rs rename to crates/dfpp-explorer/src/command.rs index 41f7039eeb..85f0a7bf07 100644 --- a/explorer/command.rs +++ b/crates/dfpp-explorer/src/command.rs @@ -281,10 +281,10 @@ impl std::str::FromStr for Direction { } #[derive(Debug)] -pub enum RunCommandErr<'g> { +pub enum RunCommandErr { NodeNotFound(NodeName), Unimplemented(&'static str), - EdgeWeightMissing(Node<'g>, Node<'g>), + EdgeWeightMissing(Node, Node), NonsensicalPathMetric(PathType, PathMetric), IOError(std::io::Error), DotError(Option), @@ -293,19 +293,19 @@ pub enum RunCommandErr<'g> { NoGraphLoaded, } -impl From for RunCommandErr<'_> { +impl From for RunCommandErr { fn from(e: sexpr::parse::Error) -> Self { RunCommandErr::LispParseErr(e) } } -impl From for RunCommandErr<'_> { +impl From for RunCommandErr { fn from(err: std::io::Error) -> Self { RunCommandErr::IOError(err) } } -impl<'g> std::fmt::Display for RunCommandErr<'g> { +impl std::fmt::Display for RunCommandErr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use RunCommandErr::*; match self { diff --git a/explorer/graph.rs b/crates/dfpp-explorer/src/graph.rs similarity index 96% rename from explorer/graph.rs rename to crates/dfpp-explorer/src/graph.rs index c8423db124..d57ebb7b08 100644 --- a/explorer/graph.rs +++ b/crates/dfpp-explorer/src/graph.rs @@ -12,7 +12,7 @@ use petgraph::visit::{ }; /// The canonical representation fo a graph used by the explorer. -pub type Graph<'g> = petgraph::graphmap::GraphMap, Edge, petgraph::Directed>; +pub type Graph = petgraph::graphmap::GraphMap; /// Assigns an edge weight via a closure. pub struct WithWeightedEdges<'f, G: IntoEdgeReferences> { @@ -174,26 +174,26 @@ impl Visitable for IgnoreCtrlEdges { /// Node representation as used by the canonical [`Graph`]. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)] #[repr(transparent)] -pub struct Node<'g>(Option>); +pub struct Node(Option); -impl<'g> Node<'g> { +impl Node { pub fn return_() -> Self { Self(None) } /// `None` means this is the return node - pub fn location(self) -> Option> { + pub fn location(self) -> Option { self.0 } } -impl<'g> From> for Node<'g> { - fn from(loc: GlobalLocation<'g>) -> Self { +impl From for Node { + fn from(loc: GlobalLocation) -> Self { Self(Some(loc)) } } -impl<'g> std::fmt::Display for Node<'g> { +impl std::fmt::Display for Node { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(n) = self.0 { n.fmt(f) diff --git a/explorer/main.rs b/crates/dfpp-explorer/src/main.rs similarity index 85% rename from explorer/main.rs rename to crates/dfpp-explorer/src/main.rs index 01f8e607c9..d2aea50ee6 100644 --- a/explorer/main.rs +++ b/crates/dfpp-explorer/src/main.rs @@ -9,7 +9,7 @@ extern crate serde_lexpr as sexpr; use clap::Parser; -use dfpp::{ir::global_location::*, serializers::Bodies, Either, HashMap}; +use dfpp::{serializers::Bodies, Either, HashMap}; use ringbuffer::RingBufferWrite; mod command; @@ -30,18 +30,16 @@ struct Args { } /// State of the read-eval-print loop -struct Repl<'g> { - gloc_translation_map: Option>>, - graph: Option>, +struct Repl { + gloc_translation_map: Option>, + graph: Option, prompt_for_missing_nodes: bool, bodies: Option, - gli: GLI<'g>, } -impl<'g> Repl<'g> { - fn empty(gli: GLI<'g>) -> Self { +impl Repl { + fn empty() -> Self { Self { - gli, gloc_translation_map: None, graph: None, bodies: None, @@ -74,10 +72,7 @@ fn main() { let args = Args::parse(); dfpp::rust::rustc_span::create_default_session_if_not_set_then(|_| { - let arena = dfpp::rust::rustc_arena::TypedArena::default(); - let interner = GlobalLocationInterner::new(&arena); - let gli = GLI::new(&interner); - let mut repl = Repl::empty(gli); + let mut repl = Repl::empty(); if let Some(file) = args.file.as_ref() { repl.load_graph(file.as_path()).unwrap(); diff --git a/explorer/run.rs b/crates/dfpp-explorer/src/run.rs similarity index 92% rename from explorer/run.rs rename to crates/dfpp-explorer/src/run.rs index a40ce604f1..1db8f5e238 100644 --- a/explorer/run.rs +++ b/crates/dfpp-explorer/src/run.rs @@ -5,7 +5,7 @@ use std::fmt::Display; use dfpp::{ ana::inline::{add_weighted_edge, Edge, EdgeType}, - ir::global_location::*, + ir::GlobalLocationS, serializers::Bodies, utils::{outfile_pls, write_sep, Print}, Either, HashMap, @@ -18,8 +18,8 @@ use crate::graph::*; use crate::Repl; -impl<'g> Repl<'g> { - fn translate_node(&self, name: NodeName) -> Result, RunCommandErr<'g>> { +impl Repl { + fn translate_node(&self, name: NodeName) -> Result { let map = self .gloc_translation_map .as_ref() @@ -45,20 +45,20 @@ impl<'g> Repl<'g> { .map(|r| *r) } - fn data_graph(&self) -> Result>, RunCommandErr<'g>> { + fn data_graph(&self) -> Result, RunCommandErr> { Ok(self.graph()?.into()) } - fn graph(&self) -> Result<&'_ Graph<'g>, RunCommandErr<'g>> { + fn graph(&self) -> Result<&'_ Graph, RunCommandErr> { self.graph.as_ref().ok_or(RunCommandErr::NoGraphLoaded) } fn create_subgraph( &self, - from: Node<'g>, + from: Node, depth: usize, direction: Direction, - ) -> Result, RunCommandErr<'g>> { + ) -> Result { let graph = self.graph()?; let mut subg = Graph::new(); subg.add_node(from); @@ -97,12 +97,12 @@ impl<'g> Repl<'g> { fn run_paths_command( &mut self, - from: Node<'g>, - to: Node<'g>, + from: Node, + to: Node, path_type: PathType, metric: PathMetric, limit: Option, - ) -> Result<(), RunCommandErr<'g>> { + ) -> Result<(), RunCommandErr> { let paths = match path_type { PathType::Both if matches!(metric, PathMetric::Shortest) => { let graph = self.graph()?; @@ -121,7 +121,7 @@ impl<'g> Repl<'g> { v }] .into_iter(), - ) as Box>>>) + ) as Box>>) } PathType::Data if matches!(metric, PathMetric::Shortest) => { let graph = self.data_graph()?; @@ -141,7 +141,7 @@ impl<'g> Repl<'g> { v }] .into_iter(), - ) as Box>>>) + ) as Box>>) } PathType::Both => Ok(Box::new(petgraph::algo::all_simple_paths::, _>( self.graph()?, @@ -149,7 +149,7 @@ impl<'g> Repl<'g> { to, 0, None, - )) as Box>>>), + )) as Box>>), PathType::Data => Ok(Box::new(petgraph::algo::all_simple_paths::, _>( self.data_graph()?, from, @@ -246,7 +246,7 @@ impl<'g> Repl<'g> { Ok(()) } - fn fn_name_for_node(&self, n: Node<'g>) -> Result, RunCommandErr<'g>> { + fn fn_name_for_node(&self, n: Node) -> Result, RunCommandErr> { if let Some(n) = n.location() { self.fn_name_for_loc(n.innermost()) } else { @@ -254,26 +254,22 @@ impl<'g> Repl<'g> { } } - fn fn_name_for_loc(&self, n: GlobalLocationS) -> Result, RunCommandErr<'g>> { + fn fn_name_for_loc(&self, n: GlobalLocationS) -> Result, RunCommandErr> { Ok(self.bodies()?.0.get(&n.function).and_then(|body| { body.1 .0 .iter() - .find(|t| t.0 == n.location) - .map(|t| t.1.as_str()) + .find(|t| t.location == n.location) + .map(|t| t.contents.as_str()) })) } - fn bodies(&self) -> Result<&'_ Bodies, RunCommandErr<'g>> { + fn bodies(&self) -> Result<&'_ Bodies, RunCommandErr> { self.bodies.as_ref().ok_or(RunCommandErr::NoGraphLoaded) } - fn run_edges>>( - &self, - g: G, - node: Node<'g>, - direction: Direction, - ) where + fn run_edges>(&self, g: G, node: Node, direction: Direction) + where G::EdgeWeight: Display, { let mut num = 0; @@ -292,7 +288,7 @@ impl<'g> Repl<'g> { println!("Found {num} edges"); } - pub fn run_command(&mut self, command: Command) -> Result<(), RunCommandErr<'g>> { + pub fn run_command(&mut self, command: Command) -> Result<(), RunCommandErr> { match command { Command::Load { path } => self.load_graph(&path), Command::DotSubgraph { @@ -495,14 +491,13 @@ impl<'g> Repl<'g> { } } - pub fn load_graph(&mut self, path: &std::path::Path) -> Result<(), RunCommandErr<'g>> { + pub fn load_graph(&mut self, path: &std::path::Path) -> Result<(), RunCommandErr> { let (flow, bodies) = dfpp::dbg::read_non_transitive_graph_and_body(std::fs::File::open(path).unwrap()); let mut g = petgraph::graphmap::GraphMap::<_, _, petgraph::Directed>::new(); let graph = &mut g; - for (to_raw, deps) in flow.location_dependencies.iter() { - let to = self.gli.from_vec(to_raw.as_slice().to_vec()).into(); + for (to, deps) in flow.location_dependencies.iter() { for (weight, deps) in deps .input_deps .iter() @@ -510,18 +505,16 @@ impl<'g> Repl<'g> { .map(|(i, deps)| (Edge::from_iter([EdgeType::Data(i as u32)]), deps)) .chain([(Edge::from_iter([EdgeType::Control]), &deps.ctrl_deps)]) { - for from_raw in deps { - let from = self.gli.from_vec(from_raw.as_slice().to_vec()).into(); - add_weighted_edge(graph, from, to, weight); + for from in deps { + add_weighted_edge(graph, (*from).into(), (*to).into(), weight); } } } - for from_raw in &flow.return_dependencies { - let from = self.gli.from_vec(from_raw.as_slice().to_vec()).into(); + for from in &flow.return_dependencies { add_weighted_edge( graph, - from, + (*from).into(), Node::return_(), Edge::from_iter([EdgeType::Data(0)]), ); diff --git a/crates/dfpp/Cargo.lock b/crates/dfpp/Cargo.lock new file mode 100644 index 0000000000..da816e3205 --- /dev/null +++ b/crates/dfpp/Cargo.lock @@ -0,0 +1,1424 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "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 = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +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 = "cc" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "clap" +version = "4.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "once_cell", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "console" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.45.0", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "dashmap" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" +dependencies = [ + "cfg-if", + "hashbrown 0.14.0", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "deranged" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" + +[[package]] +name = "dfpp" +version = "0.0.1" +dependencies = [ + "anyhow", + "camino", + "chrono", + "clap", + "dialoguer", + "dot", + "flowistry", + "humantime", + "indicatif", + "itertools", + "lazy_static", + "log", + "nom", + "num-derive", + "num-traits", + "ordermap", + "petgraph", + "pretty", + "ringbuffer", + "rustc_plugin 0.6.0-nightly-2023-04-12 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_utils 0.6.0-nightly-2023-04-12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", + "serde-lexpr", + "serde_json", + "serial_test", + "simple_logger", + "toml", + "trait_enum", +] + +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console", + "fuzzy-matcher", + "shell-words", + "tempfile", + "zeroize", +] + +[[package]] +name = "dot" +version = "0.1.4-dev" +source = "git+https://github.com/JustusAdam/dot-rust?rev=ff2b42ceda98c639c8ea3cbfc56b83d6e06e8106#ff2b42ceda98c639c8ea3cbfc56b83d6e06e8106" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flowistry" +version = "0.5.36" +source = "git+https://github.com/brownsys/flowistry?rev=f3b27bb1e06a13c599ea56beca7aa047f7d291e5#f3b27bb1e06a13c599ea56beca7aa047f7d291e5" +dependencies = [ + "anyhow", + "cfg-if", + "fluid-let", + "log", + "rustc_utils 0.6.0-nightly-2023-04-12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", +] + +[[package]] +name = "fluid-let" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749cff877dc1af878a0b31a41dd221a753634401ea0ef2f87b62d3171522485a" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "indicatif" +version = "0.17.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "intervaltree" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "270bc34e57047cab801a8c871c124d9dc7132f6473c6401f645524f4e6edd111" +dependencies = [ + "smallvec", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lexpr" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a84de6a9df442363b08f5dbf0cd5b92edc70097b89c4ce4bfea4679fe48bc67" +dependencies = [ + "itoa", + "lexpr-macros", + "ryu", +] + +[[package]] +name = "lexpr-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b5cb8bb985c81a8ac1a0f8b5c4865214f574ddd64397ef7a99c236e21f35bb" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "ordermap" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.1", +] + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap 1.9.3", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" + +[[package]] +name = "pretty" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f3aa1e3ca87d3b124db7461265ac176b40c277f37e503eaa29c9c75c037846" +dependencies = [ + "arrayvec", + "log", + "typed-arena", + "unicode-segmentation", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "ringbuffer" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e4fbb37fd18bd949f42583141d650fcdce49dbf759264e4dd3a5df0bc15dc6" + +[[package]] +name = "rustc_plugin" +version = "0.6.0-nightly-2023-04-12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b172d929863ef84797b5592af9b58160f954a484938991f5a6b2829e3c163a" +replace = "rustc_plugin 0.6.0-nightly-2023-04-12 (git+https://github.com/JustusAdam/rustc_plugin?rev=344ecb3bc056c641eaf9d06792571b3d81c8eb33)" + +[[package]] +name = "rustc_plugin" +version = "0.6.0-nightly-2023-04-12" +source = "git+https://github.com/JustusAdam/rustc_plugin?rev=344ecb3bc056c641eaf9d06792571b3d81c8eb33#344ecb3bc056c641eaf9d06792571b3d81c8eb33" +dependencies = [ + "cargo_metadata", + "log", + "rustc_tools_util", + "serde", + "serde_json", + "toml", +] + +[[package]] +name = "rustc_tools_util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3c5a95edfa0c893236ae4778bb7c4752760e4c0d245e19b5eff33c5aa5eb9dc" + +[[package]] +name = "rustc_utils" +version = "0.6.0-nightly-2023-04-12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3935b4a82abe6904308c9273afba6160cf36f20044e720c43839a08519eadfd8" +replace = "rustc_utils 0.6.0-nightly-2023-04-12 (git+https://github.com/JustusAdam/rustc_plugin?rev=344ecb3bc056c641eaf9d06792571b3d81c8eb33)" + +[[package]] +name = "rustc_utils" +version = "0.6.0-nightly-2023-04-12" +source = "git+https://github.com/JustusAdam/rustc_plugin?rev=344ecb3bc056c641eaf9d06792571b3d81c8eb33#344ecb3bc056c641eaf9d06792571b3d81c8eb33" +dependencies = [ + "anyhow", + "cfg-if", + "intervaltree", + "log", +] + +[[package]] +name = "rustix" +version = "0.38.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-lexpr" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4cda13396159f59e7946118cdac0beadeecfb7cf76b197f4147e546f4ead6f" +dependencies = [ + "lexpr", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "simple_logger" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48047e77b528151aaf841a10a9025f9459da80ba820e425ff7eb005708a76dc7" +dependencies = [ + "atty", + "colored", + "log", + "time 0.3.25", + "winapi", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +dependencies = [ + "deranged", + "itoa", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +dependencies = [ + "time-core", +] + +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "trait_enum" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "130dd741d3c71f76d031e58caffff3624eaaa2db9bd8c4b05406a71885300fc7" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5504cc7644f4b593cbc05c4a55bf9bd4e94b867c3c0bd440934174d50482427d" +dependencies = [ + "memchr", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/crates/dfpp/Cargo.toml b/crates/dfpp/Cargo.toml new file mode 100644 index 0000000000..b09f71caa5 --- /dev/null +++ b/crates/dfpp/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "dfpp" +version = "0.0.1" +edition = "2021" +publish = false +description = "A linter for user-defined privacy properties for Rust code" + +[package.metadata.rust-analyzer] +rustc_private = true + +[features] +test = [] + +[dependencies] +dfgraph = { path = "../dfgraph", features = ["rustc"] } + +#flowistry = { git = "https://github.com/willcrichton/flowistry", rev = "1759ef8" } +#flowistry = { path = "../flowistry/crates/flowistry" } +flowistry = { git = "https://github.com/brownsys/flowistry", rev = "f3b27bb1e06a13c599ea56beca7aa047f7d291e5" } + +#rustc_plugin = { git = "https://github.com/willcrichton/flowistry", rev = "1f469a4cce9f2e240ad14b5145669a8011d4e6b2" } +#rustc_plugin = { path = "../rustc_plugin/crates/rustc_plugin" } +#rustc_plugin = { git = "https://github.com/brownsys/flowistry", rev = "6e1de0459ec32bfd9ad046491a556410942d6ddc" } +#rustc_utils = { path = "../rustc_plugin/crates/rustc_utils"} +rustc_utils = "=0.6.0-nightly-2023-04-12" +rustc_plugin = "=0.6.0-nightly-2023-04-12" + +clap = { version = "=4.3.24", features = ["derive", "cargo", "env"] } +serde = { workspace = true, features = ["derive"] } +lazy_static = "1" +ordermap = "0.3" +trait_enum = "0.5" +pretty = "0.11" +nom = "7" +log = "0.4" +simple_logger = "2" +num-derive = "0.4" +num-traits = "0.2" +petgraph = "0.6" +humantime = "2" + + +#dot = "0.1" +dot = { git = "https://github.com/JustusAdam/dot-rust", rev = "ff2b42ceda98c639c8ea3cbfc56b83d6e06e8106"} +#dot = {path = "../../clones/dot-rust" } + +serde_bare = "0.5.0" +serde_json = "1" +toml = "0.7" + + + +# This is just for pinning this dependency +camino = "= 1.0.9" +serial_test = "2.0.0" +itertools = "0.11.0" +anyhow = "1.0.72" + +[build-dependencies] +chrono = "0.4" + +[dev-dependencies] +dfpp = {path = ".", features = ["test"]} + +[[bin]] +name = "cargo-dfpp" + +[[bin]] +name = "dfpp" diff --git a/build.rs b/crates/dfpp/build.rs similarity index 99% rename from build.rs rename to crates/dfpp/build.rs index 6bf94fb0ef..66d3992268 100644 --- a/build.rs +++ b/crates/dfpp/build.rs @@ -3,7 +3,7 @@ use std::process::Command; extern crate chrono; use std::env; -const COMPILER_DEPENDENT_BINARIES: &[&str] = &["dfpp", "cargo-dfpp", "dfpp-explorer"]; +const COMPILER_DEPENDENT_BINARIES: &[&str] = &["dfpp", "cargo-dfpp"]; fn add_link_arg_for_compiler_binaries(s: impl std::fmt::Display) { for bin in COMPILER_DEPENDENT_BINARIES { diff --git a/src/ana/abstract_memory.rs b/crates/dfpp/src/ana/abstract_memory.rs similarity index 100% rename from src/ana/abstract_memory.rs rename to crates/dfpp/src/ana/abstract_memory.rs diff --git a/src/ana/algebra.rs b/crates/dfpp/src/ana/algebra.rs similarity index 100% rename from src/ana/algebra.rs rename to crates/dfpp/src/ana/algebra.rs diff --git a/src/ana/df.rs b/crates/dfpp/src/ana/df.rs similarity index 97% rename from src/ana/df.rs rename to crates/dfpp/src/ana/df.rs index 079bb6a8be..ec71bbd333 100644 --- a/src/ana/df.rs +++ b/crates/dfpp/src/ana/df.rs @@ -1,7 +1,6 @@ use std::{borrow::Cow, cell::RefCell, fmt::Display, rc::Rc}; use crate::{ - ir::global_location::{GliAt, GLI}, mir::{self, visit::Visitor, *}, rustc_data_structures::fx::FxHashSet as HashSet, rustc_hir::{def_id::DefId, BodyId}, @@ -221,8 +220,8 @@ where use super::algebra; -pub type FlowResults<'a, 'tcx, 'g, 'inliner> = - engine::AnalysisResults<'tcx, FlowAnalysis<'a, 'tcx, 'g, 'inliner>>; +pub type FlowResults<'a, 'tcx, 'inliner> = + engine::AnalysisResults<'tcx, FlowAnalysis<'a, 'tcx, 'inliner>>; pub type Dependency<'tcx> = (LocationOrArgIndex, Place<'tcx>); pub type LocationSet<'tcx> = HashSet>; @@ -302,33 +301,27 @@ impl<'tcx> JoinSemiLattice for FlowDomain<'tcx> { } } -pub struct FlowAnalysis<'a, 'tcx, 'g, 's> { +pub struct FlowAnalysis<'a, 'tcx, 's> { pub tcx: TyCtxt<'tcx>, pub def_id: DefId, pub body: &'a Body<'tcx>, pub control_dependencies: ControlDependencies, pub aliases: Aliases<'a, 'tcx>, - pub gli: GLI<'g>, carries_marker: &'s InlineJudge<'tcx>, recurse_cache: RecursionBreakingCache>, elision_info: RefCell>>, } -impl<'a, 'tcx, 'g, 's> FlowAnalysis<'a, 'tcx, 'g, 's> { +impl<'a, 'tcx, 's> FlowAnalysis<'a, 'tcx, 's> { pub fn elision_info( &self, ) -> impl std::ops::Deref>> + '_ { self.elision_info.borrow() } - fn body_id(&self) -> BodyId { - self.tcx.hir().body_owned_by(self.def_id.expect_local()) - } - #[allow(clippy::too_many_arguments)] pub fn new( tcx: TyCtxt<'tcx>, - gli: GLI<'g>, def_id: DefId, body: &'a Body<'tcx>, aliases: Aliases<'a, 'tcx>, @@ -337,7 +330,6 @@ impl<'a, 'tcx, 'g, 's> FlowAnalysis<'a, 'tcx, 'g, 's> { ) -> Self { FlowAnalysis { tcx, - gli, def_id, body, aliases, @@ -352,9 +344,9 @@ impl<'a, 'tcx, 'g, 's> FlowAnalysis<'a, 'tcx, 'g, 's> { self.aliases.location_domain() } - pub fn gli_at(&self, location: Location) -> GliAt<'g> { - self.gli.at(location, self.body_id()) - } + // pub fn gli_at(&self, location: Location) -> GliAt<'g> { + // self.gli.at(location, self.body_id()) + // } pub fn location_to_index(&self, location: Location) -> LocationOrArgIndex { self.location_domain() @@ -691,7 +683,7 @@ impl<'a, 'tcx, 'g, 's> FlowAnalysis<'a, 'tcx, 'g, 's> { } } -impl<'a, 'tcx, 'g, 'inliner> AnalysisDomain<'tcx> for FlowAnalysis<'a, 'tcx, 'g, 'inliner> { +impl<'a, 'tcx, 'inliner> AnalysisDomain<'tcx> for FlowAnalysis<'a, 'tcx, 'inliner> { type Domain = FlowDomain<'tcx>; type Direction = Forward; const NAME: &'static str = "FlowAnalysis"; @@ -715,7 +707,7 @@ impl<'a, 'tcx, 'g, 'inliner> AnalysisDomain<'tcx> for FlowAnalysis<'a, 'tcx, 'g, } } -impl<'a, 'tcx, 'g, 'inliner> Analysis<'tcx> for FlowAnalysis<'a, 'tcx, 'g, 'inliner> { +impl<'a, 'tcx, 'inliner> Analysis<'tcx> for FlowAnalysis<'a, 'tcx, 'inliner> { fn apply_statement_effect( &self, state: &mut Self::Domain, @@ -781,13 +773,12 @@ impl<'a, 'tcx, 'g, 'inliner> Analysis<'tcx> for FlowAnalysis<'a, 'tcx, 'g, 'inli } } -pub fn compute_flow_internal<'a, 'tcx, 'g, 's>( +pub fn compute_flow_internal<'a, 'tcx, 's>( tcx: TyCtxt<'tcx>, - gli: GLI<'g>, body_id: BodyId, body_with_facts: &'a CachedSimplifedBodyWithFacts<'tcx>, carries_marker: &'s InlineJudge<'tcx>, -) -> FlowResults<'a, 'tcx, 'g, 's> { +) -> FlowResults<'a, 'tcx, 's> { //flowistry::infoflow::BODY_STACK.with(|body_stack| { //body_stack.borrow_mut().push(body_id); // debug!( @@ -810,7 +801,6 @@ pub fn compute_flow_internal<'a, 'tcx, 'g, 's>( let analysis = FlowAnalysis::new( tcx, - gli, def_id, body, aliases, diff --git a/src/ana/inline/graph.rs b/crates/dfpp/src/ana/inline/graph.rs similarity index 92% rename from src/ana/inline/graph.rs rename to crates/dfpp/src/ana/inline/graph.rs index d35e7d1388..58f20d1676 100644 --- a/src/ana/inline/graph.rs +++ b/crates/dfpp/src/ana/inline/graph.rs @@ -1,5 +1,5 @@ use crate::{ - ir::{regal, GlobalLocation, GLI}, + ir::{regal, GlobalLocation}, mir, serde, utils::{time, write_sep, DisplayViaDebug, FnResolution, IntoDefId, TinyBitSet}, BodyId, Either, HashMap, HashSet, Location, TyCtxt, @@ -176,7 +176,15 @@ impl std::fmt::Display for Edge { } } -impl<'g> GlobalLocal<'g> { +/// A [`mir::Local`] but also tracks the precise call chain it is reachable +/// from. +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)] +pub struct GlobalLocal { + pub(super) local: mir::Local, + location: Option, +} + +impl GlobalLocal { /// Construct a new global local in a root function (no call chain) pub fn at_root(local: mir::Local) -> Self { Self { @@ -186,34 +194,13 @@ impl<'g> GlobalLocal<'g> { } /// Construct a new global local relative to this call chain. - pub fn relative(local: mir::Local, location: GlobalLocation<'g>) -> Self { + pub fn relative(local: mir::Local, location: GlobalLocation) -> Self { Self { local, location: Some(location), } } -} - -impl std::fmt::Display for GlobalLocal<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?} @ ", self.local)?; - if let Some(loc) = self.location { - write!(f, "{}", loc) - } else { - f.write_str("root") - } - } -} -/// A [`mir::Local`] but also tracks the precise call chain it is reachable -/// from. -#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)] -pub struct GlobalLocal<'g> { - pub(super) local: mir::Local, - location: Option>, -} - -impl<'g> GlobalLocal<'g> { /// Access to the variable name. #[inline] pub fn local(self) -> mir::Local { @@ -222,11 +209,22 @@ impl<'g> GlobalLocal<'g> { /// Access to the call chain. #[inline] - pub fn location(self) -> Option> { + pub fn location(self) -> Option { self.location } } +impl std::fmt::Display for GlobalLocal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?} @ ", self.local)?; + if let Some(loc) = self.location { + write!(f, "{}", loc) + } else { + f.write_str("root") + } + } +} + /// Common structure of equations used for inlining. pub type Equation = algebra::Equality>; /// Common structure of a collection of equations used for inlining. @@ -235,20 +233,20 @@ pub type Equations = Vec>; pub type GraphImpl<'tcx, L> = pg::GraphMap)>, Edge, pg::Directed>; /// A graph that has its subgraphs inlined (or is in the process of it). -pub struct InlinedGraph<'tcx, 'g> { +pub struct InlinedGraph<'tcx> { /// The global graph - pub(super) graph: GraphImpl<'tcx, GlobalLocation<'g>>, + pub(super) graph: GraphImpl<'tcx, GlobalLocation>, /// The global equations - pub equations: Equations>, + pub equations: Equations, /// For statistics, how many functions did we inline pub(super) num_inlined: usize, /// For statistics: how deep a calll stack did we inline. pub(super) max_call_stack_depth: usize, } -impl<'tcx, 'g> InlinedGraph<'tcx, 'g> { +impl<'tcx> InlinedGraph<'tcx> { /// Access the actual graph. - pub fn graph(&self) -> &GraphImpl<'tcx, GlobalLocation<'g>> { + pub fn graph(&self) -> &GraphImpl<'tcx, GlobalLocation> { &self.graph } @@ -277,13 +275,12 @@ impl<'tcx, 'g> InlinedGraph<'tcx, 'g> { /// Construct the initial graph from a [`regal::Body`] pub fn from_body( - gli: GLI<'g>, body_id: BodyId, body: ®al::Body<'tcx, DisplayViaDebug>, tcx: TyCtxt<'tcx>, ) -> Self { time("Graph Construction From Regal Body", || { - let equations = to_global_equations(&body.equations, body_id, gli); + let equations = to_global_equations(&body.equations, body_id); let mut gwr = InlinedGraph { equations, graph: Default::default(), @@ -304,7 +301,7 @@ impl<'tcx, 'g> InlinedGraph<'tcx, 'g> { use regal::Target; let from = match d { Target::Call(c) => regal::SimpleLocation::Call(( - gli.globalize_location(**c, body_id), + GlobalLocation::single(**c, body_id), *call_map.get(c).unwrap_or_else(|| { panic!( "Expected to find call at {c} in function {}", @@ -325,7 +322,7 @@ impl<'tcx, 'g> InlinedGraph<'tcx, 'g> { }; for (&loc, call) in body.calls.iter() { - let n = Node::Call((gli.globalize_location(*loc, body_id), call.function)); + let n = Node::Call((GlobalLocation::single(*loc, body_id), call.function)); for (idx, deps) in call.arguments.iter().enumerate() { if let Some((_, deps)) = deps { add_dep_edges(n, EdgeType::Data(idx as u32), deps) @@ -344,11 +341,10 @@ impl<'tcx, 'g> InlinedGraph<'tcx, 'g> { } /// Globalize all locations mentioned in these equations. -fn to_global_equations<'g>( +fn to_global_equations( eqs: &Equations>, _body_id: BodyId, - _gli: GLI<'g>, -) -> Equations> { +) -> Equations { eqs.iter() .map(|eq| eq.map_bases(|target| GlobalLocal::at_root(**target))) .collect() diff --git a/src/ana/inline/judge.rs b/crates/dfpp/src/ana/inline/judge.rs similarity index 100% rename from src/ana/inline/judge.rs rename to crates/dfpp/src/ana/inline/judge.rs diff --git a/src/ana/inline/mod.rs b/crates/dfpp/src/ana/inline/mod.rs similarity index 89% rename from src/ana/inline/mod.rs rename to crates/dfpp/src/ana/inline/mod.rs index 5df0ef4084..c26fde069e 100644 --- a/src/ana/inline/mod.rs +++ b/crates/dfpp/src/ana/inline/mod.rs @@ -19,9 +19,8 @@ use crate::{ hir::BodyId, ir::{ flows::CallOnlyFlow, - global_location::IsGlobalLocation, regal::{self, SimpleLocation}, - GliAt, GlobalLocation, GLI, + GlobalLocation, GlobalLocationS, }, mir, mir::Location, @@ -52,12 +51,12 @@ use petgraph::{ pub use judge::InlineJudge; -type StdNode<'tcx, 'g> = Node<(GlobalLocation<'g>, FnResolution<'tcx>)>; +type StdNode<'tcx> = Node<(GlobalLocation, FnResolution<'tcx>)>; -type EdgeSet<'tcx, 'g> = HashSet<(StdNode<'tcx, 'g>, StdNode<'tcx, 'g>)>; +type EdgeSet<'tcx> = HashSet<(StdNode<'tcx>, StdNode<'tcx>)>; -impl<'tcx, 'g> Inliner<'tcx, 'g> { - fn edge_has_been_pruned_before(from: StdNode<'tcx, 'g>, to: StdNode<'tcx, 'g>) -> bool { +impl<'tcx> Inliner<'tcx> { + fn edge_has_been_pruned_before(from: StdNode<'tcx>, to: StdNode<'tcx>) -> bool { match (to, from) { (SimpleLocation::Call(c1), SimpleLocation::Call(c2)) => { c1.0.outermost() == c2.0.outermost() @@ -67,7 +66,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { } } - fn find_prunable_edges(graph: &InlinedGraph<'tcx, 'g>) -> EdgeSet<'tcx, 'g> { + fn find_prunable_edges(graph: &InlinedGraph<'tcx>) -> EdgeSet<'tcx> { let graph = &graph.graph; graph .all_edges() @@ -86,9 +85,9 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { /// that `r = *a.foo`. fn prune_impossible_edges( &self, - graph: &mut InlinedGraph<'tcx, 'g>, + graph: &mut InlinedGraph<'tcx>, name: Symbol, - edges_to_prune: &EdgeSet<'tcx, 'g>, + edges_to_prune: &EdgeSet<'tcx>, id: LocalDefId, ) { if edges_to_prune.is_empty() { @@ -136,7 +135,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { Node::Return => unreachable!(), Node::Call((location, _did)) => Either::Left({ let call = self.get_call(location); - let parent = location.parent(self.gli); + let parent = location.parent(); call.argument_locals() .chain(call.return_to.into_iter()) .map(move |local| { @@ -182,15 +181,14 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { type BodyCache<'tcx> = Cache>>; /// Essentially just a bunch of caches of analyses. -pub struct Inliner<'tcx, 'g> { +pub struct Inliner<'tcx> { /// Memoized graphs created from single-procedure analyses base_memo: BodyCache<'tcx>, /// Memoized graphs that have all their callees inlined. Unlike `base_memo` /// this has to be recursion breaking, since a function may call itself /// (possibly transitively). - inline_memo: RecursionBreakingCache>, + inline_memo: RecursionBreakingCache>, tcx: TyCtxt<'tcx>, - gli: GLI<'g>, ana_ctrl: &'static AnalysisCtrl, dbg_ctrl: &'static DumpArgs, marker_carrying: InlineJudge<'tcx>, @@ -292,17 +290,15 @@ enum DropAction { WrapReturn(Vec>>), } -impl<'tcx, 'g> Inliner<'tcx, 'g> { +impl<'tcx> Inliner<'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - gli: GLI<'g>, marker_ctx: MarkerCtx<'tcx>, ana_ctrl: &'static AnalysisCtrl, dbg_ctrl: &'static DumpArgs, ) -> Self { Self { tcx, - gli, base_memo: Default::default(), inline_memo: Default::default(), ana_ctrl, @@ -328,23 +324,17 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { body_id: BodyId, ) -> ®al::Body<'tcx, DisplayViaDebug> { self.base_memo.get(body_id, |bid| { - regal::compute_from_body_id( - self.dbg_ctrl, - bid, - self.tcx, - self.gli, - &self.marker_carrying, - ) + regal::compute_from_body_id(self.dbg_ctrl, bid, self.tcx, &self.marker_carrying) }) } /// Compute an inlined graph for this `body_id` (memoized) - pub fn get_inlined_graph(&self, body_id: BodyId) -> Option<&InlinedGraph<'tcx, 'g>> { + pub fn get_inlined_graph(&self, body_id: BodyId) -> Option<&InlinedGraph<'tcx>> { self.inline_memo.get(body_id, |bid| self.inline_graph(bid)) } /// Convenience wrapper around [`Self::get_inlined_graph`] - fn get_inlined_graph_by_def_id(&self, def_id: LocalDefId) -> Option<&InlinedGraph<'tcx, 'g>> { + fn get_inlined_graph_by_def_id(&self, def_id: LocalDefId) -> Option<&InlinedGraph<'tcx>> { let hir = self.tcx.hir(); let body_id = match hir.maybe_body_owned_by(def_id) { None => { @@ -360,16 +350,18 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { } /// Make the set of equations relative to the call site described by `gli` - fn relativize_eqs<'a>( - equations: &'a Equations>, - gli: &'a GliAt<'g>, - ) -> impl Iterator>> + 'a { + fn relativize_eqs( + equations: &Equations, + here: GlobalLocationS, + ) -> impl Iterator> + '_ { equations.iter().map(move |eq| { eq.map_bases(|base| { GlobalLocal::relative( base.local(), - base.location() - .map_or_else(|| gli.as_global_location(), |prior| gli.relativize(prior)), + base.location().map_or_else( + || GlobalLocation::single(here.location, here.function), + |prior| here.relativize(prior), + ), ) }) }) @@ -378,7 +370,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { /// Get the `regal` call description for the call site at a specific location. fn get_call( &self, - loc: GlobalLocation<'g>, + loc: GlobalLocation, ) -> ®al::Call<'tcx, regal::Dependencies>> { let body = self.get_procedure_graph(loc.innermost_function()); &body.calls[&DisplayViaDebug(loc.innermost_location())] @@ -387,7 +379,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { /// Calculate the global local that corresponds to input index `idx` at this `node`. /// /// If the node is not a [`SimpleLocation::Call`], then the index is ignored. - fn node_to_local(&self, node: &StdNode<'tcx, 'g>, idx: ArgNum) -> GlobalLocal<'g> { + fn node_to_local(&self, node: &StdNode<'tcx>, idx: ArgNum) -> GlobalLocal { match node { SimpleLocation::Return => GlobalLocal::at_root(mir::RETURN_PLACE), SimpleLocation::Argument(idx) => GlobalLocal::at_root((*idx).into()), @@ -397,7 +389,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { .as_ref() .map(|i| i.0) .unwrap(); - if let Some(parent) = loc.parent(self.gli) { + if let Some(parent) = loc.parent() { GlobalLocal::relative(pure_local, parent) } else { GlobalLocal::at_root(pure_local) @@ -418,8 +410,8 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { fn classify_special_function_handling( &self, function: DefId, - id: StdNode<'tcx, 'g>, - g: &GraphImpl<'tcx, GlobalLocation<'g>>, + id: StdNode<'tcx>, + g: &GraphImpl<'tcx, GlobalLocation>, ) -> Option { if self.ana_ctrl.drop_poll() && let Some(maybe_wrap) = is_part_of_async_desugar(self.tcx, id, g) { @@ -435,11 +427,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { } } - fn try_inline_as_async_fn( - &self, - i_graph: &mut InlinedGraph<'tcx, 'g>, - body_id: BodyId, - ) -> bool { + fn try_inline_as_async_fn(&self, i_graph: &mut InlinedGraph<'tcx>, body_id: BodyId) -> bool { let local_def_id = body_id.into_local_def_id(self.tcx); let body_with_facts = borrowck_facts::get_simplified_body_with_borrowck_facts(self.tcx, local_def_id); @@ -474,7 +462,7 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { _ => unreachable!(), }; - let root_location = self.gli.globalize_location(return_location, body_id); + let root_location = GlobalLocation::single(return_location, body_id); // Following we must sumilate two code rewrites to the body of this // function to simulate calling the closure. We make the closure @@ -534,15 +522,15 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { equations: eqs, num_inlined, max_call_stack_depth, - }: &mut InlinedGraph<'tcx, 'g>, + }: &mut InlinedGraph<'tcx>, caller_function: BodyId, inlining_target: LocalDefId, - incoming: &[(StdNode<'tcx, 'g>, Edge)], - outgoing: &[(StdNode<'tcx, 'g>, Edge)], + incoming: &[(StdNode<'tcx>, Edge)], + outgoing: &[(StdNode<'tcx>, Edge)], arguments: &[Option], return_to: Option, - queue_for_pruning: &mut EdgeSet<'tcx, 'g>, - root_location: GlobalLocation<'g>, + queue_for_pruning: &mut EdgeSet<'tcx>, + root_location: GlobalLocation, ) { let grw_to_inline = if let Some(callee_graph) = self.get_inlined_graph_by_def_id(inlining_target) { @@ -574,11 +562,12 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { } } - let gli_here = self - .gli - .at(root_location.outermost_location(), caller_function); + let here = GlobalLocationS { + function: caller_function, + location: root_location.outermost_location(), + }; eqs.extend( - Self::relativize_eqs(&grw_to_inline.equations, &gli_here).chain( + Self::relativize_eqs(&grw_to_inline.equations, here).chain( arguments .iter() .enumerate() @@ -594,36 +583,37 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { ); let to_inline = &grw_to_inline.graph; - let mut connect_to = - |g: &mut GraphImpl<'tcx, _>, source, target, weight: Edge, pruning_required| { - let mut add_edge = |source, register_for_pruning| { - debug!("Connecting {source} -> {target}"); - if register_for_pruning { - queue_for_pruning.insert((source, target)); - } - add_weighted_edge(g, source, target, weight) - }; - match source { - Node::Call((loc, did)) => add_edge( - Node::Call((gli_here.relativize(loc), did)), - pruning_required, - ), - Node::Return => unreachable!(), - Node::Argument(a) => { - for nidx in argument_map - .get(&EdgeType::Data(a.as_usize() as u32)) - .unwrap_or_else(|| panic!("Could not find {a} in arguments")) - .iter() - { - add_edge(*nidx, true) - } - } + let mut connect_to = |g: &mut GraphImpl<'tcx, _>, + source: SimpleLocation<(GlobalLocation, _)>, + target, + weight: Edge, + pruning_required| { + let mut add_edge = |source, register_for_pruning| { + debug!("Connecting {source} -> {target}"); + if register_for_pruning { + queue_for_pruning.insert((source, target)); } + add_weighted_edge(g, source, target, weight) }; + match source { + Node::Call((loc, did)) => { + add_edge(Node::Call((here.relativize(loc), did)), pruning_required) + } + Node::Return => unreachable!(), + Node::Argument(a) => { + for nidx in argument_map + .get(&EdgeType::Data(a.as_usize() as u32)) + .unwrap_or_else(|| panic!("Could not find {a} in arguments")) + .iter() + { + add_edge(*nidx, true) + } + } + } + }; for old in to_inline.nodes() { - let new = - old.map_call(|(location, function)| (gli_here.relativize(*location), *function)); + let new = old.map_call(|(location, function)| (here.relativize(*location), *function)); g.add_node(new); debug!( "Handling {old} (now {new}) {} incoming edges", @@ -651,9 +641,9 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { fn perform_subfunction_inlining( &self, proc_g: ®al::Body>, - i_graph: &mut InlinedGraph<'tcx, 'g>, + i_graph: &mut InlinedGraph<'tcx>, body_id: BodyId, - ) -> EdgeSet<'tcx, 'g> { + ) -> EdgeSet<'tcx> { let recursive_analysis_enabled = self.ana_ctrl.use_recursive_analysis(); let mut queue_for_pruning = HashSet::new(); if recursive_analysis_enabled && self.try_inline_as_async_fn(i_graph, body_id) { @@ -789,9 +779,9 @@ impl<'tcx, 'g> Inliner<'tcx, 'g> { /// In spite of the name of this function it not only inlines the graph but /// also first creates it (with [`Self::get_procedure_graph`]) and globalize /// it ([`to_global_graph`]). - fn inline_graph(&self, body_id: BodyId) -> InlinedGraph<'tcx, 'g> { + fn inline_graph(&self, body_id: BodyId) -> InlinedGraph<'tcx> { let proc_g = self.get_procedure_graph(body_id); - let mut gwr = InlinedGraph::from_body(self.gli, body_id, proc_g, self.tcx); + let mut gwr = InlinedGraph::from_body(body_id, proc_g, self.tcx); let name = body_name_pls(self.tcx, body_id).name; if self.dbg_ctrl.dump_pre_inline_graph() { @@ -873,14 +863,14 @@ fn dump_dot_graph(mut w: W, g: &InlinedGraph) -> std::io::Res ) } -impl<'tcx, 'g> Inliner<'tcx, 'g> { +impl<'tcx> Inliner<'tcx> { /// Turn the output of the inliner into the format the rest of the dfpp pipeline /// understands. - pub fn to_call_only_flow GlobalLocation<'g>>( + pub fn to_call_only_flow GlobalLocation>( &self, - InlinedGraph { graph: g, .. }: &InlinedGraph<'tcx, 'g>, + InlinedGraph { graph: g, .. }: &InlinedGraph<'tcx>, mut mk_arg: A, - ) -> crate::ir::CallOnlyFlow> { + ) -> crate::ir::CallOnlyFlow { let mut location_dependencies = HashMap::new(); let mut return_dependencies = HashSet::new(); diff --git a/src/ana/mod.rs b/crates/dfpp/src/ana/mod.rs similarity index 95% rename from src/ana/mod.rs rename to crates/dfpp/src/ana/mod.rs index 42560aa177..97c0d4b526 100644 --- a/src/ana/mod.rs +++ b/crates/dfpp/src/ana/mod.rs @@ -36,13 +36,12 @@ impl<'tcx> CollectingVisitor<'tcx> { /// Perform the analysis for one `#[dfpp::analyze]` annotated function and /// return the representation suitable for emitting into Forge. - fn handle_target<'g>( + fn handle_target( &self, //_hash_verifications: &mut HashVerifications, call_site_annotations: &mut CallSiteAnnotations, target: FnToAnalyze, - gli: GLI<'g>, - inliner: &inline::Inliner<'tcx, 'g>, + inliner: &inline::Inliner<'tcx>, ) -> std::io::Result<(Endpoint, Ctrl)> { let mut flows = Ctrl::default(); let local_def_id = self.tcx.hir().body_owner_def_id(target.body_id); @@ -78,7 +77,7 @@ impl<'tcx> CollectingVisitor<'tcx> { let i = inliner.get_inlined_graph(target.body_id).unwrap(); info!("Graph statistics for {}\n {: CollectingVisitor<'tcx> { let subtypes = self .marker_ctx .all_type_markers(ty) - .map(|t| Identifier::new(t.0.marker)) + .map(|t| t.0.marker) .collect::>(); (DataSource::Argument(l.as_usize() - 1), subtypes) }); @@ -196,7 +195,7 @@ impl<'tcx> CollectingVisitor<'tcx> { // Add ctrl flows to callsite. for dep in deps.ctrl_deps.iter() { flows.add_ctrl_flow( - Cow::Owned(dep.as_data_source(tcx, check_realness)), + Cow::Owned(data_source_from_global_location(*dep, tcx, check_realness)), call_site.clone(), ) } @@ -224,7 +223,7 @@ impl<'tcx> CollectingVisitor<'tcx> { for dep in arg_deps.iter() { debug!(" to {dep}"); flows.add_data_flow( - Cow::Owned(dep.as_data_source(tcx, check_realness)), + Cow::Owned(data_source_from_global_location(*dep, tcx, check_realness)), to.clone(), ); } @@ -232,7 +231,7 @@ impl<'tcx> CollectingVisitor<'tcx> { } for dep in flow.return_dependencies.iter() { flows.add_data_flow( - Cow::Owned(dep.as_data_source(tcx, check_realness)), + Cow::Owned(data_source_from_global_location(*dep, tcx, check_realness)), DataSink::Return, ); } @@ -245,9 +244,6 @@ impl<'tcx> CollectingVisitor<'tcx> { /// /// Should only be called after the visit. fn analyze(mut self) -> std::io::Result { - let arena = rustc_arena::TypedArena::default(); - let interner = GlobalLocationInterner::new(&arena); - let gli = GLI::new(&interner); let tcx = self.tcx; let mut targets = std::mem::take(&mut self.functions_to_analyze); @@ -265,7 +261,6 @@ impl<'tcx> CollectingVisitor<'tcx> { let inliner = inline::Inliner::new( self.tcx, - gli, self.marker_ctx.clone(), self.opts.anactrl(), self.opts.dbg(), @@ -282,7 +277,6 @@ impl<'tcx> CollectingVisitor<'tcx> { //hash_verifications, &mut call_site_annotations, desc, - gli, &inliner, ) }) diff --git a/src/ana/non_transitive_aliases.rs b/crates/dfpp/src/ana/non_transitive_aliases.rs similarity index 100% rename from src/ana/non_transitive_aliases.rs rename to crates/dfpp/src/ana/non_transitive_aliases.rs diff --git a/src/ann_parse.rs b/crates/dfpp/src/ann_parse.rs similarity index 99% rename from src/ann_parse.rs rename to crates/dfpp/src/ann_parse.rs index 923e71d0c9..26b655dfb6 100644 --- a/src/ann_parse.rs +++ b/crates/dfpp/src/ann_parse.rs @@ -20,6 +20,7 @@ use crate::{ Symbol, }; use ast::{token, tokenstream}; +use dfgraph::Identifier; use token::*; use tokenstream::*; @@ -312,7 +313,7 @@ pub(crate) fn ann_match_fn(ann: &rustc_ast::AttrArgs) -> MarkerAnnotation { let (i, refinement) = nom::combinator::cond(cont.is_some(), refinements_parser)(i)?; let (_, _) = nom::combinator::eof(i)?; Ok(MarkerAnnotation { - marker: label, + marker: Identifier::new(label), refinement: refinement.unwrap_or_else(MarkerRefinement::empty), }) }; diff --git a/src/args.rs b/crates/dfpp/src/args.rs similarity index 100% rename from src/args.rs rename to crates/dfpp/src/args.rs diff --git a/src/bin/cargo-dfpp.rs b/crates/dfpp/src/bin/cargo-dfpp.rs similarity index 100% rename from src/bin/cargo-dfpp.rs rename to crates/dfpp/src/bin/cargo-dfpp.rs diff --git a/src/bin/dfpp.rs b/crates/dfpp/src/bin/dfpp.rs similarity index 100% rename from src/bin/dfpp.rs rename to crates/dfpp/src/bin/dfpp.rs diff --git a/src/consts.rs b/crates/dfpp/src/consts.rs similarity index 100% rename from src/consts.rs rename to crates/dfpp/src/consts.rs diff --git a/src/dbg.rs b/crates/dfpp/src/dbg.rs similarity index 88% rename from src/dbg.rs rename to crates/dfpp/src/dbg.rs index 673f7aa6f9..177313983c 100644 --- a/src/dbg.rs +++ b/crates/dfpp/src/dbg.rs @@ -8,10 +8,11 @@ //! to stdout, a file or a log statement. Some take additional information (such //! as [TyCtxt]) to get contextual information that is used to make the output //! more useful. +use dfgraph::Identifier; use flowistry::indexed::IndexedDomain; use crate::{ - ir::{CallOnlyFlow, GlobalLocation, GlobalLocationS, IsGlobalLocation}, + ir::CallOnlyFlow, rust::{mir, TyCtxt}, utils::body_name_pls, HashMap, HashSet, @@ -68,7 +69,7 @@ pub mod call_only_flow_dot { use std::collections::HashSet; use crate::{ - ir::{CallOnlyFlow, GlobalLocation, GlobalLocationS, IsGlobalLocation}, + ir::{CallOnlyFlow, GlobalLocation, GlobalLocationS}, rust::mir::{Statement, StatementKind}, rust::TyCtxt, utils::{identifier_for_item, AsFnAndArgs, DfppBodyExt, LocationExt}, @@ -76,11 +77,11 @@ pub mod call_only_flow_dot { }; /// `None` encodes the return state of the function - pub type N<'g> = Option>; + pub type N = Option; #[derive(Clone)] - pub struct E<'g> { - from: N<'g>, - to: N<'g>, + pub struct E { + from: N, + to: N, into: To, } #[derive(Clone, PartialEq, Eq)] @@ -94,10 +95,8 @@ pub mod call_only_flow_dot { detailed: bool, } - impl<'a, 'tcx, 'g> dot::GraphWalk<'a, N<'g>, E<'g>> - for G<'tcx, 'g, CallOnlyFlow>> - { - fn nodes(&'a self) -> dot::Nodes<'a, N<'g>> { + impl<'a, 'tcx, 'g> dot::GraphWalk<'a, N, E> for G<'tcx, 'g, CallOnlyFlow> { + fn nodes(&'a self) -> dot::Nodes<'a, N> { self.graph .location_dependencies .iter() @@ -113,7 +112,7 @@ pub mod call_only_flow_dot { .collect::>() .into() } - fn edges(&'a self) -> dot::Edges<'a, E<'g>> { + fn edges(&'a self) -> dot::Edges<'a, E> { self.graph .location_dependencies .iter() @@ -136,39 +135,39 @@ pub mod call_only_flow_dot { .collect::>() .into() } - fn source(&'a self, edge: &E<'g>) -> N<'g> { + fn source(&'a self, edge: &E) -> N { edge.from } - fn target(&'a self, edge: &E<'g>) -> N<'g> { + fn target(&'a self, edge: &E) -> N { edge.to } } - impl<'a, 'g, 'tcx, Flow> dot::Labeller<'a, N<'g>, E<'g>> for G<'tcx, 'g, Flow> { + impl<'a, 'g, 'tcx, Flow> dot::Labeller<'a, N, E> for G<'tcx, 'g, Flow> { fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("g").unwrap() } - fn node_id(&'a self, n: &N<'g>) -> dot::Id<'a> { + fn node_id(&'a self, n: &N) -> dot::Id<'a> { if let Some(n) = n { dot::Id::new(format!("n{}", n.stable_id())).unwrap() } else { dot::Id::new("return").unwrap() } } - fn node_shape(&'a self, _node: &N<'g>) -> Option> { + fn node_shape(&'a self, _node: &N) -> Option> { Some(dot::LabelText::LabelStr("record".into())) } fn source_port_position( &'a self, - _e: &E<'g>, + _e: &E, ) -> (Option>, Option) { (Some(dot::Id::new("ret").unwrap()), None) } fn target_port_position( &'a self, - e: &E<'g>, + e: &E, ) -> (Option>, Option) { ( match e.into { @@ -179,7 +178,7 @@ pub mod call_only_flow_dot { ) } - fn node_label(&'a self, n: &N<'g>) -> dot::LabelText<'a> { + fn node_label(&'a self, n: &N) -> dot::LabelText<'a> { use std::fmt::Write; let GlobalLocationS { location: loc, @@ -272,7 +271,7 @@ pub mod call_only_flow_dot { dot::LabelText::LabelStr(s.into()) } - fn edge_color(&'a self, e: &E<'g>) -> Option> { + fn edge_color(&'a self, e: &E) -> Option> { (e.into == To::Ctrl).then(|| dot::LabelText::LabelStr("aqua".into())) } } @@ -303,13 +302,7 @@ pub mod call_only_flow_dot { } } -impl<'g> GlobalLocation<'g> { - pub fn iter(&self) -> impl Iterator + '_ { - self.as_slice().iter().copied() - } -} - -use crate::serializers::{Bodies, BodyProxy, SerializableCallOnlyFlow}; +use crate::serializers::{Bodies, BodyProxy}; /// All locations that a body has (helper) pub fn locations_of_body<'a: 'tcx, 'tcx>( @@ -330,7 +323,7 @@ pub fn locations_of_body<'a: 'tcx, 'tcx>( /// [read_non_transitive_graph_and_body]. pub fn write_non_transitive_graph_and_body( tcx: TyCtxt, - flow: &CallOnlyFlow, + flow: &CallOnlyFlow, mut out: W, ) { let bodies = Bodies( @@ -350,7 +343,7 @@ pub fn write_non_transitive_graph_and_body( ( bid, ( - body_name_pls(tcx, bid).name, + Identifier::new(body_name_pls(tcx, bid).name), BodyProxy::from_body_with_normalize( rustc_utils::mir::borrowck_facts::get_simplified_body_with_borrowck_facts( tcx, @@ -364,7 +357,10 @@ pub fn write_non_transitive_graph_and_body( }) .collect::>(), ); - serde_json::to_writer(&mut out, &(flow.make_serializable(), bodies)).unwrap() + + // We use serde_bare because JSON doesn't allow for non-string hashmap keys, + // which we use in the CallOnlyFlow + serde_bare::to_writer(&mut out, &(flow, bodies)).unwrap() } /// Read a flow and a set of mentioned `mir::Body`s from the file. Is expected @@ -372,8 +368,6 @@ pub fn write_non_transitive_graph_and_body( /// /// The companion function [write_non_transitive_graph_and_body] can be used to /// create such a file. -pub fn read_non_transitive_graph_and_body( - read: R, -) -> (SerializableCallOnlyFlow, Bodies) { - serde_json::from_reader(read).unwrap() +pub fn read_non_transitive_graph_and_body(read: R) -> (CallOnlyFlow, Bodies) { + serde_bare::from_reader(read).unwrap() } diff --git a/src/discover.rs b/crates/dfpp/src/discover.rs similarity index 100% rename from src/discover.rs rename to crates/dfpp/src/discover.rs diff --git a/src/frg.rs b/crates/dfpp/src/frg.rs similarity index 94% rename from src/frg.rs rename to crates/dfpp/src/frg.rs index 7338e4ea13..73a4becb9e 100644 --- a/src/frg.rs +++ b/crates/dfpp/src/frg.rs @@ -484,7 +484,7 @@ where } #[derive(Hash, PartialEq, Eq)] -struct FormalParameter { +pub struct FormalParameter { function: Identifier, position: u16, } @@ -499,7 +499,91 @@ impl<'a, A: 'a, D: DocAllocator<'a, A>> ToForge<'a, A, D> for FormalParameter { } } -impl ProgramDescription { +pub trait ProgramDescriptionExt { + fn used_labels(&self) -> HashSet; + + fn all_formal_parameters(&self) -> HashSet; + + fn make_label_sigs<'a, A: Clone + 'a, D: DocAllocator<'a, A>>( + &self, + alloc: &'a D, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; + + fn all_types(&self) -> HashSet<&Identifier>; + + fn make_labels_relation<'a, A: Clone + 'a, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; + + fn make_callsite_argument_relation<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; + + fn make_return_func_relation<'a, A: Clone + 'a, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; + + fn make_otype_relation<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; + + fn make_formal_param_relation<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; + + fn make_types_relation<'a, A: 'a, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + version: Version, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone, + A: Clone; + + fn make_flow<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + version: Version, + ) -> DocBuilder + where + D::Doc: Clone; + + fn make_ctrl_flow<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + version: Version, + ) -> DocBuilder + where + D::Doc: Clone; + + fn serialize_forge<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + &'a self, + alloc: &'a D, + _tcx: TyCtxt, + model_ctrl: &ModelCtrl, + ) -> DocBuilder<'a, D, A> + where + D::Doc: Clone; +} + +impl ProgramDescriptionExt for ProgramDescription { /// Returns all labels in this program description, including the special /// [`name::EXCEPTIONS_LABEL`] label. fn used_labels(&self) -> HashSet { @@ -508,10 +592,9 @@ impl ProgramDescription { .flat_map(|v| v.0.iter()) .filter_map(Annotation::as_label_ann) .map(|a| a.marker) - .chain(std::iter::once(crate::Symbol::intern( + .chain(std::iter::once(Identifier::new_intern( name::EXCEPTIONS_LABEL, ))) - .map(Identifier::new) .collect() } @@ -637,7 +720,7 @@ impl ProgramDescription { // This is necessary because otherwise captured variables escape .collect::>() .into_iter(), - std::iter::once(Identifier::new(a.marker).build_forge(alloc)), + std::iter::once(a.marker.build_forge(alloc)), ) }) })) @@ -762,10 +845,8 @@ impl ProgramDescription { })), } } -} -impl ProgramDescription { - pub fn make_flow<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + fn make_flow<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( &'a self, alloc: &'a D, version: Version, @@ -810,7 +891,7 @@ impl ProgramDescription { } } - pub fn make_ctrl_flow<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + fn make_ctrl_flow<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( &'a self, alloc: &'a D, version: Version, @@ -853,7 +934,7 @@ impl ProgramDescription { } } - pub fn serialize_forge<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( + fn serialize_forge<'a, A: 'a + Clone, D: DocAllocator<'a, A>>( &'a self, alloc: &'a D, _tcx: TyCtxt, diff --git a/crates/dfpp/src/ir/flows.rs b/crates/dfpp/src/ir/flows.rs new file mode 100644 index 0000000000..3467fe2bc9 --- /dev/null +++ b/crates/dfpp/src/ir/flows.rs @@ -0,0 +1,37 @@ +use crate::{ir::GlobalLocation, HashMap, HashSet}; + +use serde::{Deserialize, Serialize}; + +/// Coarse grained, [`Place`](mir::Place) abstracted version of a +/// [`GlobalFlowGraph`]. +#[derive(Serialize, Deserialize)] +pub struct CallOnlyFlow { + pub location_dependencies: HashMap, + pub return_dependencies: HashSet, +} + +impl CallOnlyFlow { + pub fn all_locations_iter(&self) -> impl Iterator + '_ { + self.location_dependencies.iter().flat_map(|(from, deps)| { + std::iter::once(from).chain( + std::iter::once(&deps.ctrl_deps) + .chain(deps.input_deps.iter()) + .flatten(), + ) + }) + } +} + +/// Dependencies of a function call with the [`Place`](mir::Place)s abstracted +/// away. Instead each location in the `input_deps` vector corresponds to the +/// dependencies for the positional argument at that index. For methods the 0th +/// index is `self`. +#[derive(Serialize, Deserialize)] +pub struct CallDeps { + /// Additional dependencies that arise from the control flow, e.g. the scope + /// this function call is located in. + pub ctrl_deps: HashSet, + /// Dependencies of each argument in the same order as the parameters + /// provided to the function call. + pub input_deps: Vec>, +} diff --git a/src/ir/mod.rs b/crates/dfpp/src/ir/mod.rs similarity index 67% rename from src/ir/mod.rs rename to crates/dfpp/src/ir/mod.rs index b429124c6d..17ef575eee 100644 --- a/src/ir/mod.rs +++ b/crates/dfpp/src/ir/mod.rs @@ -1,7 +1,6 @@ //! Library of intermediate representations used in this tool. -pub mod global_location; -pub use global_location::*; +pub use dfgraph::global_location::*; pub mod flows; pub use flows::*; pub mod regal; diff --git a/src/ir/regal.rs b/crates/dfpp/src/ir/regal.rs similarity index 99% rename from src/ir/regal.rs rename to crates/dfpp/src/ir/regal.rs index 85dd178703..8186f76cca 100644 --- a/src/ir/regal.rs +++ b/crates/dfpp/src/ir/regal.rs @@ -7,7 +7,6 @@ use rustc_utils::{ BodyExt, }; -use super::GLI; use crate::{ ana::{ algebra::{self, Equality, Term}, @@ -268,7 +267,7 @@ pub fn get_highest_local(body: &mir::Body) -> mir::Local { impl<'tcx> Body<'tcx, DisplayViaDebug> { pub fn construct>( - flow_analysis: df::FlowResults<'_, 'tcx, '_, '_>, + flow_analysis: df::FlowResults<'_, 'tcx, '_>, equations: I, tcx: TyCtxt<'tcx>, def_id: LocalDefId, @@ -561,7 +560,6 @@ pub fn compute_from_body_id<'tcx>( dbg_opts: &DumpArgs, body_id: BodyId, tcx: TyCtxt<'tcx>, - gli: GLI, carries_marker: &InlineJudge<'tcx>, ) -> Body<'tcx, DisplayViaDebug> { let local_def_id = body_id.into_local_def_id(tcx); @@ -569,7 +567,7 @@ pub fn compute_from_body_id<'tcx>( let body_with_facts = borrowck_facts::get_simplified_body_with_borrowck_facts(tcx, local_def_id); let body = body_with_facts.simplified_body(); - let flow = df::compute_flow_internal(tcx, gli, body_id, body_with_facts, carries_marker); + let flow = df::compute_flow_internal(tcx, body_id, body_with_facts, carries_marker); if dbg_opts.dump_callee_mir() { mir::pretty::write_mir_fn( tcx, diff --git a/src/lib.rs b/crates/dfpp/src/lib.rs similarity index 98% rename from src/lib.rs rename to crates/dfpp/src/lib.rs index 95e2673d52..cce9adc91c 100644 --- a/src/lib.rs +++ b/crates/dfpp/src/lib.rs @@ -88,7 +88,6 @@ pub mod ana; pub mod ann_parse; mod args; pub mod dbg; -pub mod desc; mod discover; pub mod frg; pub mod ir; @@ -98,10 +97,14 @@ pub mod serializers; pub mod utils; pub mod consts; pub mod marker_db; +#[cfg(feature = "test")] +pub mod test_utils; + +pub use dfgraph as desc; pub use args::{AnalysisCtrl, Args, DumpArgs, ModelCtrl}; -use crate::utils::outfile_pls; +use crate::{frg::ProgramDescriptionExt, utils::outfile_pls}; pub use crate::marker_db::MarkerCtx; diff --git a/src/marker_db.rs b/crates/dfpp/src/marker_db.rs similarity index 100% rename from src/marker_db.rs rename to crates/dfpp/src/marker_db.rs diff --git a/src/sah.rs b/crates/dfpp/src/sah.rs similarity index 100% rename from src/sah.rs rename to crates/dfpp/src/sah.rs diff --git a/crates/dfpp/src/serializers.rs b/crates/dfpp/src/serializers.rs new file mode 100644 index 0000000000..fd65162c98 --- /dev/null +++ b/crates/dfpp/src/serializers.rs @@ -0,0 +1,214 @@ +//! [`serde`] serializers, most used for JSON debugging output in [`crate::dbg`]. +//! +//! The proxy structs are foreign serializers for their non-proxy counterparts, +//! see for more information. As a naming +//! convention `Proxy` is used to (de)serialize `` e.g. +//! [`BasicBlockProxy`] (de)serializes a [`mir::BasicBlock`]. +//! +//! Be aware that in some cases serialization is not bidirectional (usually if +//! there is a lifetime parameter in the serialized type). For instance +//! [`GlobalLocation`] can be serialized, but only a [`RawGlobalLocation`] can +//! be deserialized. +//! +//! Some types (such as [`mir::Body`]) first have to be explicitly transformed +//! into the respective proxy type. In the case of [`mir::Body`] this can be +//! done with [`BodyProxy::from_body_with_normalize`] +use dfgraph::Identifier; +use serde::Deserialize; + +use crate::{ + hir, mir, + rust::TyCtxt, + serde::{Serialize, Serializer}, + utils::{extract_places, read_places_with_provenance, DfppBodyExt}, + Either, HashMap, HashSet, +}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct InstructionProxy { + #[serde(with = "dfgraph::rustc_proxies::Location")] + pub location: mir::Location, + pub contents: String, + pub places: HashSet, +} + +/// A serializable version of a `mir::Body`. +/// +/// Be aware that this transports less information than the actual `mir::Body`. +/// It records for each [`mir::Location`] a string representation of the +/// statement or terminator at that location and a set of [`mir::Place`]s that +/// are mentioned in the statement/terminator, also represented as strings +/// (though using the efficient, interned [`Identifier`]s). +/// +/// Construct one with [`Self::from_body_with_normalize`]. +#[derive(Debug, Serialize, Deserialize)] +pub struct BodyProxy(pub Vec); + +fn iter_stmts<'a, 'tcx>( + b: &'a mir::Body<'tcx>, +) -> impl Iterator< + Item = ( + mir::Location, + Either<&'a mir::Statement<'tcx>, &'a mir::Terminator<'tcx>>, + ), +> { + b.basic_blocks.iter_enumerated().flat_map(|(block, bbdat)| { + bbdat + .statements + .iter() + .enumerate() + .map(move |(statement_index, stmt)| { + ( + mir::Location { + block, + statement_index, + }, + Either::Left(stmt), + ) + }) + .chain(std::iter::once(( + mir::Location { + block, + statement_index: bbdat.statements.len(), + }, + Either::Right(bbdat.terminator()), + ))) + }) +} + +impl<'tcx> From<&mir::Body<'tcx>> for BodyProxy { + fn from(body: &mir::Body<'tcx>) -> Self { + Self( + iter_stmts(body) + .map(|(location, stmt)| InstructionProxy { + location, + contents: stmt.either(|s| format!("{:?}", s.kind), |t| format!("{:?}", t.kind)), + places: extract_places(location, body, false) + .into_iter() + .map(|p| Identifier::new_intern(&format!("{p:?}"))) + .collect(), + }) + .collect::>(), + ) + } +} + +impl BodyProxy { + /// Create a serializable version of a `mir::Body` by stringifying + /// everything. + /// + /// Includes, as the set of places for each statements the read places with + /// provenance as calculated by [`read_places_with_provenance`]. + pub fn from_body_with_normalize<'tcx>(body: &mir::Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + Self( + iter_stmts(body) + .map(|(location, stmt)| InstructionProxy { + location, + contents: stmt.either(|s| format!("{:?}", s.kind), |t| format!("{:?}", t.kind)), + places: read_places_with_provenance( + location, + &body.stmt_at_better_err(location), + tcx, + ) + .map(|p| Identifier::new_intern(&format!("{p:?}"))) + .collect(), + }) + .collect::>(), + ) + } +} + +/// This exists because of serde's restrictions on how you derive serializers. +/// [`BodyIdProxy`] can be used to serialize a [`BodyId`](hir::BodyId) but if +/// the [`BodyId`](hir::BodyId) is used as e.g. a key in a map or in a vector it +/// does not dispatch to the remote impl on [`BodyIdProxy`]. Implementing the +/// serializers for the map or vector by hand is annoying so instead you can map +/// over the datastructure, wrap each [`BodyId`](hir::BodyId) in this proxy type +/// and then dispatch to the `serialize` impl for the reconstructed data +/// structure. +#[derive(Serialize, Deserialize)] +pub struct BodyIdProxy2(#[serde(with = "dfgraph::rustc_proxies::BodyId")] pub hir::BodyId); + +pub mod serde_map_via_vec { + //! Serialize a [`HashMap`] by converting it to a [`Vec`], lifting + //! restrictions on the types of permissible keys. + //! + //! The JSON serializer for [`HashMap`] needs the keys to serialize to a + //! JSON string object, but sometimes that is not the case. Since the + //! [`HashMap`] struct only requires its keys be [`Eq`] and [`Hash`] other + //! non-string values may have been used as key (such is the case in + //! [`Bodies`](super::Bodies)). Unfortunately you can still use the + //! [`Serialize`] trait on [`HashMap`], even if the keys do not serialize to + //! strings. Instead a runtime error will be thrown when a non-string key is + //! encountered. + //! + //! This module converts the [`HashMap`] into a [`Vec`] of tuples and + //! (de)serializes that, which permits arbitrary types to be used for the + //! keys. + //! + //! You are meant to use both [`serialize`] and [`deserialize`], because the + //! [`Serialize`] and [`Deserialize`] instances of [`HashMap`] do not work + //! together with these functions. + + use crate::HashMap; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + /// Serialize a [`HashMap`] by first converting to a [`Vec`] of tuples and + /// then serializing the vector. + /// + /// See module level documentation for usage information. + pub fn serialize( + map: &HashMap, + serializer: S, + ) -> Result { + map.iter().collect::>().serialize(serializer) + } + + /// Deserialize a [`HashMap`] by first deserializing a [`Vec`] of tuples and + /// then converting. + /// + /// See module level documentation for usage information. + pub fn deserialize< + 'de, + D: Deserializer<'de>, + K: Deserialize<'de> + std::cmp::Eq + std::hash::Hash, + V: Deserialize<'de>, + >( + deserializer: D, + ) -> Result, D::Error> { + Ok(Vec::deserialize(deserializer)?.into_iter().collect()) + } +} + +/// A serializable version of [`mir::Body`]s, mapped to their [`hir::BodyId`] so +/// that you can resolve the body belonging to a global location (see +/// [`IsGlobalLocation::function`]). +pub struct Bodies(pub HashMap); + +impl Serialize for Bodies { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0 + .iter() + .map(|(bid, (name, b))| (BodyIdProxy2(*bid), *name, b)) + .collect::>() + .serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Bodies { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Vec::deserialize(deserializer).map(|v| { + Bodies( + v.into_iter() + .map(|(BodyIdProxy2(bid), s, v)| (bid, (s, v))) + .collect(), + ) + }) + } +} diff --git a/tests/helpers/mod.rs b/crates/dfpp/src/test_utils.rs similarity index 89% rename from tests/helpers/mod.rs rename to crates/dfpp/src/test_utils.rs index 158d882f76..4dde7c8126 100644 --- a/tests/helpers/mod.rs +++ b/crates/dfpp/src/test_utils.rs @@ -3,10 +3,11 @@ extern crate either; extern crate rustc_hir as hir; extern crate rustc_middle; extern crate rustc_span; -use dfpp::{ +use crate::{ desc::{AnnotationMap, DataSink, DataSource, Identifier, ProgramDescription, TypeDescriptor}, - ir::{GlobalLocationS, IsGlobalLocation, RawGlobalLocation}, - serializers::Bodies, + ir::{CallOnlyFlow, GlobalLocation, GlobalLocationS, RawGlobalLocation}, + serializers::{Bodies, InstructionProxy}, + utils::outfile_pls, HashSet, Symbol, }; use hir::BodyId; @@ -14,7 +15,6 @@ use rustc_middle::mir; use either::Either; -use dfpp::utils::outfile_pls; use std::borrow::Cow; use std::io::prelude::*; use std::path::Path; @@ -52,10 +52,10 @@ pub fn use_rustc A>(f: F) -> A { /// Run dfpp in the current directory, passing the /// `--dump-serialized-non-transitive-graph` flag, which dumps a -/// [`CallOnlyFlow`](dfpp::ir::flows::CallOnlyFlow) for each controller. +/// [`CallOnlyFlow`](crate::ir::flows::CallOnlyFlow) for each controller. /// /// The result is suitable for reading with -/// [`read_non_transitive_graph_and_body`](dfpp::dbg::read_non_transitive_graph_and_body). +/// [`read_non_transitive_graph_and_body`](crate::dbg::read_non_transitive_graph_and_body). pub fn run_dfpp_with_graph_dump(dir: impl AsRef) -> bool { run_dfpp_with_graph_dump_and::<_, &str>(dir, []) } @@ -64,10 +64,11 @@ pub fn run_dfpp_with_graph_dump(dir: impl AsRef) -> bool { /// and `dfpp` executables that were built from this project are (first) in the /// `PATH`. pub fn dfpp_command(dir: impl AsRef) -> std::process::Command { - let mut cmd = std::process::Command::new("cargo"); let path = std::env::var("PATH").unwrap_or_else(|_| Default::default()); // Cargo gives us the path where it wrote `cargo-dfpp` to - let cargo_dfpp_path = std::path::Path::new(env!("CARGO_BIN_EXE_cargo-dfpp")); + let cargo_dfpp_path = Path::new("../../target/debug/cargo-dfpp") + .canonicalize() + .unwrap(); let mut new_path = std::ffi::OsString::with_capacity(path.len() + cargo_dfpp_path.as_os_str().len() + 1); // We then append the parent (e.g. its directory) to the search path. THat @@ -80,6 +81,7 @@ pub fn dfpp_command(dir: impl AsRef) -> std::process::Command { })); new_path.push(":"); new_path.push(path); + let mut cmd = std::process::Command::new(cargo_dfpp_path); cmd.arg("dfpp").env("PATH", new_path).current_dir(dir); eprintln!("Command is {cmd:?}"); cmd @@ -87,10 +89,10 @@ pub fn dfpp_command(dir: impl AsRef) -> std::process::Command { /// Run dfpp in the current directory, passing the /// `--dump-serialized-non-transitive-graph` flag, which dumps a -/// [`CallOnlyFlow`](dfpp::ir::flows::CallOnlyFlow) for each controller. +/// [`CallOnlyFlow`](crate::ir::flows::CallOnlyFlow) for each controller. /// /// The result is suitable for reading with -/// [`read_non_transitive_graph_and_body`](dfpp::dbg::read_non_transitive_graph_and_body). +/// [`read_non_transitive_graph_and_body`](crate::dbg::read_non_transitive_graph_and_body). /// /// Allows for additional arguments to be passed to dfpp pub fn run_dfpp_with_graph_dump_and(dir: impl AsRef, extra: I) -> bool @@ -226,45 +228,35 @@ test expect {{ }} ", property, - dfpp::frg::name::FLOWS_PREDICATE, + crate::frg::name::FLOWS_PREDICATE, result ); outfile_pls(file).and_then(|mut f| f.write_all(content.as_bytes())) } -use dfpp::serializers::SerializableCallOnlyFlow; - -/// A deserialized version of [`CallOnlyFlow`](dfpp::ir::flows::CallOnlyFlow) +/// A deserialized version of [`CallOnlyFlow`](crate::ir::flows::CallOnlyFlow) pub struct G { - pub graph: SerializableCallOnlyFlow, + pub graph: CallOnlyFlow, pub body: Bodies, - pub ctrl_name: Symbol, + pub ctrl_name: Identifier, } pub trait GetCallSites { - fn get_call_sites<'a>( - &'a self, - g: &'a SerializableCallOnlyFlow, - ) -> HashSet<&'a RawGlobalLocation>; + fn get_call_sites<'a>(&'a self, g: &'a CallOnlyFlow) -> HashSet<&'a RawGlobalLocation>; } impl GetCallSites for RawGlobalLocation { - fn get_call_sites<'a>( - &'a self, - _: &'a SerializableCallOnlyFlow, - ) -> HashSet<&'a RawGlobalLocation> { + fn get_call_sites<'a>(&'a self, _: &'a CallOnlyFlow) -> HashSet<&'a RawGlobalLocation> { [self].into_iter().collect() } } impl GetCallSites for GlobalLocationS { - fn get_call_sites<'a>( - &'a self, - g: &'a SerializableCallOnlyFlow, - ) -> HashSet<&'a RawGlobalLocation> { + fn get_call_sites<'a>(&'a self, g: &'a CallOnlyFlow) -> HashSet<&'a RawGlobalLocation> { g.all_locations_iter() .filter(move |l| l.innermost() == *self) + .map(|loc| &**loc) .collect() } } @@ -303,7 +295,7 @@ impl EdgeSelection { impl G { /// Direct predecessor nodes of `n` - fn predecessors(&self, n: &RawGlobalLocation) -> impl Iterator { + fn predecessors(&self, n: &GlobalLocation) -> impl Iterator { self.predecessors_configurable(n, EdgeSelection::Both) } @@ -353,7 +345,7 @@ impl G { ) -> impl Iterator { self.graph .location_dependencies - .get(n) + .get(&GlobalLocation::intern(n)) .into_iter() .flat_map(move |deps| { con_ty @@ -368,8 +360,9 @@ impl G { .into_iter() .flatten(), ) - .flat_map(|s| s.iter()) + .flatten() }) + .map(|dep| &**dep) } pub fn connects(&self, from: &From, to: &To) -> bool { self.connects_configurable(from, to, EdgeSelection::Both) @@ -475,7 +468,7 @@ impl G { .graph .return_dependencies .iter() - .any(|r| self.connects(from, r)) + .any(|r| self.connects(from, &**r)) } /// Return all call sites for functions with names matching `pattern`. @@ -487,10 +480,10 @@ impl G { body.1 .0 .iter() - .filter(|s| s.1.contains(pattern)) + .filter(|s| s.contents.contains(pattern)) .map(|s| GlobalLocationS { function: *bid, - location: s.0, + location: s.location, }) }) .collect() @@ -509,13 +502,13 @@ impl G { /// Deserialize from a `.ntgb.json` file for the controller named `s` pub fn from_file(s: Symbol) -> Self { - let (graph, body) = dfpp::dbg::read_non_transitive_graph_and_body( + let (graph, body) = crate::dbg::read_non_transitive_graph_and_body( std::fs::File::open(format!("{}.ntgb.json", s.as_str())).unwrap(), ); Self { graph, body, - ctrl_name: s, + ctrl_name: Identifier::new(s), } } pub fn ctrl(&self) -> BodyId { @@ -532,9 +525,9 @@ impl G { body.1 .0 .iter() - .find(|(_, s, _)| s == format!("Argument _{n}").as_str()) + .find(|InstructionProxy { contents, .. }| contents == format!("Argument _{n}").as_str()) .unwrap_or_else(|| panic!("Argument {n} not found in {:?}", body)) - .0 + .location } } @@ -575,7 +568,7 @@ pub trait HasGraph<'g>: Sized + Copy { } fn has_marker(self, marker: &str) -> bool { - let marker = Symbol::intern(marker); + let marker = Identifier::new_intern(marker); self.graph().0.annotations.values().any(|v| { v.0.iter() .filter_map(|a| a.as_label_ann()) @@ -588,7 +581,7 @@ pub trait HasGraph<'g>: Sized + Copy { } } -pub struct PreFrg(ProgramDescription); +pub struct PreFrg(pub ProgramDescription); impl<'g> HasGraph<'g> for &'g PreFrg { fn graph(self) -> &'g PreFrg { @@ -603,7 +596,7 @@ impl PreFrg { serde_json::from_reader( &mut std::fs::File::open(format!( "{dir}/{}", - dfpp::consts::FLOW_GRAPH_OUT_NAME + crate::consts::FLOW_GRAPH_OUT_NAME )) .unwrap(), ) @@ -617,7 +610,7 @@ impl PreFrg { pub struct CtrlRef<'g> { graph: &'g PreFrg, ident: Identifier, - ctrl: &'g dfpp::desc::Ctrl, + ctrl: &'g crate::desc::Ctrl, } impl<'g> PartialEq for CtrlRef<'g> { @@ -653,7 +646,7 @@ impl<'g> CtrlRef<'g> { .data_flow .0 .keys() - .filter_map(dfpp::desc::DataSource::as_function_call) + .filter_map(crate::desc::DataSource::as_function_call) .map(|f| CallSiteRef { function: fun, call_site: f, @@ -665,7 +658,7 @@ impl<'g> CtrlRef<'g> { .ctrl_flow .0 .keys() - .filter_map(dfpp::desc::DataSource::as_function_call) + .filter_map(crate::desc::DataSource::as_function_call) .map(|f| CallSiteRef { function: fun, call_site: f, @@ -730,12 +723,12 @@ impl<'g> FnRef<'g> { pub struct CallSiteRef<'g> { function: &'g FnRef<'g>, - call_site: &'g dfpp::desc::CallSite, + call_site: &'g crate::desc::CallSite, ctrl: Cow<'g, CtrlRef<'g>>, } -impl<'g> PartialEq for CallSiteRef<'g> { - fn eq(&self, other: &dfpp::desc::CallSite) -> bool { +impl<'g> PartialEq for CallSiteRef<'g> { + fn eq(&self, other: &crate::desc::CallSite) -> bool { self.call_site == other } } @@ -760,12 +753,12 @@ impl<'g> CallSiteRef<'g> { } pub fn flows_to(&self, sink: &DataSinkRef) -> bool { - let next_hop = |src: dfpp::desc::CallSite| { + let next_hop = |src: crate::desc::CallSite| { self.ctrl .ctrl .data_flow .0 - .get(&dfpp::desc::DataSource::FunctionCall(src.clone())) + .get(&crate::desc::DataSource::FunctionCall(src.clone())) .iter() .flat_map(|i| i.iter()) .map(Either::Left) @@ -774,7 +767,7 @@ impl<'g> CallSiteRef<'g> { .ctrl .ctrl_flow .0 - .get(&dfpp::desc::DataSource::FunctionCall(src)) + .get(&crate::desc::DataSource::FunctionCall(src)) .iter() .flat_map(|i| i.iter()) .map(Either::Right), @@ -806,7 +799,7 @@ impl<'g> CallSiteRef<'g> { } false } - pub fn call_site(&self) -> &dfpp::desc::CallSite { + pub fn call_site(&self) -> &crate::desc::CallSite { self.call_site } } @@ -819,7 +812,7 @@ impl<'g> HasGraph<'g> for &CallSiteRef<'g> { pub struct DataSinkRef<'g> { call_site: Either<&'g CallSiteRef<'g>, &'g PreFrg>, - sink: &'g dfpp::desc::DataSink, + sink: &'g crate::desc::DataSink, } impl<'g> HasGraph<'g> for &DataSinkRef<'g> { @@ -831,8 +824,8 @@ impl<'g> HasGraph<'g> for &DataSinkRef<'g> { } } -impl PartialEq for DataSinkRef<'_> { - fn eq(&self, other: &dfpp::desc::DataSink) -> bool { +impl PartialEq for DataSinkRef<'_> { + fn eq(&self, other: &crate::desc::DataSink) -> bool { self.sink == other } } diff --git a/src/utils/mod.rs b/crates/dfpp/src/utils/mod.rs similarity index 94% rename from src/utils/mod.rs rename to crates/dfpp/src/utils/mod.rs index 5360d6e05e..18062101e5 100644 --- a/src/utils/mod.rs +++ b/crates/dfpp/src/utils/mod.rs @@ -2,10 +2,12 @@ extern crate smallvec; +use dfgraph::{CallSite, DataSource}; use smallvec::SmallVec; use crate::{ desc::Identifier, + ir::{GlobalLocation, GlobalLocationS}, rust::{ ast, hir::{ @@ -32,8 +34,7 @@ pub mod resolve; mod print; pub use print::*; -pub mod tiny_bitset; -pub use tiny_bitset::TinyBitSet; +pub use dfgraph::{hash_pls, short_hash_pls, TinyBitSet}; /// This is meant as an extension trait for `ast::Attribute`. The main method of /// interest is [`match_extract`](#tymethod.match_extract), @@ -331,21 +332,22 @@ impl<'tcx> AsFnAndArgs<'tcx> for mir::TerminatorKind<'tcx> { AsFnAndArgsErr<'tcx>, > { let mir::TerminatorKind::Call { - func, - args, - destination, - .. - } = self else { - return Err(AsFnAndArgsErr::NotAFunctionCall) - }; + func, + args, + destination, + .. + } = self + else { + return Err(AsFnAndArgsErr::NotAFunctionCall); + }; let ty = match &func.constant().ok_or(AsFnAndArgsErr::NotAConstant)?.literal { mir::ConstantKind::Val(_, ty) => *ty, mir::ConstantKind::Ty(cst) => cst.ty(), mir::ConstantKind::Unevaluated { .. } => unreachable!(), }; let (ty::FnDef(defid, gargs) | ty::Closure(defid, gargs)) = ty.kind() else { - return Err(AsFnAndArgsErr::NotFunctionType(ty.kind().clone())) - }; + return Err(AsFnAndArgsErr::NotFunctionType(ty.kind().clone())); + }; let instance = ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), *defid, gargs) .map_err(|_| AsFnAndArgsErr::InstanceResolutionErr)? .map_or(FnResolution::Partial(*defid), FnResolution::Final); @@ -708,20 +710,6 @@ fn handle_aggregate_assign<'tcx>( .project_deeper(rest_project, tcx)) } -/// Create a hash for this object that is no longer than six hex digits -pub fn short_hash_pls(t: T) -> u64 { - // Six digits in hex - hash_pls(t) % 0x1_000_000 -} - -/// Calculate a hash for this object -pub fn hash_pls(t: T) -> u64 { - use std::hash::Hasher; - let mut hasher = std::collections::hash_map::DefaultHasher::default(); - t.hash(&mut hasher); - hasher.finish() -} - /// Brother to [`IntoLocalDefId`], converts the id type to a [`DefId`] using [`TyCtxt`] pub trait IntoDefId { fn into_def_id(self, tcx: TyCtxt) -> DefId; @@ -1038,3 +1026,48 @@ impl IntoBodyId for DefId { self.as_local()?.into_body_id(tcx) } } + +pub trait CallSiteExt { + fn new(loc: &GlobalLocation, function: DefId, tcx: TyCtxt<'_>) -> Self; +} + +impl CallSiteExt for CallSite { + fn new(location: &GlobalLocation, function: DefId, tcx: TyCtxt<'_>) -> Self { + Self { + location: *location, + function: identifier_for_item(tcx, function), + } + } +} + +/// Create a Forge friendly descriptor for this location as a source of data +/// in a model flow. +pub fn data_source_from_global_location bool>( + loc: GlobalLocation, + tcx: TyCtxt, + is_real_location: F, +) -> DataSource { + let GlobalLocationS { + location: dep_loc, + function: dep_fun, + } = loc.innermost(); + let is_real_location = is_real_location(dep_loc); + if loc.is_at_root() && !is_real_location { + DataSource::Argument(loc.outermost_location().statement_index - 1) + } else { + let terminator = + tcx.body_for_body_id(dep_fun) + .simplified_body() + .maybe_stmt_at(dep_loc) + .unwrap_or_else(|e| + panic!("Could not convert {loc} to data source with body {}. is at root: {}, is real: {}. Reason: {e:?}", body_name_pls(tcx, dep_fun), loc.is_at_root(), is_real_location) + ) + .right() + .expect("not a terminator"); + DataSource::FunctionCall(CallSite::new( + &loc, + terminator.as_fn_and_args(tcx).unwrap().0, + tcx, + )) + } +} diff --git a/src/utils/print.rs b/crates/dfpp/src/utils/print.rs similarity index 70% rename from src/utils/print.rs rename to crates/dfpp/src/utils/print.rs index 16764afaf0..4e9d2231df 100644 --- a/src/utils/print.rs +++ b/crates/dfpp/src/utils/print.rs @@ -1,3 +1,4 @@ +pub use dfgraph::utils::write_sep; use std::fmt::{Debug, Display, Formatter, Result}; pub struct Print) -> Result>(pub F); @@ -7,23 +8,6 @@ impl) -> Result> Display for Print { (self.0)(f) } } -pub fn write_sep, F: FnMut(E, &mut Formatter<'_>) -> Result>( - fmt: &mut Formatter<'_>, - sep: &str, - it: I, - mut f: F, -) -> Result { - let mut first = true; - for e in it { - if first { - first = false; - } else { - fmt.write_str(sep)?; - } - f(e, fmt)?; - } - Ok(()) -} #[derive(Hash, Eq, Ord, PartialEq, PartialOrd, Clone, Copy)] pub struct DisplayViaDebug(pub T); diff --git a/src/utils/resolve.rs b/crates/dfpp/src/utils/resolve.rs similarity index 100% rename from src/utils/resolve.rs rename to crates/dfpp/src/utils/resolve.rs diff --git a/tests/.forge_tests.rs b/crates/dfpp/tests/.forge_tests.rs similarity index 99% rename from tests/.forge_tests.rs rename to crates/dfpp/tests/.forge_tests.rs index 9cb9da4a0e..001f3de6b2 100644 --- a/tests/.forge_tests.rs +++ b/crates/dfpp/tests/.forge_tests.rs @@ -2,8 +2,7 @@ #[macro_use] extern crate lazy_static; -mod helpers; -use helpers::*; +use dfpp::test_utils::*; use serial_test::serial; const TEST_CRATE_NAME: &str = "tests/forge-tests"; diff --git a/tests/.gitignore b/crates/dfpp/tests/.gitignore similarity index 100% rename from tests/.gitignore rename to crates/dfpp/tests/.gitignore diff --git a/tests/_contile_tests.rs (ignored) b/crates/dfpp/tests/_contile_tests.rs (ignored) similarity index 100% rename from tests/_contile_tests.rs (ignored) rename to crates/dfpp/tests/_contile_tests.rs (ignored) diff --git a/tests/async-tests/Cargo.lock b/crates/dfpp/tests/async-tests/Cargo.lock similarity index 100% rename from tests/async-tests/Cargo.lock rename to crates/dfpp/tests/async-tests/Cargo.lock diff --git a/tests/async-tests/Cargo.toml b/crates/dfpp/tests/async-tests/Cargo.toml similarity index 100% rename from tests/async-tests/Cargo.toml rename to crates/dfpp/tests/async-tests/Cargo.toml diff --git a/tests/async-tests/src/main.rs b/crates/dfpp/tests/async-tests/src/main.rs similarity index 100% rename from tests/async-tests/src/main.rs rename to crates/dfpp/tests/async-tests/src/main.rs diff --git a/tests/async_tests.rs b/crates/dfpp/tests/async_tests.rs similarity index 98% rename from tests/async_tests.rs rename to crates/dfpp/tests/async_tests.rs index 897d84bfe7..2d673e9ba2 100644 --- a/tests/async_tests.rs +++ b/crates/dfpp/tests/async_tests.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate lazy_static; -use dfpp::Symbol; -mod helpers; -use helpers::*; +use dfpp::{define_G_test_template, define_test_skip, test_utils::*, Symbol}; const CRATE_DIR: &str = "tests/async-tests"; diff --git a/tests/call-chain-analysis-tests/Cargo.lock b/crates/dfpp/tests/call-chain-analysis-tests/Cargo.lock similarity index 100% rename from tests/call-chain-analysis-tests/Cargo.lock rename to crates/dfpp/tests/call-chain-analysis-tests/Cargo.lock diff --git a/tests/call-chain-analysis-tests/Cargo.toml b/crates/dfpp/tests/call-chain-analysis-tests/Cargo.toml similarity index 100% rename from tests/call-chain-analysis-tests/Cargo.toml rename to crates/dfpp/tests/call-chain-analysis-tests/Cargo.toml diff --git a/tests/call-chain-analysis-tests/src/main.rs b/crates/dfpp/tests/call-chain-analysis-tests/src/main.rs similarity index 100% rename from tests/call-chain-analysis-tests/src/main.rs rename to crates/dfpp/tests/call-chain-analysis-tests/src/main.rs diff --git a/tests/call_chain_analysis_tests.rs b/crates/dfpp/tests/call_chain_analysis_tests.rs similarity index 98% rename from tests/call_chain_analysis_tests.rs rename to crates/dfpp/tests/call_chain_analysis_tests.rs index e6c61a824e..13726a8914 100644 --- a/tests/call_chain_analysis_tests.rs +++ b/crates/dfpp/tests/call_chain_analysis_tests.rs @@ -3,9 +3,7 @@ #[macro_use] extern crate lazy_static; -mod helpers; - -use helpers::*; +use dfpp::{define_flow_test_template, define_test_skip, test_utils::*}; const TEST_CRATE_NAME: &str = "tests/call-chain-analysis-tests"; diff --git a/tests/contile-tests (ignored)/Cargo.lock b/crates/dfpp/tests/contile-tests (ignored)/Cargo.lock similarity index 100% rename from tests/contile-tests (ignored)/Cargo.lock rename to crates/dfpp/tests/contile-tests (ignored)/Cargo.lock diff --git a/tests/contile-tests (ignored)/Cargo.toml b/crates/dfpp/tests/contile-tests (ignored)/Cargo.toml similarity index 100% rename from tests/contile-tests (ignored)/Cargo.toml rename to crates/dfpp/tests/contile-tests (ignored)/Cargo.toml diff --git a/tests/contile-tests (ignored)/src/main.rs b/crates/dfpp/tests/contile-tests (ignored)/src/main.rs similarity index 100% rename from tests/contile-tests (ignored)/src/main.rs rename to crates/dfpp/tests/contile-tests (ignored)/src/main.rs diff --git a/tests/control-flow-tests/Cargo.lock b/crates/dfpp/tests/control-flow-tests/Cargo.lock similarity index 100% rename from tests/control-flow-tests/Cargo.lock rename to crates/dfpp/tests/control-flow-tests/Cargo.lock diff --git a/tests/control-flow-tests/Cargo.toml b/crates/dfpp/tests/control-flow-tests/Cargo.toml similarity index 100% rename from tests/control-flow-tests/Cargo.toml rename to crates/dfpp/tests/control-flow-tests/Cargo.toml diff --git a/tests/control-flow-tests/src/main.rs b/crates/dfpp/tests/control-flow-tests/src/main.rs similarity index 100% rename from tests/control-flow-tests/src/main.rs rename to crates/dfpp/tests/control-flow-tests/src/main.rs diff --git a/tests/control_flow_tests.rs b/crates/dfpp/tests/control_flow_tests.rs similarity index 98% rename from tests/control_flow_tests.rs rename to crates/dfpp/tests/control_flow_tests.rs index 4bd60ac798..e82b6aaf8b 100644 --- a/tests/control_flow_tests.rs +++ b/crates/dfpp/tests/control_flow_tests.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate lazy_static; -use dfpp::Symbol; -mod helpers; -use helpers::*; +use dfpp::{define_G_test_template, test_utils::*, Symbol}; const CRATE_DIR: &str = "tests/control-flow-tests"; diff --git a/tests/external-annotation-tests/.gitignore b/crates/dfpp/tests/external-annotation-tests/.gitignore similarity index 100% rename from tests/external-annotation-tests/.gitignore rename to crates/dfpp/tests/external-annotation-tests/.gitignore diff --git a/tests/external-annotation-tests/Cargo.lock b/crates/dfpp/tests/external-annotation-tests/Cargo.lock similarity index 100% rename from tests/external-annotation-tests/Cargo.lock rename to crates/dfpp/tests/external-annotation-tests/Cargo.lock diff --git a/tests/external-annotation-tests/Cargo.toml b/crates/dfpp/tests/external-annotation-tests/Cargo.toml similarity index 100% rename from tests/external-annotation-tests/Cargo.toml rename to crates/dfpp/tests/external-annotation-tests/Cargo.toml diff --git a/tests/external-annotation-tests/external-annotations.toml b/crates/dfpp/tests/external-annotation-tests/external-annotations.toml similarity index 100% rename from tests/external-annotation-tests/external-annotations.toml rename to crates/dfpp/tests/external-annotation-tests/external-annotations.toml diff --git a/tests/external-annotation-tests/helpers.frg b/crates/dfpp/tests/external-annotation-tests/helpers.frg similarity index 100% rename from tests/external-annotation-tests/helpers.frg rename to crates/dfpp/tests/external-annotation-tests/helpers.frg diff --git a/tests/external-annotation-tests/src/main.rs b/crates/dfpp/tests/external-annotation-tests/src/main.rs similarity index 100% rename from tests/external-annotation-tests/src/main.rs rename to crates/dfpp/tests/external-annotation-tests/src/main.rs diff --git a/tests/external_annotation_tests.rs b/crates/dfpp/tests/external_annotation_tests.rs similarity index 98% rename from tests/external_annotation_tests.rs rename to crates/dfpp/tests/external_annotation_tests.rs index 61692224b6..883fdf8943 100644 --- a/tests/external_annotation_tests.rs +++ b/crates/dfpp/tests/external_annotation_tests.rs @@ -2,8 +2,7 @@ #[macro_use] extern crate lazy_static; -mod helpers; -use helpers::*; +use dfpp::test_utils::*; fn do_in_crate_dir A>(f: F) -> std::io::Result { with_current_directory(CRATE_DIR, f) diff --git a/tests/forge-tests/.gitignore b/crates/dfpp/tests/forge-tests/.gitignore similarity index 100% rename from tests/forge-tests/.gitignore rename to crates/dfpp/tests/forge-tests/.gitignore diff --git a/tests/forge-tests/Cargo.lock b/crates/dfpp/tests/forge-tests/Cargo.lock similarity index 100% rename from tests/forge-tests/Cargo.lock rename to crates/dfpp/tests/forge-tests/Cargo.lock diff --git a/tests/forge-tests/Cargo.toml b/crates/dfpp/tests/forge-tests/Cargo.toml similarity index 100% rename from tests/forge-tests/Cargo.toml rename to crates/dfpp/tests/forge-tests/Cargo.toml diff --git a/tests/forge-tests/helpers.frg b/crates/dfpp/tests/forge-tests/helpers.frg similarity index 100% rename from tests/forge-tests/helpers.frg rename to crates/dfpp/tests/forge-tests/helpers.frg diff --git a/tests/forge-tests/src/main.rs b/crates/dfpp/tests/forge-tests/src/main.rs similarity index 100% rename from tests/forge-tests/src/main.rs rename to crates/dfpp/tests/forge-tests/src/main.rs diff --git a/tests/inconsequential-call-removal-tests/Cargo.lock b/crates/dfpp/tests/inconsequential-call-removal-tests/Cargo.lock similarity index 100% rename from tests/inconsequential-call-removal-tests/Cargo.lock rename to crates/dfpp/tests/inconsequential-call-removal-tests/Cargo.lock diff --git a/tests/inconsequential-call-removal-tests/Cargo.toml b/crates/dfpp/tests/inconsequential-call-removal-tests/Cargo.toml similarity index 100% rename from tests/inconsequential-call-removal-tests/Cargo.toml rename to crates/dfpp/tests/inconsequential-call-removal-tests/Cargo.toml diff --git a/tests/inconsequential-call-removal-tests/src/main.rs b/crates/dfpp/tests/inconsequential-call-removal-tests/src/main.rs similarity index 100% rename from tests/inconsequential-call-removal-tests/src/main.rs rename to crates/dfpp/tests/inconsequential-call-removal-tests/src/main.rs diff --git a/tests/inconsequential_call_removal_tests.rs (ignored) b/crates/dfpp/tests/inconsequential_call_removal_tests.rs (ignored) similarity index 100% rename from tests/inconsequential_call_removal_tests.rs (ignored) rename to crates/dfpp/tests/inconsequential_call_removal_tests.rs (ignored) diff --git a/tests/inline-elision-tests/Cargo.lock b/crates/dfpp/tests/inline-elision-tests/Cargo.lock similarity index 100% rename from tests/inline-elision-tests/Cargo.lock rename to crates/dfpp/tests/inline-elision-tests/Cargo.lock diff --git a/tests/inline-elision-tests/Cargo.toml b/crates/dfpp/tests/inline-elision-tests/Cargo.toml similarity index 100% rename from tests/inline-elision-tests/Cargo.toml rename to crates/dfpp/tests/inline-elision-tests/Cargo.toml diff --git a/tests/inline-elision-tests/src/main.rs b/crates/dfpp/tests/inline-elision-tests/src/main.rs similarity index 100% rename from tests/inline-elision-tests/src/main.rs rename to crates/dfpp/tests/inline-elision-tests/src/main.rs diff --git a/tests/inline-no-arg-closure-tests/Cargo.lock b/crates/dfpp/tests/inline-no-arg-closure-tests/Cargo.lock similarity index 100% rename from tests/inline-no-arg-closure-tests/Cargo.lock rename to crates/dfpp/tests/inline-no-arg-closure-tests/Cargo.lock diff --git a/tests/inline-no-arg-closure-tests/Cargo.toml b/crates/dfpp/tests/inline-no-arg-closure-tests/Cargo.toml similarity index 100% rename from tests/inline-no-arg-closure-tests/Cargo.toml rename to crates/dfpp/tests/inline-no-arg-closure-tests/Cargo.toml diff --git a/tests/inline-no-arg-closure-tests/src/main.rs b/crates/dfpp/tests/inline-no-arg-closure-tests/src/main.rs similarity index 100% rename from tests/inline-no-arg-closure-tests/src/main.rs rename to crates/dfpp/tests/inline-no-arg-closure-tests/src/main.rs diff --git a/tests/inline_elision_tests.rs b/crates/dfpp/tests/inline_elision_tests.rs similarity index 98% rename from tests/inline_elision_tests.rs rename to crates/dfpp/tests/inline_elision_tests.rs index 093686f019..409bc0a6fc 100644 --- a/tests/inline_elision_tests.rs +++ b/crates/dfpp/tests/inline_elision_tests.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate lazy_static; -use dfpp::Symbol; -mod helpers; -use helpers::*; +use dfpp::{define_G_test_template, define_test_skip, test_utils::*, Symbol}; const CRATE_DIR: &str = "tests/inline-elision-tests"; diff --git a/tests/inline_no_arg_closure_tests.rs b/crates/dfpp/tests/inline_no_arg_closure_tests.rs similarity index 96% rename from tests/inline_no_arg_closure_tests.rs rename to crates/dfpp/tests/inline_no_arg_closure_tests.rs index 11092d4e58..56e1cd428a 100644 --- a/tests/inline_no_arg_closure_tests.rs +++ b/crates/dfpp/tests/inline_no_arg_closure_tests.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate lazy_static; -use dfpp::Symbol; -mod helpers; -use helpers::*; +use dfpp::{define_G_test_template, test_utils::*, Symbol}; const CRATE_DIR: &str = "tests/inline-no-arg-closure-tests"; diff --git a/tests/marker-tests/Cargo.lock b/crates/dfpp/tests/marker-tests/Cargo.lock similarity index 100% rename from tests/marker-tests/Cargo.lock rename to crates/dfpp/tests/marker-tests/Cargo.lock diff --git a/tests/marker-tests/Cargo.toml b/crates/dfpp/tests/marker-tests/Cargo.toml similarity index 100% rename from tests/marker-tests/Cargo.toml rename to crates/dfpp/tests/marker-tests/Cargo.toml diff --git a/tests/marker-tests/src/main.rs b/crates/dfpp/tests/marker-tests/src/main.rs similarity index 100% rename from tests/marker-tests/src/main.rs rename to crates/dfpp/tests/marker-tests/src/main.rs diff --git a/tests/marker_tests.rs b/crates/dfpp/tests/marker_tests.rs similarity index 93% rename from tests/marker_tests.rs rename to crates/dfpp/tests/marker_tests.rs index 503e4faadc..14de4f0cd3 100644 --- a/tests/marker_tests.rs +++ b/crates/dfpp/tests/marker_tests.rs @@ -3,9 +3,7 @@ #[macro_use] extern crate lazy_static; -mod helpers; - -use helpers::*; +use dfpp::{define_flow_test_template, test_utils::*}; const TEST_CRATE_NAME: &str = "tests/marker-tests"; diff --git a/tests/new-alias-analysis-tests/Cargo.lock b/crates/dfpp/tests/new-alias-analysis-tests/Cargo.lock similarity index 100% rename from tests/new-alias-analysis-tests/Cargo.lock rename to crates/dfpp/tests/new-alias-analysis-tests/Cargo.lock diff --git a/tests/new-alias-analysis-tests/Cargo.toml b/crates/dfpp/tests/new-alias-analysis-tests/Cargo.toml similarity index 100% rename from tests/new-alias-analysis-tests/Cargo.toml rename to crates/dfpp/tests/new-alias-analysis-tests/Cargo.toml diff --git a/tests/new-alias-analysis-tests/src/main.rs b/crates/dfpp/tests/new-alias-analysis-tests/src/main.rs similarity index 100% rename from tests/new-alias-analysis-tests/src/main.rs rename to crates/dfpp/tests/new-alias-analysis-tests/src/main.rs diff --git a/tests/new_alias_analysis_tests.rs b/crates/dfpp/tests/new_alias_analysis_tests.rs similarity index 98% rename from tests/new_alias_analysis_tests.rs rename to crates/dfpp/tests/new_alias_analysis_tests.rs index 9d099f912c..adabb19767 100644 --- a/tests/new_alias_analysis_tests.rs +++ b/crates/dfpp/tests/new_alias_analysis_tests.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate lazy_static; -use dfpp::Symbol; -mod helpers; -use helpers::*; +use dfpp::{define_G_test_template, test_utils::*, Symbol}; const CRATE_DIR: &str = "tests/new-alias-analysis-tests"; diff --git a/tests/non-transitive-graph-tests/Cargo.lock b/crates/dfpp/tests/non-transitive-graph-tests/Cargo.lock similarity index 100% rename from tests/non-transitive-graph-tests/Cargo.lock rename to crates/dfpp/tests/non-transitive-graph-tests/Cargo.lock diff --git a/tests/non-transitive-graph-tests/Cargo.toml b/crates/dfpp/tests/non-transitive-graph-tests/Cargo.toml similarity index 100% rename from tests/non-transitive-graph-tests/Cargo.toml rename to crates/dfpp/tests/non-transitive-graph-tests/Cargo.toml diff --git a/tests/non-transitive-graph-tests/rust-toolchain.toml b/crates/dfpp/tests/non-transitive-graph-tests/rust-toolchain.toml similarity index 100% rename from tests/non-transitive-graph-tests/rust-toolchain.toml rename to crates/dfpp/tests/non-transitive-graph-tests/rust-toolchain.toml diff --git a/tests/non-transitive-graph-tests/src/main.rs b/crates/dfpp/tests/non-transitive-graph-tests/src/main.rs similarity index 100% rename from tests/non-transitive-graph-tests/src/main.rs rename to crates/dfpp/tests/non-transitive-graph-tests/src/main.rs diff --git a/tests/non_transitive_graph_tests.rs b/crates/dfpp/tests/non_transitive_graph_tests.rs similarity index 98% rename from tests/non_transitive_graph_tests.rs rename to crates/dfpp/tests/non_transitive_graph_tests.rs index a74f17ad5a..8f49b18043 100644 --- a/tests/non_transitive_graph_tests.rs +++ b/crates/dfpp/tests/non_transitive_graph_tests.rs @@ -2,9 +2,7 @@ #[macro_use] extern crate lazy_static; -use dfpp::Symbol; -mod helpers; -use helpers::*; +use dfpp::{define_G_test_template, define_test_skip, test_utils::*, Symbol}; const CRATE_DIR: &str = "tests/non-transitive-graph-tests"; diff --git a/props/Cargo.toml b/props/Cargo.toml new file mode 100644 index 0000000000..8a74bdc02b --- /dev/null +++ b/props/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["lemmy", "websubmit"] \ No newline at end of file diff --git a/props/lemmy/.cargo/config.toml b/props/lemmy/.cargo/config.toml new file mode 100644 index 0000000000..b3c8c8be6f --- /dev/null +++ b/props/lemmy/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "prefer-dynamic", "-C", "rpath"] \ No newline at end of file diff --git a/props/lemmy/Cargo.toml b/props/lemmy/Cargo.toml new file mode 100644 index 0000000000..361157dca3 --- /dev/null +++ b/props/lemmy/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "lemmy" +version = "0.1.0" +edition = "2021" + +[dependencies] +dfcheck = { path = "../../crates/dfcheck" } \ No newline at end of file diff --git a/props/lemmy/src/main.rs b/props/lemmy/src/main.rs new file mode 100644 index 0000000000..e272cae254 --- /dev/null +++ b/props/lemmy/src/main.rs @@ -0,0 +1,52 @@ +use std::{collections::HashSet, sync::Arc}; + +use dfcheck::{ + dfgraph::{CallSite, Ctrl, DataSource}, + Context, Marker, +}; + +pub struct CommunityProp { + cx: Arc, +} + +impl CommunityProp { + pub fn new(cx: Arc) -> Self { + CommunityProp { cx } + } + + fn flow_to_auth(&self, c: &Ctrl, sink: &CallSite, marker: Marker) -> bool { + let auth_callsites = self + .cx + .marked_callsites(c.data_flow.0.values().flatten(), marker) + .collect::>(); + + let mut influence_sink = c.ctrl_flow.0.iter().filter_map(|(src, dsts)| match src { + DataSource::FunctionCall(cs) => dsts.iter().any(|dst| dst == sink).then_some(cs), + DataSource::Argument(_) => None, + }); + + influence_sink.any(|cs| auth_callsites.contains(cs)) + } + + pub fn check(&self) { + let db_community_write = Marker::new_intern("db_community_write"); + let community_delete_check = Marker::new_intern("community_delete_check"); + let community_ban_check = Marker::new_intern("community_ban_check"); + + for c in self.cx.desc().controllers.values() { + for dsts in c.data_flow.0.values() { + for write_sink in self.cx.marked_callsites(dsts, db_community_write) { + let ok = self.flow_to_auth(c, write_sink, community_delete_check) + && self.flow_to_auth(c, write_sink, community_ban_check); + if !ok { + println!("Found an failure!"); + } + } + } + } + } +} + +fn main() { + dfcheck::cli(|cx| CommunityProp::new(cx).check()) +} diff --git a/props/websubmit/Cargo.toml b/props/websubmit/Cargo.toml new file mode 100644 index 0000000000..2dc0a3ec3e --- /dev/null +++ b/props/websubmit/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "websubmit" +version = "0.1.0" +edition = "2021" + +[dependencies] +dfcheck = { path = "../../crates/dfcheck" } \ No newline at end of file diff --git a/props/websubmit/src/main.rs b/props/websubmit/src/main.rs new file mode 100644 index 0000000000..14e4f97a3d --- /dev/null +++ b/props/websubmit/src/main.rs @@ -0,0 +1,77 @@ +use std::sync::Arc; + +use dfcheck::{dfgraph::Identifier, Context, Marker}; + +pub struct DeletionProp { + cx: Arc, +} + +impl DeletionProp { + pub fn new(cx: Arc) -> Self { + DeletionProp { cx } + } + + fn flows_to_store(&self, t: &Identifier) -> bool { + let stores = Marker::new_intern("stores"); + + for (c_id, c) in &self.cx.desc().controllers { + let t_srcs = self.cx.srcs_with_type(c, t); + let store_cs = self + .cx + .marked_sinks(c.data_sinks(), stores) + .collect::>(); + + for t_src in t_srcs { + for store in &store_cs { + if self.cx.flows_to(c_id, t_src, store) { + return true; + } + } + } + } + + false + } + + fn flows_to_deletion(&self, t: &Identifier) -> bool { + let deletes = Marker::new_intern("deletes"); + + let mut ots = self.cx.otypes(t); + ots.push(*t); + + for (c_id, c) in &self.cx.desc().controllers { + for ot in &ots { + let t_srcs = self.cx.srcs_with_type(c, ot).collect::>(); + let delete_cs = self + .cx + .marked_sinks(c.data_sinks(), deletes) + .collect::>(); + + for t_src in &t_srcs { + for delete in &delete_cs { + if self.cx.flows_to(c_id, t_src, delete) { + return true; + } + } + } + } + } + + false + } + + // Asserts that there exists one controller which calls a deletion + // function on every value (or an equivalent type) that is ever stored. + pub fn check(&self) { + let sensitive = Marker::new_intern("sensitive"); + for (t, _) in self.cx.marked(sensitive) { + if self.flows_to_store(t) && !self.flows_to_deletion(t) { + println!("Found an error for type: {t:?}"); + } + } + } +} + +fn main() { + dfcheck::cli(|cx| DeletionProp::new(cx).check()) +} diff --git a/src/ir/flows.rs b/src/ir/flows.rs deleted file mode 100644 index 20f25ff97f..0000000000 --- a/src/ir/flows.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::{HashMap, HashSet}; - -use serde::{Deserialize, Serialize}; - -/// Coarse grained, [`Place`](mir::Place) abstracted version of a -/// [`GlobalFlowGraph`]. -#[derive(Serialize, Deserialize)] -#[serde(bound( - serialize = "Location: std::cmp::Eq + std::hash::Hash + serde::Serialize", - deserialize = "Location: std::cmp::Eq + std::hash::Hash + serde::Deserialize<'de>" -))] -pub struct CallOnlyFlow { - #[serde(with = "crate::serializers::serde_map_via_vec")] - pub location_dependencies: HashMap>, - pub return_dependencies: HashSet, -} - -/// Dependencies of a function call with the [`Place`](mir::Place)s abstracted -/// away. Instead each location in the `input_deps` vector corresponds to the -/// dependencies for the positional argument at that index. For methods the 0th -/// index is `self`. -#[derive(serde::Serialize, serde::Deserialize)] -#[serde(bound( - serialize = "Location: std::cmp::Eq + std::hash::Hash + serde::Serialize", - deserialize = "Location: std::cmp::Eq + std::hash::Hash + serde::Deserialize<'de>" -))] -pub struct CallDeps { - /// Additional dependencies that arise from the control flow, e.g. the scope - /// this function call is located in. - pub ctrl_deps: HashSet, - /// Dependencies of each argument in the same order as the parameters - /// provided to the function call. - pub input_deps: Vec>, -} diff --git a/src/ir/global_location.rs b/src/ir/global_location.rs deleted file mode 100644 index 951b7a94ef..0000000000 --- a/src/ir/global_location.rs +++ /dev/null @@ -1,437 +0,0 @@ -//! Unique identifiers for a point in the MIR program execution that span cross -//! function boundaries. -//! -//! The idea of a global location is to capture the call chain up to a specific -//! location. -//! -//! # Example -//! -//! Consider the following code: -//! -//! ``` -//! fn bar() { -//! let x = 1; -//! } -//! -//! @[dfpp::analyze] -//! fn foo { -//! bar(); -//! bar(); -//! } -//! ``` -//! -//! The MIR location of `let x = 1` would likely be something like `bb0[0]` i.e. -//! the 0th statement in basic block 0. However if we construct a flow graph of -//! `foo` that traverses into the called functions (e.g. `bar`), this location -//! is no longer unique. In fact the location of the call to `bar` in `foo` -//! probably also has the MIR location `bb0[0]`. In addition the same function -//! can occur twice so we need to be able to disambiguate a location based on -//! the call chain of getting to the location. -//! -//! So in this example when we inline the first call of `bar` at `bb0[0]` the -//! global location for `let x = 1` for that call is `bb0[0]@bb0[0]` (This is -//! what the `impl Display for GlobalLocation` shows). When the second call is -//! inlined the second `let x = 1` would be `bb0[0]@bb1[0]`. -//! -//! In addition we also capture for every location the `BodyId` of the body the -//! location occurs in, so we can later find the body and the code at that -//! location. -//! -//! # Construction -//! -//! [`GLI::globalize_location`] is used to construct global locations that are -//! not nested in a call chain (such as the location of `let x = 1` within -//! `bar`). A nested location (such as nesting this one behind the call to `bar` -//! in `foo`) is done using [`GLI::global_location_from_relative`]. -//! -//! In the example we would first construct global locations for all locations -//! in `bar` with (pseudocode) `bar_bb0[0] = `[`gli.globalize_location(bb0[0], -//! bar_id)`](GLI::globalize_location) and then make the relative locations to -//! foo with [`gli.global_location_from_relative(bar_bb0[0], bb0[0], -//! foo_id)`](GLI::global_location_from_relative) and -//! [`gli.global_location_from_relative(bar_bb0[0], bb1[0], -//! foo_id)`](GLI::global_location_from_relative) for the first and second -//! inlining respectively. -//! -//! # Representation -//! -//! It is organized from the outside in i.e. the top-level function call is the -//! outermost location which calls `next` at `location` going one level deeper -//! and so forth. You may access the innermost location using -//! `GlobalLocation::innermost_location_and_body`. -//! -//! The innermost location is what you'd want to look up if you are wanting to -//! see the actual statement or terminator that this location refers to. -//! -//! # Usage -//! -//! Global locations are intended to be used via the [`IsGlobalLocation`] trait. -//! -//! ## Why we need a trait -//! -//! We intern global locations to make the fact that they are linked lists more -//! efficient. However this makes serialization harder. Since we only use -//! serialization for testing I am doing the lazy thing where I just serialize -//! copies of the linked list. But this also means there's two ways to represent -//! global location, one being the one that recurses with interned pointers, the -//! other uses an owned (e.g. copied) `Box`. This trait lets you treat both of -//! them the same for convenience. This is the reason this trait uses `&self` -//! instead of `self`. For interned values using `self` would be fine, but the -//! serializable version is an owned `Box` and as such would be moved with these -//! function calls. - -use crate::desc::{CallSite, DataSource}; -use crate::rust::rustc_arena; -use crate::rust::*; -use crate::utils::*; -use hir::BodyId; -use rustc_data_structures::{intern::Interned, sharded::ShardedHashMap}; - -/// The interned version of a global location. See the [module level documentation](super) -/// information on usage and rational. -/// -/// To construct these values use [`GLI::globalize_location`] and -/// [`GLI::global_location_from_relative`]. -/// -/// INVARIANT: self.0.len() > 0 -#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] -pub struct GlobalLocation<'g>(Interned<'g, Vec>); - -impl<'tcx> std::cmp::PartialOrd for GlobalLocation<'tcx> { - fn partial_cmp(&self, other: &Self) -> Option { - for (slf, othr) in self.as_slice().iter().zip(other.as_slice().iter()) { - if slf.function != othr.function { - return slf.function.hir_id.partial_cmp(&othr.function.hir_id); - } - if slf.location == othr.location { - return slf.location.partial_cmp(&othr.location); - } - } - - self.as_slice().len().partial_cmp(&other.as_slice().len()) - } -} - -impl<'tcx> std::cmp::Ord for GlobalLocation<'tcx> { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.partial_cmp(other).unwrap() - } -} - -/// Formatting for global locations that works independent of whether it is an -/// interned or inlined location. -pub fn format_global_location( - t: &T, - f: &mut std::fmt::Formatter<'_>, -) -> std::fmt::Result { - write_sep(f, "@", t.as_slice().iter().rev(), |elem, f| { - write!( - f, - "{:?}[{}]", - elem.location.block, elem.location.statement_index - ) - })?; - Ok(()) -} - -impl<'g> std::fmt::Display for GlobalLocation<'g> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - format_global_location(self, f) - } -} - -pub trait IsGlobalLocation: Sized + std::fmt::Display { - fn outermost(&self) -> GlobalLocationS { - *self.as_slice().first().unwrap() - } - /// Get the `function` field of the underlying location. - fn outermost_function(&self) -> BodyId { - self.outermost().function - } - /// Get the `location` field of the underlying location. - fn outermost_location(&self) -> mir::Location { - self.outermost().location - } - /// Get the `next` field of the underlying location. - fn as_slice(&self) -> &[GlobalLocationS]; - - fn innermost(&self) -> GlobalLocationS { - *self.as_slice().last().unwrap() - } - - fn innermost_location(&self) -> mir::Location { - self.innermost().location - } - - fn innermost_function(&self) -> BodyId { - self.innermost().function - } - - /// It this location is top-level (i.e. `self.next() == None`), then return - /// the `location` field. - fn as_local(&self) -> Option { - if self.is_at_root() { - Some(self.outermost_location()) - } else { - None - } - } - /// This location is at the top level (e.g. not-nested e.g. `self.next() == - /// None`). - fn is_at_root(&self) -> bool { - self.as_slice().len() == 1 - } - - fn as_raw(&self) -> RawGlobalLocation { - RawGlobalLocation(self.as_slice().to_vec()) - } - - /// Create a Forge friendly descriptor for this location as a source of data - /// in a model flow. - fn as_data_source bool>( - &self, - tcx: TyCtxt, - is_real_location: F, - ) -> DataSource { - let GlobalLocationS { - location: dep_loc, - function: dep_fun, - } = self.innermost(); - let is_real_location = is_real_location(dep_loc); - if self.is_at_root() && !is_real_location { - DataSource::Argument(self.outermost_location().statement_index - 1) - } else { - let terminator = - tcx.body_for_body_id(dep_fun) - .simplified_body() - .maybe_stmt_at(dep_loc) - .unwrap_or_else(|e| - panic!("Could not convert {self} to data source with body {}. is at root: {}, is real: {}. Reason: {e:?}", body_name_pls(tcx, dep_fun), self.is_at_root(), is_real_location) - ) - .right() - .expect("not a terminator"); - DataSource::FunctionCall(CallSite::new( - self, - terminator.as_fn_and_args(tcx).unwrap().0, - tcx, - )) - } - } -} - -pub fn iter_parents(l: &L) -> impl Iterator { - let slc = l.as_slice(); - (1..slc.len()).map(|i| &slc[0..i]) -} - -impl<'g> IsGlobalLocation for GlobalLocation<'g> { - fn as_slice(&self) -> &[GlobalLocationS] { - self.0.as_slice() - } -} - -impl<'g> GlobalLocation<'g> { - /// The naming here might be misleading, this id is *not stable across tool - /// runs*, but because of the interner it is guaranteed that for any two - /// locations `g1` and `g2`, `g1.stable_id() == g2.stable_id()` iff `g1 == - /// g2`. - pub fn stable_id(self) -> usize { - self.0 .0 as *const Vec as usize - } - - pub fn to_owned(&self) -> Vec { - self.0 .0.clone() - } - - pub fn parent(self, gli: GLI<'g>) -> Option { - if self.is_at_root() { - None - } else { - Some(gli.from_vec(self.as_slice().split_last().unwrap().1.to_vec())) - } - } -} - -/// The payload type of a global location. You will probably want to operate on -/// the interned wrapper type [`GlobalLocation`], which gives access to the same -/// fields with methods such as [`function`](IsGlobalLocation::function), -/// [`location`](IsGlobalLocation::location) and -/// [`next`](IsGlobalLocation::next). -/// -/// Other methods and general information for global locations is documented on -/// [`GlobalLocation`]. -/// -/// The generic parameter `Inner` is typically instantiated recursively with the -/// interned wrapper type `GlobalLocation<'g>`, forming an interned linked list. -/// We use a generic parameter so that deserializers can instead instantiate -/// them as [`GlobalLocationS`], i.e. a non-interned version of the same struct. -/// This is necessary because in the derived deserializers we do not have access -/// to the interner. -/// -/// For convenience the trait [`IsGlobalLocation`] is provided which lets you -/// operate directly on the wrapper types and also na way that works with any -/// global location type (both [`GlobalLocation`] as well as the serializable -/// [`crate::serializers::RawGlobalLocation`]) -#[derive(PartialEq, Eq, Hash, Debug, Clone, serde::Deserialize, serde::Serialize, Copy)] -pub struct GlobalLocationS { - /// The id of the body in which this location is located. - #[serde(with = "crate::serializers::BodyIdProxy")] - pub function: BodyId, - /// The location itself - #[serde(with = "crate::serializers::ser_loc")] - pub location: mir::Location, -} -/// A serializable non-interned version of [`GlobalLocation`]. -/// -/// Thanks to the [`IsGlobalLocation`] trait you can use this the same way as a -/// [`GlobalLocation`]. Though be aware that this struct is significantly larger -/// in memory as it contains a singly-linked list of call chains that is not -/// interned. -/// -/// For information on the meaning of this struct see [`GlobalLocation`] -#[derive(serde::Deserialize, serde::Serialize, PartialEq, Eq, Hash, Clone, Debug)] -pub struct RawGlobalLocation(Vec); - -impl<'g> From<&'_ GlobalLocation<'g>> for RawGlobalLocation { - fn from(other: &GlobalLocation<'g>) -> Self { - (*other).into() - } -} - -impl<'g> From> for RawGlobalLocation { - fn from(other: GlobalLocation<'g>) -> Self { - RawGlobalLocation(other.to_owned()) - } -} - -impl std::fmt::Display for RawGlobalLocation { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - format_global_location(self, f) - } -} - -impl IsGlobalLocation for RawGlobalLocation { - fn as_slice(&self) -> &[GlobalLocationS] { - &self.0 - } -} - -/// The interner for `GlobalLocation`s. You should never have to use this -/// directly, use the convenience wrapper type `GLI` instead. -/// -/// Be aware that the lifetime of locations is tied to `'g`, meaning you need to -/// allocate the arena before you create the interner. And also the arena must -/// outlive the interner (rustc will make sure to remind you of this). -/// -/// Also be aware that interning *will no longer work correctly if you discard -/// the interner*. This is because the decision whether or not to intern a new -/// copy of the location is made using the `known_location` map. If you discard -/// the interner and create a new one its map will be empty. This means it -/// *doesn't know about any previously interned locations* and as a result it -/// will reintern locations, which in turn creates interned values that have the -/// same payload as previously interned locations *and even the same lifetime -/// `'g`*, but have a different pointer value and thus do not compare equal with -/// later interned locations or have the same hash. -pub struct GlobalLocationInterner<'g> { - arena: &'g rustc_arena::TypedArena>, - known_locations: ShardedHashMap<&'g Vec, ()>, -} - -impl<'g> GlobalLocationInterner<'g> { - fn intern_location(&'g self, loc: Vec) -> GlobalLocation<'g> { - GlobalLocation(Interned::new_unchecked( - self.known_locations - .intern(loc, |loc| self.arena.alloc(loc)), - )) - } - /// Construct a new interner. - /// - /// We have to take the arena by reference because the lifetime of the reference ensures it outlives the interner and is not mutated altered. - pub fn new(arena: &'g rustc_arena::TypedArena>) -> Self { - GlobalLocationInterner { - arena, - known_locations: ShardedHashMap::default(), - } - } -} - -/// Convenience struct, similar to [`ty::TyCtxt`]. Everything you could ever want -/// from the interner can be done on this struct and it's `Copy` so you don't -/// have to worry about accidentally moving it (as you would when using -/// `&GlobalLocationInterner`). -#[derive(Clone, Copy)] -pub struct GLI<'g>(&'g GlobalLocationInterner<'g>); - -impl<'g> GLI<'g> { - pub fn new(interner: &'g GlobalLocationInterner<'g>) -> Self { - Self(interner) - } - fn make_global_location( - self, - function: BodyId, - location: mir::Location, - next: Option>, - ) -> GlobalLocation<'g> { - let mut v = vec![GlobalLocationS { function, location }]; - if let Some(others) = next { - v.extend_from_slice(others.as_slice()) - } - self.0.intern_location(v) - } - - pub fn from_vec(self, v: Vec) -> GlobalLocation<'g> { - assert!(!v.is_empty()); - self.0.intern_location(v) - } - /// Create a top-level [`GlobalLocation`] (e.g. a non-nested call) - /// - /// `function` is the id of the [`mir::Body`] that the [`mir::Location`] is from. - /// - /// See the [`IsGlobalLocation`](./trait.IsGlobalLocation.html#construction) - /// trait for more information. - pub fn globalize_location( - self, - location: mir::Location, - function: BodyId, - ) -> GlobalLocation<'g> { - self.make_global_location(function, location, None) - } - /// Make `relative_location` a location in a nested call in `root_function` - /// at `root_location` - /// - /// See the [`IsGlobalLocation`](./trait.IsGlobalLocation.html#construction) - /// trait for more information. - pub fn global_location_from_relative( - self, - relative_location: GlobalLocation<'g>, - root_location: mir::Location, - root_function: BodyId, - ) -> GlobalLocation<'g> { - self.make_global_location(root_function, root_location, Some(relative_location)) - } - - pub fn at(self, location: mir::Location, function: BodyId) -> GliAt<'g> { - GliAt { - gli: self, - location, - function, - } - } -} - -#[derive(Clone)] -pub struct GliAt<'g> { - gli: GLI<'g>, - location: mir::Location, - function: BodyId, -} - -impl<'g> GliAt<'g> { - pub fn as_global_location(&self) -> GlobalLocation<'g> { - self.gli.globalize_location(self.location, self.function) - } - pub fn relativize(&self, relative: GlobalLocation<'g>) -> GlobalLocation<'g> { - self.gli - .global_location_from_relative(relative, self.location, self.function) - } -} diff --git a/src/serializers.rs b/src/serializers.rs deleted file mode 100644 index 8435e8011a..0000000000 --- a/src/serializers.rs +++ /dev/null @@ -1,483 +0,0 @@ -//! [`serde`] serializers, most used for JSON debugging output in [`crate::dbg`]. -//! -//! The proxy structs are foreign serializers for their non-proxy counterparts, -//! see for more information. As a naming -//! convention `Proxy` is used to (de)serialize `` e.g. -//! [`BasicBlockProxy`] (de)serializes a [`mir::BasicBlock`]. -//! -//! Be aware that in some cases serialization is not bidirectional (usually if -//! there is a lifetime parameter in the serialized type). For instance -//! [`GlobalLocation`] can be serialized, but only a [`RawGlobalLocation`] can -//! be deserialized. -//! -//! Some types (such as [`mir::Body`]) first have to be explicitly transformed -//! into the respective proxy type. In the case of [`mir::Body`] this can be -//! done with [`BodyProxy::from_body_with_normalize`] -use serde::Deserialize; - -use crate::{ - ir::{CallDeps, CallOnlyFlow, GlobalLocation, RawGlobalLocation}, - mir, - rust::TyCtxt, - serde::{Serialize, Serializer}, - utils::{extract_places, read_places_with_provenance, DfppBodyExt}, - Either, HashMap, HashSet, Symbol, -}; - -fn bbref_to_usize(r: &mir::BasicBlock) -> usize { - r.as_usize() -} - -#[derive(serde::Serialize, serde::Deserialize)] -#[serde(remote = "mir::BasicBlock")] -struct BasicBlockProxy { - #[serde(getter = "bbref_to_usize")] - private: usize, -} - -impl From for mir::BasicBlock { - fn from(proxy: BasicBlockProxy) -> mir::BasicBlock { - mir::BasicBlock::from_usize(proxy.private) - } -} - -#[derive(serde::Serialize, Eq, PartialEq, Hash, serde::Deserialize)] -pub struct LocationProxy { - #[serde(with = "BasicBlockProxy")] - pub block: mir::BasicBlock, - pub statement_index: usize, -} - -pub mod ser_loc { - //! Serialization of locations, bundled into a `mod` so that you can use it - //! like - //! [`#[serde(with="ser_loc")]`](https://serde.rs/field-attrs.html#with) - use crate::mir; - use serde::{Deserialize, Serialize}; - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - super::LocationProxy::deserialize(deserializer).map(|s| s.into()) - } - - pub fn serialize(s: &mir::Location, serializer: S) -> Result - where - S: serde::Serializer, - { - super::LocationProxy::from(*s).serialize(serializer) - } -} - -impl From for LocationProxy { - fn from(l: mir::Location) -> Self { - Self { - block: l.block, - statement_index: l.statement_index, - } - } -} - -impl From for mir::Location { - fn from(proxy: LocationProxy) -> mir::Location { - let LocationProxy { - block, - statement_index, - } = proxy; - mir::Location { - block, - statement_index, - } - } -} - -/// A serializable version of a `mir::Body`. -/// -/// Be aware that this transports less information than the actual `mir::Body`. -/// It records for each [`mir::Location`] a string representation of the -/// statement or terminator at that location and a set of [`mir::Place`]s that -/// are mentioned in the statement/terminator, also represented as strings -/// (though using the efficient, interned [`Symbol`]s). -/// -/// Construct one with [`Self::from_body_with_normalize`]. -#[derive(Debug)] -pub struct BodyProxy(pub Vec<(mir::Location, String, HashSet)>); - -impl Serialize for BodyProxy { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0 - .iter() - .map(|(l, s, h)| { - ( - (*l).into(), - s, - h.iter().map(|s| s.as_str()).collect::>(), - ) - }) - .collect::>() - .serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for BodyProxy { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - )> as Deserialize<'de>>::deserialize( - deserializer, - ) - .map(|v| { - v.into_iter() - .map(|(l, s, vs)| (l.into(), s, vs.into_iter().map(|s| s.into()).collect())) - .collect() - }) - .map(BodyProxy) - } -} -fn iter_stmts<'a, 'tcx>( - b: &'a mir::Body<'tcx>, -) -> impl Iterator< - Item = ( - mir::Location, - Either<&'a mir::Statement<'tcx>, &'a mir::Terminator<'tcx>>, - ), -> { - b.basic_blocks.iter_enumerated().flat_map(|(block, bbdat)| { - bbdat - .statements - .iter() - .enumerate() - .map(move |(statement_index, stmt)| { - ( - mir::Location { - block, - statement_index, - }, - Either::Left(stmt), - ) - }) - .chain(std::iter::once(( - mir::Location { - block, - statement_index: bbdat.statements.len(), - }, - Either::Right(bbdat.terminator()), - ))) - }) -} - -impl<'tcx> From<&mir::Body<'tcx>> for BodyProxy { - fn from(body: &mir::Body<'tcx>) -> Self { - Self( - iter_stmts(body) - .map(|(loc, stmt)| { - ( - loc, - stmt.either(|s| format!("{:?}", s.kind), |t| format!("{:?}", t.kind)), - extract_places(loc, body, false) - .into_iter() - .map(|p| Symbol::intern(&format!("{p:?}"))) - .collect(), - ) - }) - .collect::>(), - ) - } -} - -impl BodyProxy { - /// Create a serializable version of a `mir::Body` by stringifying - /// everything. - /// - /// Includes, as the set of places for each statements the read places with - /// provenance as calculated by [`read_places_with_provenance`]. - pub fn from_body_with_normalize<'tcx>(body: &mir::Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self { - Self( - iter_stmts(body) - .map(|(loc, stmt)| { - ( - loc, - stmt.either(|s| format!("{:?}", s.kind), |t| format!("{:?}", t.kind)), - read_places_with_provenance(loc, &body.stmt_at_better_err(loc), tcx) - .map(|p| Symbol::intern(&format!("{p:?}"))) - .collect(), - ) - }) - .collect::>(), - ) - } -} - -pub struct SymbolProxy(Symbol); - -pub mod ser_sym { - //! Serialization of [`Symbol`]s, bundled into a `mod` so that you can use it - //! like - //! [`#[serde(with="ser_sym")]`](https://serde.rs/field-attrs.html#with) - use crate::Symbol; - use serde::{Deserialize, Serialize}; - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - super::SymbolProxy::deserialize(deserializer).map(|s| s.into()) - } - - pub fn serialize(s: &Symbol, serializer: S) -> Result - where - S: serde::Serializer, - { - super::SymbolProxy::from(*s).serialize(serializer) - } -} - -impl<'de> serde::Deserialize<'de> for SymbolProxy { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - String::deserialize(deserializer).map(|s| Self(Symbol::intern(&s))) - } -} - -impl Serialize for SymbolProxy { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.0.as_str().serialize(serializer) - } -} - -impl From for SymbolProxy { - fn from(sym: Symbol) -> Self { - Self(sym) - } -} - -impl From for Symbol { - fn from(proxy: SymbolProxy) -> Symbol { - proxy.0 - } -} - -use crate::rust::hir::{self, def_id}; - -#[derive(Serialize, Deserialize)] -struct LocationDomainProxy { - domain: Vec, - #[serde(with = "BasicBlockProxy")] - arg_block: mir::BasicBlock, - real_locations: usize, -} - -fn item_local_id_as_u32(i: &hir::ItemLocalId) -> u32 { - i.as_u32() -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "hir::ItemLocalId")] -struct ItemLocalIdProxy { - #[serde(getter = "item_local_id_as_u32")] - private: u32, -} - -impl From for hir::ItemLocalId { - fn from(proxy: ItemLocalIdProxy) -> hir::ItemLocalId { - hir::ItemLocalId::from_u32(proxy.private) - } -} - -fn def_index_as_u32(i: &def_id::DefIndex) -> u32 { - i.as_u32() -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "def_id::DefIndex")] -struct DefIndexProxy { - #[serde(getter = "def_index_as_u32")] - private: u32, -} - -impl From for def_id::DefIndex { - fn from(proxy: DefIndexProxy) -> def_id::DefIndex { - def_id::DefIndex::from_u32(proxy.private) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "def_id::LocalDefId")] -struct LocalDefIdProxy { - #[serde(with = "DefIndexProxy")] - local_def_index: def_id::DefIndex, -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "hir::hir_id::OwnerId")] -struct OwnerIdProxy { - #[serde(with = "LocalDefIdProxy")] - def_id: crate::LocalDefId, -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "hir::HirId")] -struct HirIdProxy { - #[serde(with = "OwnerIdProxy")] - owner: hir::OwnerId, - #[serde(with = "ItemLocalIdProxy")] - local_id: hir::ItemLocalId, -} - -#[derive(Deserialize, Serialize)] -#[serde(remote = "hir::BodyId")] -pub struct BodyIdProxy { - #[serde(with = "HirIdProxy")] - hir_id: hir::HirId, -} - -/// This exists because of serde's restrictions on how you derive serializers. -/// [`BodyIdProxy`] can be used to serialize a [`BodyId`](hir::BodyId) but if -/// the [`BodyId`](hir::BodyId) is used as e.g. a key in a map or in a vector it -/// does not dispatch to the remote impl on [`BodyIdProxy`]. Implementing the -/// serializers for the map or vector by hand is annoying so instead you can map -/// over the datastructure, wrap each [`BodyId`](hir::BodyId) in this proxy type -/// and then dispatch to the `serialize` impl for the reconstructed data -/// structure. -#[derive(Serialize, Deserialize)] -pub struct BodyIdProxy2(#[serde(with = "BodyIdProxy")] pub hir::BodyId); - -impl<'g> Serialize for GlobalLocation<'g> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - RawGlobalLocation::from(self).serialize(serializer) - } -} -pub type SerializableCallOnlyFlow = CallOnlyFlow; - -pub mod serde_map_via_vec { - //! Serialize a [`HashMap`] by converting it to a [`Vec`], lifting - //! restrictions on the types of permissible keys. - //! - //! The JSON serializer for [`HashMap`] needs the keys to serialize to a - //! JSON string object, but sometimes that is not the case. Since the - //! [`HashMap`] struct only requires its keys be [`Eq`] and [`Hash`] other - //! non-string values may have been used as key (such is the case in - //! [`Bodies`](super::Bodies)). Unfortunately you can still use the - //! [`Serialize`] trait on [`HashMap`], even if the keys do not serialize to - //! strings. Instead a runtime error will be thrown when a non-string key is - //! encountered. - //! - //! This module converts the [`HashMap`] into a [`Vec`] of tuples and - //! (de)serializes that, which permits arbitrary types to be used for the - //! keys. - //! - //! You are meant to use both [`serialize`] and [`deserialize`], because the - //! [`Serialize`] and [`Deserialize`] instances of [`HashMap`] do not work - //! together with these functions. - - use crate::HashMap; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - /// Serialize a [`HashMap`] by first converting to a [`Vec`] of tuples and - /// then serializing the vector. - /// - /// See module level documentation for usage information. - pub fn serialize( - map: &HashMap, - serializer: S, - ) -> Result { - map.iter().collect::>().serialize(serializer) - } - - /// Deserialize a [`HashMap`] by first deserializing a [`Vec`] of tuples and - /// then converting. - /// - /// See module level documentation for usage information. - pub fn deserialize< - 'de, - D: Deserializer<'de>, - K: Deserialize<'de> + std::cmp::Eq + std::hash::Hash, - V: Deserialize<'de>, - >( - deserializer: D, - ) -> Result, D::Error> { - Ok(Vec::deserialize(deserializer)?.into_iter().collect()) - } -} - -impl SerializableCallOnlyFlow { - pub fn all_locations_iter(&self) -> impl Iterator { - self.location_dependencies.iter().flat_map(|(from, deps)| { - std::iter::once(from).chain( - std::iter::once(&deps.ctrl_deps) - .chain(deps.input_deps.iter()) - .flat_map(|d| d.iter()), - ) - }) - } -} - -impl CallOnlyFlow> { - pub fn make_serializable(&self) -> SerializableCallOnlyFlow { - CallOnlyFlow { - location_dependencies: self - .location_dependencies - .iter() - .map(|(g, v)| { - ( - g.into(), - CallDeps { - ctrl_deps: v.ctrl_deps.iter().map(|l| l.into()).collect(), - input_deps: v - .input_deps - .iter() - .map(|hs| hs.iter().map(|d| d.into()).collect()) - .collect(), - }, - ) - }) - .collect(), - return_dependencies: self.return_dependencies.iter().map(|l| l.into()).collect(), - } - } -} -/// A serializable version of [`mir::Body`]s, mapped to their [`hir::BodyId`] so -/// that you can resolve the body belonging to a global location (see -/// [`IsGlobalLocation::function`]). -pub struct Bodies(pub HashMap); - -impl Serialize for Bodies { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0 - .iter() - .map(|(bid, (name, b))| (BodyIdProxy2(*bid), (SymbolProxy(*name), b))) - .collect::>() - .serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for Bodies { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Vec::deserialize(deserializer).map(|v| { - Bodies( - v.into_iter() - .map(|(BodyIdProxy2(bid), (SymbolProxy(s), v))| (bid, (s, v))) - .collect(), - ) - }) - } -}