rust/tests/ui-fulldeps/stable-mir/check_crate_defs.rs
Celina G. Val 0ce579f6f3 [StableMIR] API to retrieve definitions from crates
Add functions to retrieve function definitions and static items from
all crates (local and external).

For external crates, add a query to retrieve the number of defs in a
foreign crate.
2024-11-07 13:11:46 -08:00

150 lines
4.4 KiB
Rust

//@ run-pass
//! Test information about crate definitions (local and external).
//@ ignore-stage1
//@ ignore-cross-compile
//@ ignore-remote
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
#![feature(rustc_private)]
#![feature(assert_matches)]
extern crate rustc_hir;
#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;
use rustc_smir::rustc_internal;
use stable_mir::CrateDef;
use std::collections::HashSet;
use std::io::Write;
use std::ops::ControlFlow;
const CRATE_NAME: &str = "crate_defs";
/// This function uses the Stable MIR APIs to get information about the test crate.
fn test_stable_mir() -> ControlFlow<()> {
// Find items in the local crate.
let local = stable_mir::local_crate();
check_items(&local.statics(), &["PRIVATE_STATIC", "dummy::PUBLIC_STATIC"]);
check_items(
&local.fn_defs(),
&[
"top_level",
"dummy::public_fn",
"dummy::private_fn",
"dummy::PrivateStruct::new",
"<dummy::PrivateStruct as std::ops::Drop>::drop",
"DummyTrait::method",
"<T as DummyTrait>::method",
],
);
// Find items inside core crate.
// FIXME: We are currently missing primitive type methods and trait implementations for external
// crates.
let core = stable_mir::find_crates("core").pop().expect("Cannot find `core` crate");
contains(
&core.fn_defs(),
&[
"std::fmt::Debug::fmt",
"std::option::Option::<T>::is_some",
"std::ptr::swap",
"<std::slice::Iter<'a, T> as std::iter::Iterator>::next",
"core::num::<impl u8>::abs_diff",
],
);
// Ensure nothing crashes. There is no public static in core that we can test here.
let _ = core.statics();
ControlFlow::Continue(())
}
/// Check if the list of definitions matches the expected list.
/// Note that order doesn't matter.
fn check_items<T: CrateDef>(items: &[T], expected: &[&str]) {
let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect();
let item_names: HashSet<_> = items.iter().map(|item| item.name()).collect();
assert_eq!(item_names, expected);
}
/// Check that the list contains the expected items.
fn contains<T: CrateDef + std::fmt::Debug>(items: &[T], expected: &[&str]) {
let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect();
let item_names = items.iter().map(|item| item.name()).collect();
let not_found: Vec<_> = expected.difference(&item_names).collect();
assert!(not_found.is_empty(), "Missing items: {:?}", not_found);
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then
/// it will run the compiler.
fn main() {
let path = "crate_definitions.rs";
generate_input(&path).unwrap();
let args = vec![
"rustc".to_string(),
"--crate-type=lib".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
];
run!(args, test_stable_mir).unwrap();
}
fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
#![allow(dead_code, unused_variables)]
static PRIVATE_STATIC: u8 = 0;
fn top_level() -> &'static str {{
"hello"
}}
pub trait DummyTrait {{
fn method(&self) -> Self;
}}
impl<T: Copy> DummyTrait for T {{
fn method(&self) -> T {{
*self
}}
}}
pub mod dummy {{
pub static mut PUBLIC_STATIC: Option<char> = None;
pub fn public_fn(input: bool) -> bool {{
private_fn(!input)
}}
fn private_fn(input: bool) -> bool {{
todo!()
}}
struct PrivateStruct {{
field: u32,
}}
impl PrivateStruct {{
fn new() -> Self {{
Self {{ field: 42 }}
}}
}}
impl Drop for PrivateStruct {{
fn drop(&mut self) {{
println!("Dropping PrivateStruct");
}}
}}
}}
"#
)?;
Ok(())
}