Skip to main content

rust_code_analysis_code_split/output/
dump_metrics.rs

1use std::io::Write;
2use termcolor::{Color, ColorChoice, StandardStream, StandardStreamLock};
3
4use crate::abc;
5use crate::cognitive;
6use crate::cyclomatic;
7use crate::exit;
8use crate::halstead;
9use crate::loc;
10use crate::mi;
11use crate::nargs;
12use crate::nom;
13use crate::npa;
14use crate::npm;
15use crate::wmc;
16
17use crate::spaces::{CodeMetrics, FuncSpace};
18
19use crate::tools::{color, intense_color};
20
21/// Dumps the metrics of a code.
22///
23/// Returns a [`Result`] value, when an error occurs.
24///
25/// # Examples
26///
27/// ```
28/// use std::path::PathBuf;
29///
30/// use rust_code_analysis::{dump_root, metrics, CppParser, ParserTrait};
31///
32/// let source_code = "int a = 42;";
33///
34/// // The path to a dummy file used to contain the source code
35/// let path = PathBuf::from("foo.c");
36/// let source_as_vec = source_code.as_bytes().to_vec();
37///
38/// // The parser of the code, in this case a CPP parser
39/// let parser = CppParser::new(source_as_vec, &path, None);
40///
41/// // Compute metrics
42/// let space = metrics(&parser, &path).unwrap();
43///
44/// // Dump all metrics
45/// dump_root(&space).unwrap();
46/// ```
47///
48/// [`Result`]: #variant.Result
49pub fn dump_root(space: &FuncSpace) -> std::io::Result<()> {
50    let stdout = StandardStream::stdout(ColorChoice::Always);
51    let mut stdout = stdout.lock();
52    dump_space(space, "", true, &mut stdout)?;
53    color(&mut stdout, Color::White)?;
54
55    Ok(())
56}
57
58fn dump_space(
59    space: &FuncSpace,
60    prefix: &str,
61    last: bool,
62    stdout: &mut StandardStreamLock,
63) -> std::io::Result<()> {
64    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
65
66    color(stdout, Color::Blue)?;
67    write!(stdout, "{prefix}{pref}")?;
68
69    intense_color(stdout, Color::Yellow)?;
70    write!(stdout, "{}: ", space.kind)?;
71
72    intense_color(stdout, Color::Cyan)?;
73    write!(stdout, "{}", space.name.as_ref().map_or("", |name| name))?;
74
75    intense_color(stdout, Color::Red)?;
76    writeln!(stdout, " (@{})", space.start_line)?;
77
78    let prefix = format!("{prefix}{pref_child}");
79    dump_metrics(&space.metrics, &prefix, space.spaces.is_empty(), stdout)?;
80
81    if let Some((last, spaces)) = space.spaces.split_last() {
82        for space in spaces {
83            dump_space(space, &prefix, false, stdout)?;
84        }
85        dump_space(last, &prefix, true, stdout)?;
86    }
87
88    Ok(())
89}
90
91fn dump_metrics(
92    metrics: &CodeMetrics,
93    prefix: &str,
94    last: bool,
95    stdout: &mut StandardStreamLock,
96) -> std::io::Result<()> {
97    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
98
99    color(stdout, Color::Blue)?;
100    write!(stdout, "{prefix}{pref}")?;
101
102    intense_color(stdout, Color::Yellow)?;
103    writeln!(stdout, "metrics")?;
104
105    let prefix = format!("{prefix}{pref_child}");
106    dump_cognitive(&metrics.cognitive, &prefix, false, stdout)?;
107    dump_cyclomatic(&metrics.cyclomatic, &prefix, false, stdout)?;
108    dump_nargs(&metrics.nargs, &prefix, false, stdout)?;
109    dump_nexits(&metrics.nexits, &prefix, false, stdout)?;
110    dump_halstead(&metrics.halstead, &prefix, false, stdout)?;
111    dump_loc(&metrics.loc, &prefix, false, stdout)?;
112    dump_nom(&metrics.nom, &prefix, false, stdout)?;
113    dump_mi(&metrics.mi, &prefix, false, stdout)?;
114    dump_abc(&metrics.abc, &prefix, false, stdout)?;
115    dump_wmc(&metrics.wmc, &prefix, false, stdout)?;
116    dump_npm(&metrics.npm, &prefix, false, stdout)?;
117    dump_npa(&metrics.npa, &prefix, true, stdout)
118}
119
120fn dump_cognitive(
121    stats: &cognitive::Stats,
122    prefix: &str,
123    last: bool,
124    stdout: &mut StandardStreamLock,
125) -> std::io::Result<()> {
126    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
127
128    color(stdout, Color::Blue)?;
129    write!(stdout, "{prefix}{pref}")?;
130
131    intense_color(stdout, Color::Green)?;
132    writeln!(stdout, "cognitive")?;
133
134    let prefix = format!("{prefix}{pref_child}");
135
136    dump_value("sum", stats.cognitive(), &prefix, false, stdout)?;
137    dump_value("average", stats.cognitive_average(), &prefix, true, stdout)
138}
139
140fn dump_cyclomatic(
141    stats: &cyclomatic::Stats,
142    prefix: &str,
143    last: bool,
144    stdout: &mut StandardStreamLock,
145) -> std::io::Result<()> {
146    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
147
148    color(stdout, Color::Blue)?;
149    write!(stdout, "{prefix}{pref}")?;
150
151    intense_color(stdout, Color::Green)?;
152    writeln!(stdout, "cyclomatic")?;
153
154    let prefix = format!("{prefix}{pref_child}");
155
156    dump_value("sum", stats.cyclomatic(), &prefix, false, stdout)?;
157    dump_value("average", stats.cyclomatic_average(), &prefix, true, stdout)
158}
159
160fn dump_halstead(
161    stats: &halstead::Stats,
162    prefix: &str,
163    last: bool,
164    stdout: &mut StandardStreamLock,
165) -> std::io::Result<()> {
166    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
167
168    color(stdout, Color::Blue)?;
169    write!(stdout, "{prefix}{pref}")?;
170
171    intense_color(stdout, Color::Green)?;
172    writeln!(stdout, "halstead")?;
173
174    let prefix = format!("{prefix}{pref_child}");
175
176    dump_value("n1", stats.u_operators(), &prefix, false, stdout)?;
177    dump_value("N1", stats.operators(), &prefix, false, stdout)?;
178    dump_value("n2", stats.u_operands(), &prefix, false, stdout)?;
179    dump_value("N2", stats.operands(), &prefix, false, stdout)?;
180
181    dump_value("length", stats.length(), &prefix, false, stdout)?;
182    dump_value(
183        "estimated program length",
184        stats.estimated_program_length(),
185        &prefix,
186        false,
187        stdout,
188    )?;
189    dump_value("purity ratio", stats.purity_ratio(), &prefix, false, stdout)?;
190    dump_value("vocabulary", stats.vocabulary(), &prefix, false, stdout)?;
191    dump_value("volume", stats.volume(), &prefix, false, stdout)?;
192    dump_value("difficulty", stats.difficulty(), &prefix, false, stdout)?;
193    dump_value("level", stats.level(), &prefix, false, stdout)?;
194    dump_value("effort", stats.effort(), &prefix, false, stdout)?;
195    dump_value("time", stats.time(), &prefix, false, stdout)?;
196    dump_value("bugs", stats.bugs(), &prefix, true, stdout)
197}
198
199fn dump_loc(
200    stats: &loc::Stats,
201    prefix: &str,
202    last: bool,
203    stdout: &mut StandardStreamLock,
204) -> std::io::Result<()> {
205    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
206
207    color(stdout, Color::Blue)?;
208    write!(stdout, "{prefix}{pref}")?;
209
210    intense_color(stdout, Color::Green)?;
211    writeln!(stdout, "loc")?;
212
213    let prefix = format!("{prefix}{pref_child}");
214    dump_value("sloc", stats.sloc(), &prefix, false, stdout)?;
215    dump_value("ploc", stats.ploc(), &prefix, false, stdout)?;
216    dump_value("lloc", stats.lloc(), &prefix, false, stdout)?;
217    dump_value("cloc", stats.cloc(), &prefix, false, stdout)?;
218    dump_value("blank", stats.blank(), &prefix, true, stdout)
219}
220
221fn dump_nom(
222    stats: &nom::Stats,
223    prefix: &str,
224    last: bool,
225    stdout: &mut StandardStreamLock,
226) -> std::io::Result<()> {
227    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
228
229    color(stdout, Color::Blue)?;
230    write!(stdout, "{prefix}{pref}")?;
231
232    intense_color(stdout, Color::Green)?;
233    writeln!(stdout, "nom")?;
234
235    let prefix = format!("{prefix}{pref_child}");
236    dump_value("functions", stats.functions(), &prefix, false, stdout)?;
237    dump_value("closures", stats.closures(), &prefix, false, stdout)?;
238    dump_value("total", stats.total(), &prefix, true, stdout)
239}
240
241fn dump_mi(
242    stats: &mi::Stats,
243    prefix: &str,
244    last: bool,
245    stdout: &mut StandardStreamLock,
246) -> std::io::Result<()> {
247    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
248
249    color(stdout, Color::Blue)?;
250    write!(stdout, "{prefix}{pref}")?;
251
252    intense_color(stdout, Color::Green)?;
253    writeln!(stdout, "mi")?;
254
255    let prefix = format!("{prefix}{pref_child}");
256    dump_value("mi_original", stats.mi_original(), &prefix, false, stdout)?;
257    dump_value("mi_sei", stats.mi_sei(), &prefix, false, stdout)?;
258    dump_value(
259        "mi_visual_studio",
260        stats.mi_visual_studio(),
261        &prefix,
262        true,
263        stdout,
264    )
265}
266
267fn dump_nargs(
268    stats: &nargs::Stats,
269    prefix: &str,
270    last: bool,
271    stdout: &mut StandardStreamLock,
272) -> std::io::Result<()> {
273    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
274
275    color(stdout, Color::Blue)?;
276    write!(stdout, "{prefix}{pref}")?;
277
278    intense_color(stdout, Color::Green)?;
279    writeln!(stdout, "nargs")?;
280
281    let prefix = format!("{prefix}{pref_child}");
282    dump_value("functions", stats.fn_args(), &prefix, false, stdout)?;
283    dump_value("closures", stats.closure_args(), &prefix, false, stdout)?;
284    dump_value("total", stats.nargs_total(), &prefix, false, stdout)?;
285    dump_value("average", stats.nargs_average(), &prefix, true, stdout)
286}
287
288fn dump_nexits(
289    stats: &exit::Stats,
290    prefix: &str,
291    last: bool,
292    stdout: &mut StandardStreamLock,
293) -> std::io::Result<()> {
294    let pref = if last { "`- " } else { "|- " };
295
296    color(stdout, Color::Blue)?;
297    write!(stdout, "{prefix}{pref}")?;
298
299    intense_color(stdout, Color::Green)?;
300    write!(stdout, "nexits: ")?;
301
302    color(stdout, Color::White)?;
303    writeln!(stdout, "{}", stats.exit())
304}
305
306fn dump_abc(
307    stats: &abc::Stats,
308    prefix: &str,
309    last: bool,
310    stdout: &mut StandardStreamLock,
311) -> std::io::Result<()> {
312    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
313
314    color(stdout, Color::Blue)?;
315    write!(stdout, "{prefix}{pref}")?;
316
317    intense_color(stdout, Color::Green)?;
318    writeln!(stdout, "abc")?;
319
320    let prefix = format!("{prefix}{pref_child}");
321
322    dump_value(
323        "assignments",
324        stats.assignments_sum(),
325        &prefix,
326        false,
327        stdout,
328    )?;
329    dump_value("branches", stats.branches_sum(), &prefix, false, stdout)?;
330    dump_value("conditions", stats.conditions_sum(), &prefix, false, stdout)?;
331    dump_value("magnitude", stats.magnitude_sum(), &prefix, true, stdout)
332}
333
334fn dump_wmc(
335    stats: &wmc::Stats,
336    prefix: &str,
337    last: bool,
338    stdout: &mut StandardStreamLock,
339) -> std::io::Result<()> {
340    if stats.is_disabled() {
341        return Ok(());
342    }
343
344    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
345
346    color(stdout, Color::Blue)?;
347    write!(stdout, "{prefix}{pref}")?;
348
349    intense_color(stdout, Color::Green)?;
350    writeln!(stdout, "wmc")?;
351
352    let prefix = format!("{prefix}{pref_child}");
353    dump_value("classes", stats.class_wmc_sum(), &prefix, false, stdout)?;
354    dump_value(
355        "interfaces",
356        stats.interface_wmc_sum(),
357        &prefix,
358        false,
359        stdout,
360    )?;
361    dump_value("total", stats.total_wmc(), &prefix, true, stdout)
362}
363
364fn dump_npm(
365    stats: &npm::Stats,
366    prefix: &str,
367    last: bool,
368    stdout: &mut StandardStreamLock,
369) -> std::io::Result<()> {
370    if stats.is_disabled() {
371        return Ok(());
372    }
373
374    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
375
376    color(stdout, Color::Blue)?;
377    write!(stdout, "{prefix}{pref}")?;
378
379    intense_color(stdout, Color::Green)?;
380    writeln!(stdout, "npm")?;
381
382    let prefix = format!("{prefix}{pref_child}");
383    dump_value("classes", stats.class_npm_sum(), &prefix, false, stdout)?;
384    dump_value(
385        "interfaces",
386        stats.interface_npm_sum(),
387        &prefix,
388        false,
389        stdout,
390    )?;
391    dump_value("total", stats.total_npm(), &prefix, false, stdout)?;
392    dump_value("average", stats.total_coa(), &prefix, true, stdout)
393}
394
395fn dump_npa(
396    stats: &npa::Stats,
397    prefix: &str,
398    last: bool,
399    stdout: &mut StandardStreamLock,
400) -> std::io::Result<()> {
401    if stats.is_disabled() {
402        return Ok(());
403    }
404
405    let (pref_child, pref) = if last { ("   ", "`- ") } else { ("|  ", "|- ") };
406
407    color(stdout, Color::Blue)?;
408    write!(stdout, "{prefix}{pref}")?;
409
410    intense_color(stdout, Color::Green)?;
411    writeln!(stdout, "npa")?;
412
413    let prefix = format!("{prefix}{pref_child}");
414    dump_value("classes", stats.class_npa_sum(), &prefix, false, stdout)?;
415    dump_value(
416        "interfaces",
417        stats.interface_npa_sum(),
418        &prefix,
419        false,
420        stdout,
421    )?;
422    dump_value("total", stats.total_npa(), &prefix, false, stdout)?;
423    dump_value("average", stats.total_cda(), &prefix, true, stdout)
424}
425
426fn dump_value(
427    name: &str,
428    val: f64,
429    prefix: &str,
430    last: bool,
431    stdout: &mut StandardStreamLock,
432) -> std::io::Result<()> {
433    let pref = if last { "`- " } else { "|- " };
434
435    color(stdout, Color::Blue)?;
436    write!(stdout, "{prefix}{pref}")?;
437
438    intense_color(stdout, Color::Magenta)?;
439    write!(stdout, "{name}: ")?;
440
441    color(stdout, Color::White)?;
442    writeln!(stdout, "{val}")
443}