rust_code_analysis_code_split/
parser.rs1use std::marker::PhantomData;
2use std::path::Path;
3use std::sync::Arc;
4
5use crate::abc::Abc;
6use crate::checker::Checker;
7use crate::cognitive::Cognitive;
8use crate::cyclomatic::Cyclomatic;
9use crate::exit::Exit;
10use crate::halstead::Halstead;
11use crate::loc::Loc;
12use crate::mi::Mi;
13use crate::nargs::NArgs;
14use crate::nom::Nom;
15use crate::npa::Npa;
16use crate::npm::Npm;
17use crate::wmc::Wmc;
18
19use crate::alterator::Alterator;
20use crate::getter::Getter;
21
22use crate::c_macro;
23use crate::langs::*;
24use crate::node::{Node, Tree};
25use crate::preproc::{PreprocResults, get_macros};
26use crate::traits::*;
27
28#[derive(Debug)]
29pub struct Parser<
30 T: LanguageInfo
31 + Alterator
32 + Checker
33 + Getter
34 + Abc
35 + Cognitive
36 + Cyclomatic
37 + Exit
38 + Halstead
39 + Loc
40 + Mi
41 + NArgs
42 + Nom
43 + Npa
44 + Npm
45 + Wmc,
46> {
47 code: Vec<u8>,
48 tree: Tree,
49 phantom: PhantomData<T>,
50}
51
52type FilterFn = dyn Fn(&Node) -> bool;
53
54pub struct Filter {
55 filters: Vec<Box<FilterFn>>,
56}
57
58impl Filter {
59 pub fn any(&self, node: &Node) -> bool {
60 for f in self.filters.iter() {
61 if f(node) {
62 return true;
63 }
64 }
65 false
66 }
67
68 pub fn all(&self, node: &Node) -> bool {
69 for f in self.filters.iter() {
70 if !f(node) {
71 return false;
72 }
73 }
74 true
75 }
76}
77
78#[inline(always)]
79fn get_fake_code<T: LanguageInfo>(
80 code: &[u8],
81 path: &Path,
82 pr: Option<Arc<PreprocResults>>,
83) -> Option<Vec<u8>> {
84 if let Some(pr) = pr {
85 match T::get_lang() {
86 LANG::Cpp => {
87 let macros = get_macros(path, &pr.files);
88 c_macro::replace(code, ¯os)
89 }
90 _ => None,
91 }
92 } else {
93 None
94 }
95}
96
97impl<
98 T: 'static
99 + LanguageInfo
100 + Alterator
101 + Checker
102 + Getter
103 + Abc
104 + Cognitive
105 + Cyclomatic
106 + Exit
107 + Halstead
108 + Loc
109 + Mi
110 + NArgs
111 + Nom
112 + Npa
113 + Npm
114 + Wmc,
115> ParserTrait for Parser<T>
116{
117 type Checker = T;
118 type Getter = T;
119 type Cognitive = T;
120 type Cyclomatic = T;
121 type Halstead = T;
122 type Loc = T;
123 type Nom = T;
124 type Mi = T;
125 type NArgs = T;
126 type Exit = T;
127 type Wmc = T;
128 type Abc = T;
129 type Npm = T;
130 type Npa = T;
131
132 fn new(code: Vec<u8>, path: &Path, pr: Option<Arc<PreprocResults>>) -> Self {
133 let fake_code = get_fake_code::<T>(&code, path, pr);
134 let code = if let Some(fake) = fake_code {
135 fake
136 } else {
137 code
138 };
139
140 let tree = Tree::new::<T>(&code);
141
142 Self {
143 code,
144 tree,
145 phantom: PhantomData,
146 }
147 }
148
149 #[inline(always)]
150 fn get_language(&self) -> LANG {
151 T::get_lang()
152 }
153
154 #[inline(always)]
155 fn get_root(&self) -> Node<'_> {
156 self.tree.get_root()
157 }
158
159 #[inline(always)]
160 fn get_code(&self) -> &[u8] {
161 &self.code
162 }
163
164 fn get_filters(&self, filters: &[String]) -> Filter {
165 let mut res: Vec<Box<FilterFn>> = Vec::new();
166 for f in filters.iter() {
167 let f = f.as_str();
168 match f {
169 "all" => res.push(Box::new(|_: &Node| -> bool { true })),
170 "call" => res.push(Box::new(T::is_call)),
171 "comment" => res.push(Box::new(T::is_comment)),
172 "error" => res.push(Box::new(T::is_error)),
173 "string" => res.push(Box::new(T::is_string)),
174 "function" => res.push(Box::new(T::is_func)),
175 _ => {
176 if let Ok(n) = f.parse::<u16>() {
177 res.push(Box::new(move |node: &Node| -> bool { node.kind_id() == n }));
178 } else {
179 let f = f.to_owned();
180 res.push(Box::new(move |node: &Node| -> bool {
181 node.kind().contains(&f)
182 }));
183 }
184 }
185 }
186 }
187 if res.is_empty() {
188 res.push(Box::new(|_: &Node| -> bool { true }))
189 }
190
191 Filter { filters: res }
192 }
193}