1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! A library for inspecting Rust code
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

/// Available configuration settings when using cargo-inspect as a library
pub mod config;

mod comment;
/// Contains all types defined for error handling
pub mod errors;
mod format;
mod hir;

use prettyprint::PrettyPrinter;

use crate::comment::comment_file;
pub use crate::config::{Config, Opt};
pub use crate::errors::InspectError;
use crate::format::format;
use crate::hir::HIR;
use std::env;
use std::fs::{self, File};
use std::path::PathBuf;
use tempfile::tempdir;

/// inspect takes a Rust file or crate as an input and returns the desugared
/// output.
pub fn inspect(config: &Config) -> Result<(), InspectError> {
    let hir = match config.input {
        Some(_) => inspect_file(config),
        None => inspect_crate(config),
    }?;

    let formatted = format(hir.output)?;

    if config.plain {
        println!("{}", formatted);
    } else {
        let printer = PrettyPrinter::default().language("rust").build()?;
        let header = config.input.to_owned().unwrap_or(env::current_dir()?);
        printer.string_with_header(formatted, header.to_string_lossy().to_string())?;
    }
    Ok(())
}

/// Run cargo-inspect on a file
fn inspect_file(config: &Config) -> Result<HIR, InspectError> {
    let input: &PathBuf = match &config.input {
        Some(input) => input,
        None => return Err(InspectError::Generic("No file to analyze".to_string())),
    };

    let input = match config.verbose {
        true => {
            // Create a temporary copy of the input file,
            // which contains comments for each input line
            // to avoid modifying the original input file.
            // This will be used as the input of rustc.
            let tmp = tmpfile()?;
            fs::copy(&input, &tmp)?;
            comment_file(&tmp)?;
            tmp
        }
        false => input.into(),
    };
    hir::from_file(&input, &config.unpretty)
}

/// Run cargo-inspect on a crate
fn inspect_crate(config: &Config) -> Result<HIR, InspectError> {
    if config.verbose {
        unimplemented!(
            "Verbose option doesn't work for crates yet. \
             See https://github.com/mre/cargo-inspect/issues/5"
        )
        // comment_crate()?;
    }
    hir::from_crate(&config.unpretty)
}

fn tmpfile() -> Result<PathBuf, InspectError> {
    let tmp_path = tempdir()?.into_path();
    let file_path = tmp_path.join("temp.rs");
    File::create(&file_path)?;
    Ok(file_path)
}