rust_code_analysis/
function.rs

1use std::io::Write;
2use std::path::PathBuf;
3
4use serde::Serialize;
5use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLock, WriteColor};
6
7use crate::traits::*;
8
9use crate::checker::Checker;
10use crate::getter::Getter;
11
12/// Function span data.
13#[derive(Debug, Serialize)]
14pub struct FunctionSpan {
15    /// The function name
16    pub name: String,
17    /// The first line of a function
18    pub start_line: usize,
19    /// The last line of a function
20    pub end_line: usize,
21    /// If `true`, an error is occurred in determining the span
22    /// of a function
23    pub error: bool,
24}
25
26/// Detects the span of each function in a code.
27///
28/// Returns a vector containing the [`FunctionSpan`] of each function
29///
30/// [`FunctionSpan`]: struct.FunctionSpan.html
31pub fn function<T: ParserTrait>(parser: &T) -> Vec<FunctionSpan> {
32    let root = parser.get_root();
33    let code = parser.get_code();
34    let mut spans = Vec::new();
35    root.act_on_node(&mut |n| {
36        if T::Checker::is_func(n) {
37            let start_line = n.object().start_position().row + 1;
38            let end_line = n.object().end_position().row + 1;
39            if let Some(name) = T::Getter::get_func_name(n, code) {
40                spans.push(FunctionSpan {
41                    name: name.to_string(),
42                    start_line,
43                    end_line,
44                    error: false,
45                });
46            } else {
47                spans.push(FunctionSpan {
48                    name: "".to_string(),
49                    start_line,
50                    end_line,
51                    error: true,
52                });
53            }
54        }
55    });
56
57    spans
58}
59
60fn dump_span(
61    span: FunctionSpan,
62    stdout: &mut StandardStreamLock,
63    last: bool,
64) -> std::io::Result<()> {
65    /*if !span.error {
66        return Ok(());
67    }*/
68
69    let pref = if last { "   `- " } else { "   |- " };
70
71    color!(stdout, Blue);
72    write!(stdout, "{}", pref)?;
73
74    if span.error {
75        color!(stdout, Red, true);
76        write!(stdout, "error: ")?;
77    } else {
78        color!(stdout, Magenta, true);
79        write!(stdout, "{}: ", span.name)?;
80    }
81
82    color!(stdout, Green);
83    write!(stdout, "from line ")?;
84
85    color!(stdout, White);
86    write!(stdout, "{}", span.start_line)?;
87
88    color!(stdout, Green);
89    write!(stdout, " to line ")?;
90
91    color!(stdout, White);
92    writeln!(stdout, "{}.", span.end_line)
93}
94
95fn dump_spans(mut spans: Vec<FunctionSpan>, path: PathBuf) -> std::io::Result<()> {
96    if !spans.is_empty() {
97        let stdout = StandardStream::stdout(ColorChoice::Always);
98        let mut stdout = stdout.lock();
99
100        color!(stdout, Yellow, true);
101        writeln!(&mut stdout, "In file {}", path.to_str().unwrap_or("..."))?;
102
103        for span in spans.drain(..spans.len() - 1) {
104            dump_span(span, &mut stdout, false)?;
105        }
106        dump_span(spans.pop().unwrap(), &mut stdout, true)?;
107        color!(stdout, White);
108    }
109    Ok(())
110}
111
112/// Configuration options for detecting the span of
113/// each function in a code.
114pub struct FunctionCfg {
115    /// Path to the file containing the code
116    pub path: PathBuf,
117}
118
119pub struct Function {
120    _guard: (),
121}
122
123impl Callback for Function {
124    type Res = std::io::Result<()>;
125    type Cfg = FunctionCfg;
126
127    fn call<T: ParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
128        dump_spans(function(parser), cfg.path)
129    }
130}