anodized_core/instrument/
impls.rs1#[cfg(test)]
2#[path = "impls_tests.rs"]
3mod impls_tests;
4
5use syn::{
6 Attribute, Error, ImplItem, ImplItemFn, ItemImpl, Result, ReturnType, Visibility, parse_quote,
7};
8
9use crate::{
10 DataSpec, Spec,
11 instrument::{Mode, find_spec_attr, make_item_error},
12};
13
14impl Mode {
15 pub fn instrument_impl(&self, spec: DataSpec, mut the_impl: ItemImpl) -> Result<ItemImpl> {
20 if the_impl.trait_.is_some() {
21 return Err(make_item_error(&the_impl, "trait impl"));
22 };
23
24 if !spec.is_empty() {
25 return Err(spec.spec_err("Unsupported spec element on inherent impl."));
26 }
27
28 let mut new_items = Vec::with_capacity(the_impl.items.len() * 4);
29
30 for item in the_impl.items.into_iter() {
31 match item {
32 ImplItem::Fn(mut item_fn) => {
33 let (spec_attr, func_attrs) = find_spec_attr(item_fn.attrs)?;
34 item_fn.attrs = func_attrs;
35
36 if item_fn.sig.ident.to_string().starts_with("__anodized_") {
37 return Err(Error::new_spanned(
38 item_fn.sig.ident,
39 r#"An item with the `__anodized_` prefix is internal. Do not implement it directly.
40Instead, ensure that both the impl block and the fn have a `#[spec]` annotation."#,
41 ));
42 }
43
44 let fn_spec: Spec = match spec_attr {
45 Some(spec_attr) => spec_attr.parse_args()?,
46 None => Spec::empty(),
47 };
48
49 if let Self::EmbedSpecs = self {
50 let attrs: [Attribute; 2] = [
52 parse_quote!(#[doc(hidden)]),
53 parse_quote!(#[allow(warnings)]),
54 ];
55
56 let spec_qualifiers_const = Self::build_qualifier_const_item(
57 &attrs,
58 "__anodized_fn_qualifiers",
59 fn_spec.qualifiers,
60 &item_fn.sig.ident,
61 );
62 let spec_requires_fn = ImplItemFn {
63 attrs: attrs.to_vec(),
64 sig: Self::build_precondition_fn_sig(
65 "__anodized_fn_requires",
66 &item_fn.sig,
67 ),
68 block: Self::build_precondition_fn_body(
69 &fn_spec.requires,
70 &fn_spec.maintains,
71 ),
72 vis: Visibility::Inherited,
73 defaultness: None,
74 };
75 let spec_ensures_fn = ImplItemFn {
76 attrs: attrs.to_vec(),
77 sig: Self::build_postcondition_fn_sig(
78 "__anodized_fn_ensures",
79 &item_fn.sig,
80 ),
81 block: Self::build_postcondition_fn_body(
82 &fn_spec.maintains,
83 &fn_spec.captures,
84 &fn_spec.ensures,
85 )?,
86 vis: Visibility::Inherited,
87 defaultness: None,
88 };
89
90 new_items.push(ImplItem::Const(spec_qualifiers_const));
91 new_items.push(ImplItem::Fn(spec_requires_fn));
92 new_items.push(ImplItem::Fn(spec_ensures_fn));
93 }
94
95 self.instrument_fn(&fn_spec, &item_fn.sig, &mut item_fn.block)?;
97
98 if let Self::InjectChecks(check_settings) = self
99 && let Some(ref panic_settings) = check_settings.does_panic
100 && panic_settings.has_try_fn
101 {
102 let mut wrapper_fn = item_fn.clone();
104 let mangled_ident = Self::build_try_fn_wrapper(
105 true,
106 &mut wrapper_fn.sig,
107 &mut wrapper_fn.block,
108 );
109 new_items.push(ImplItem::Fn(wrapper_fn));
110
111 item_fn.sig.ident = mangled_ident;
113 item_fn.sig.output = match item_fn.sig.output {
114 ReturnType::Default => {
115 parse_quote!(-> ::anodized::result::Result<()>)
116 }
117 ReturnType::Type(ra, ty) => {
118 parse_quote!(#ra ::anodized::result::Result<#ty>)
119 }
120 };
121 item_fn.attrs = vec![parse_quote!(#[doc(hidden)]), parse_quote!(#[inline])];
122 }
123
124 new_items.push(ImplItem::Fn(item_fn));
125 }
126 ImplItem::Const(mut const_item) => {
127 let (spec, attrs) = find_spec_attr(const_item.attrs)?;
128 if let Some(ref spec_attr) = spec {
129 return Err(make_item_error(&spec_attr, "impl const"));
130 }
131 const_item.attrs = attrs;
132 new_items.push(ImplItem::Const(const_item));
133 }
134 ImplItem::Type(mut type_item) => {
135 let (spec, attrs) = find_spec_attr(type_item.attrs)?;
136 if let Some(ref spec_attr) = spec {
137 return Err(make_item_error(&spec_attr, "impl type"));
138 }
139 type_item.attrs = attrs;
140 new_items.push(ImplItem::Type(type_item));
141 }
142 ImplItem::Macro(mut macro_item) => {
143 let (spec, attrs) = find_spec_attr(macro_item.attrs)?;
144 if let Some(ref spec_attr) = spec {
145 return Err(make_item_error(&spec_attr, "impl macro"));
146 }
147 macro_item.attrs = attrs;
148 new_items.push(ImplItem::Macro(macro_item));
149 }
150 ImplItem::Verbatim(token_stream) => {
151 new_items.push(ImplItem::Verbatim(token_stream))
152 }
153 _ => unimplemented!(),
154 };
155 }
156
157 the_impl.items = new_items;
158 Ok(the_impl)
159 }
160}