1use hir::{DefWithBody, Semantics};
2use ide_db::{FilePosition, RootDatabase};
3use syntax::{AstNode, algo::ancestors_at_offset, ast};
4
5pub(crate) fn view_mir(db: &RootDatabase, position: FilePosition) -> String {
11 body_mir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
12}
13
14fn body_mir(db: &RootDatabase, position: FilePosition) -> Option<String> {
15 let sema = Semantics::new(db);
16 let source_file = sema.parse_guess_edition(position.file_id);
17
18 let item = ancestors_at_offset(source_file.syntax(), position.offset)
19 .filter(|it| !ast::MacroCall::can_cast(it.kind()))
20 .find_map(ast::Item::cast)?;
21 let def: DefWithBody = match item {
22 ast::Item::Fn(it) => sema.to_def(&it)?.into(),
23 ast::Item::Const(it) => sema.to_def(&it)?.into(),
24 ast::Item::Static(it) => sema.to_def(&it)?.into(),
25 _ => return None,
26 };
27 Some(def.debug_mir(db))
28}
29
30#[cfg(test)]
31mod tests {
32 use crate::fixture;
33
34 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
35 let (analysis, position) = fixture::position(ra_fixture);
36 let mir = analysis.view_mir(position);
37 assert!(mir.is_ok());
38 }
39
40 #[test]
41 fn tuple_field_projection_uses_base_type() {
42 check(
43 r#"
44//- minicore: sized
45struct Inner { value: u32 }
46fn test$0(value: (u32, Inner)) -> Inner { value.1 }
47"#,
48 );
49 }
50
51 #[test]
52 fn nested_struct_field_projection_uses_base_type() {
53 check(
54 r#"
55//- minicore: sized
56struct Inner { value: u32 }
57struct Outer { first: u32, second: Inner }
58fn test$0(value: Outer) -> u32 { value.second.value }
59"#,
60 );
61 }
62
63 #[test]
64 fn enum_field_projection_uses_base_variant() {
65 check(
66 r#"
67//- minicore: sized
68struct Inner { value: u32 }
69enum Outer { Variant { first: u32, second: Inner } }
70fn test$0(value: Outer) -> Inner {
71 match value { Outer::Variant { second, .. } => second }
72}
73"#,
74 );
75 }
76}