cargo_check_deadlock/lib.rs
1//! Library code that implements the translation of Rust source code to a Petri net.
2//!
3//! It uses rustc's query system to navigate the AST.
4//!
5//! Adapted from the example in the rustc-dev guide:
6//! <https://rustc-dev-guide.rust-lang.org/rustc-driver-interacting-with-the-ast.html>
7//!
8//! NOTE: For the library code to compile, you will need to first run the following:
9//! `rustup component add rustc-dev llvm-tools-preview`
10
11// This feature gate is necessary to access the internal crates of the compiler.
12// It has existed for a long time and since the compiler internals will never be stabilized,
13// the situation will probably stay like this.
14// <https://doc.rust-lang.org/unstable-book/language-features/rustc-private.html>
15#![feature(rustc_private)]
16
17// Compiler crates need to be imported in this way because they are not published on crates.io.
18// These crates are only available when using the nightly toolchain.
19// It suffices to declare them once to use their types and methods in the whole crate.
20extern crate rustc_ast_pretty;
21extern crate rustc_const_eval;
22extern crate rustc_driver;
23extern crate rustc_error_codes;
24extern crate rustc_errors;
25extern crate rustc_hir;
26extern crate rustc_interface;
27extern crate rustc_middle;
28extern crate rustc_session;
29extern crate rustc_span;
30
31mod data_structures;
32pub mod model_checker;
33mod naming;
34mod translator;
35mod utils;
36
37pub use data_structures::petri_net_interface::PetriNet;
38
39use std::collections::HashMap;
40
41/// The Config struct is documented here:
42/// <https://doc.rust-lang.org/stable/nightly-rustc/rustc_interface/interface/struct.Config.html>
43///
44/// It includes command-line options as well as internal rustc options.
45/// The relevant parts in this case is only the input file.
46///
47/// See the rustc driver examples for other possible example configurations:
48/// <https://rustc-dev-guide.rust-lang.org/rustc-driver.html>
49fn prepare_rustc_config(source_code_filepath: std::path::PathBuf) -> rustc_interface::Config {
50 rustc_interface::Config {
51 opts: rustc_session::config::Options::default(),
52 crate_cfg: Vec::new(),
53 crate_check_cfg: Vec::new(),
54 input: rustc_session::config::Input::File(source_code_filepath),
55 output_dir: None,
56 output_file: None,
57 hash_untracked_state: None,
58 ice_file: None,
59 file_loader: None,
60 lint_caps: HashMap::default(),
61 psess_created: None,
62 register_lints: None,
63 override_queries: None,
64 make_codegen_backend: None,
65 using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
66 extra_symbols: Vec::new(),
67 }
68}
69
70/// Entry point for the translation of the Rust code to a Petri net.
71///
72/// Adapted from the [example in the rustc repo](https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs)
73///
74/// # Errors
75///
76/// If the `sysroot` cannot be found, then an error is returned.
77/// If the translation fails, then an error with the corresponding description is returned.
78///
79/// # Panics
80///
81/// If the translation failed due to a bug, then the function panics.
82pub fn run(source_code_filepath: std::path::PathBuf) -> Result<PetriNet, &'static str> {
83 let config = prepare_rustc_config(source_code_filepath);
84 let mut translation_result: Result<PetriNet, &'static str> = Err("Translation did not run");
85
86 rustc_interface::run_compiler(config, |compiler| {
87 // Parse the program and print the syntax tree.
88 let krate = rustc_interface::passes::parse(&compiler.sess);
89 // Analyze the program and inspect the types of definitions.
90 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
91 let mut translator = translator::Translator::new(tcx);
92 translator.run();
93 translation_result = Ok(translator.get_result());
94 });
95 });
96
97 translation_result
98}