1use std::fs;
4use std::path::Path;
5
6use syn::{
7 Attribute, Expr, ExprLit, Item, ItemMod, ItemUse, Lit, Meta, UseGroup, UseName, UsePath,
8 UseRename, UseTree,
9};
10
11use crate::ParseError;
12
13pub fn parse_file(path: &Path) -> Result<syn::File, ParseError> {
19 let content = fs::read_to_string(path).map_err(|error| ParseError::Io {
20 path: path.to_path_buf(),
21 error,
22 })?;
23 syn::parse_file(&content).map_err(|error| ParseError::Syntax {
24 path: path.to_path_buf(),
25 error,
26 })
27}
28
29#[must_use]
31pub fn extract_mod_declarations(file: &syn::File) -> Vec<&ItemMod> {
32 file.items
33 .iter()
34 .filter_map(|item| {
35 if let Item::Mod(item_mod) = item {
36 Some(item_mod)
37 } else {
38 None
39 }
40 })
41 .collect()
42}
43
44#[must_use]
46pub fn extract_use_statements(file: &syn::File) -> Vec<&ItemUse> {
47 file.items
48 .iter()
49 .filter_map(|item| {
50 if let Item::Use(item_use) = item {
51 Some(item_use)
52 } else {
53 None
54 }
55 })
56 .collect()
57}
58
59#[must_use]
61pub fn get_path_attribute(item_mod: &ItemMod) -> Option<String> {
62 find_path_in_attrs(&item_mod.attrs)
63}
64
65fn find_path_in_attrs(attrs: &[Attribute]) -> Option<String> {
67 for attr in attrs {
68 if attr.path().is_ident("path") {
69 if let Meta::NameValue(nv) = &attr.meta {
70 if let Expr::Lit(ExprLit {
71 lit: Lit::Str(s), ..
72 }) = &nv.value
73 {
74 return Some(s.value());
75 }
76 }
77 }
78 }
79 None
80}
81
82pub fn walk_use_tree(
84 tree: &UseTree,
85 current_path: &mut Vec<String>,
86 results: &mut Vec<Vec<String>>,
87) {
88 match tree {
89 UseTree::Path(UsePath { ident, tree, .. }) => {
90 current_path.push(ident.to_string());
91 walk_use_tree(tree, current_path, results);
92 current_path.pop();
93 }
94 UseTree::Name(UseName { ident, .. }) | UseTree::Rename(UseRename { ident, .. }) => {
95 current_path.push(ident.to_string());
96 results.push(current_path.clone());
97 current_path.pop();
98 }
99 UseTree::Glob(_) => {
100 results.push(current_path.clone());
102 }
103 UseTree::Group(UseGroup { items, .. }) => {
104 for item in items {
105 walk_use_tree(item, current_path, results);
106 }
107 }
108 }
109}
110
111#[must_use]
113pub fn extract_use_paths(item_use: &ItemUse) -> Vec<Vec<String>> {
114 let mut results = Vec::new();
115 let mut path = Vec::new();
116 walk_use_tree(&item_use.tree, &mut path, &mut results);
117 results
118}