fix_getters_utils/
scope.rs

1//! Rust code scope identification.
2
3use std::{cell::RefCell, fmt, rc::Rc, string::ToString};
4
5/// Rust code scope identification.
6#[derive(Debug)]
7pub enum Scope {
8    Attribute(String),
9    Const(String),
10    Documentation,
11    Fn(String),
12    Macro(String),
13    Static(String),
14    StructImpl(String),
15    Trait(String),
16    TraitImpl { trait_: String, type_: String },
17    Unexpected,
18}
19
20impl Default for Scope {
21    fn default() -> Self {
22        Scope::Unexpected
23    }
24}
25
26impl From<&syn::Item> for Scope {
27    fn from(node: &syn::Item) -> Self {
28        match node {
29            syn::Item::Const(item) => Scope::Const(item.ident.to_string()),
30            syn::Item::Fn(fn_) => Scope::Fn(fn_.sig.ident.to_string()),
31            syn::Item::Impl(impl_) => {
32                let type_ident = format_type_name(&impl_.self_ty);
33
34                if let Some((_, trait_path, _)) = &impl_.trait_ {
35                    let trait_ident = path_ident(&trait_path);
36
37                    Scope::TraitImpl {
38                        trait_: trait_ident,
39                        type_: type_ident,
40                    }
41                } else {
42                    Scope::StructImpl(type_ident)
43                }
44            }
45            syn::Item::Macro(macro_) => Scope::Macro(
46                macro_
47                    .ident
48                    .as_ref()
49                    .map(|ident| ident.to_string())
50                    .unwrap_or_else(|| "unnamed".to_string()),
51            ),
52            syn::Item::Macro2(macro2) => Scope::Macro(macro2.ident.to_string()),
53            syn::Item::Static(static_) => Scope::Static(static_.ident.to_string()),
54            syn::Item::Trait(trait_) => Scope::Trait(trait_.ident.to_string()),
55            _ => Scope::Unexpected,
56        }
57    }
58}
59
60impl From<&syn::Attribute> for Scope {
61    fn from(node: &syn::Attribute) -> Self {
62        Scope::Attribute(path_ident(&node.path))
63    }
64}
65
66impl From<&syn::Macro> for Scope {
67    fn from(node: &syn::Macro) -> Self {
68        Scope::Macro(path_ident(&node.path))
69    }
70}
71
72impl From<Scope> for Rc<RefCell<Scope>> {
73    fn from(scope: Scope) -> Self {
74        Rc::new(RefCell::new(scope))
75    }
76}
77
78impl fmt::Display for Scope {
79    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
80        use Scope::*;
81
82        match self {
83            Attribute(name) => write!(f, "attr {}", name),
84            Const(name) => write!(f, "const {}", name),
85            Documentation => f.write_str("doc code"),
86            Fn(name) => write!(f, "fn {}", name),
87            Macro(name) => write!(f, "macro! {}", name),
88            Static(name) => write!(f, "static {}", name),
89            StructImpl(struct_) => f.write_str(struct_),
90            Trait(trait_) => f.write_str(trait_),
91            TraitImpl { trait_, type_ } => write!(f, "impl {} for {}", trait_, type_),
92            Unexpected => f.write_str("**Unexpected scope**"),
93        }
94    }
95}
96
97fn path_ident(path: &syn::Path) -> String {
98    if path.segments.is_empty() {
99        return String::default();
100    }
101    path.segments.last().unwrap().ident.to_string()
102}
103
104fn format_type_name(self_ty: &syn::Type) -> String {
105    match self_ty {
106        syn::Type::Path(path) => path_ident(&path.path),
107        syn::Type::Reference(ref_) => {
108            let prefix = match &ref_.lifetime {
109                None => if ref_.mutability.is_some() {
110                    "&mut "
111                } else {
112                    "&"
113                }
114                .to_string(),
115                Some(lifetime) => {
116                    if ref_.mutability.is_some() {
117                        format!("&{} mut ", lifetime.to_string())
118                    } else {
119                        format!("&{} ", lifetime.to_string())
120                    }
121                }
122            };
123
124            format!("{}{}", prefix, format_type_name(&ref_.elem))
125        }
126        syn::Type::Slice(slice) => format!("[{}]", format_type_name(&slice.elem)),
127        syn::Type::TraitObject(trait_obj) => {
128            let mut trait_bound = "dyn ".to_string();
129            for (idx, bound) in trait_obj.bounds.iter().enumerate() {
130                if idx > 0 {
131                    trait_bound += " + ";
132                }
133
134                if let syn::TypeParamBound::Trait(trait_) = bound {
135                    trait_bound += &path_ident(&trait_.path);
136                }
137            }
138            trait_bound
139        }
140        syn::Type::Tuple(tuple) => {
141            let mut tuple_str = "(".to_string();
142            for (idx, elem) in tuple.elems.iter().enumerate() {
143                if idx > 0 {
144                    tuple_str += ", ";
145                }
146
147                tuple_str += &format_type_name(elem);
148            }
149            tuple_str + ")"
150        }
151        syn::Type::Paren(paren) => {
152            format!("({})", format_type_name(&paren.elem))
153        }
154        syn::Type::Ptr(ptr) => {
155            format!("*{}", format_type_name(&ptr.elem))
156        }
157        _ => unimplemented!("format type formatting for {:#?}", self_ty),
158    }
159}