cargo_is_tested/
error.rs

1use miette::{Diagnostic, NamedSource, SourceSpan};
2use proc_macro2::LineColumn;
3use thiserror::Error;
4
5pub fn get_span(src: &str, start: &LineColumn, end: &LineColumn) -> SourceSpan {
6    let mut remaining_lines = end.line - 1;
7    let mut bytepos_start: usize = 0;
8    let mut bytepos_end: usize = 0;
9	for (i, c) in src.chars().enumerate() {
10        if c == '\n' {
11			if end.line - remaining_lines == start.line {
12				bytepos_end = i + start.column;
13				break;
14			} else {
15				bytepos_start = i + 1;
16			}
17			remaining_lines -= 1;
18        }
19    }
20
21    return (bytepos_start, bytepos_end - bytepos_start).into();
22}
23
24#[macro_export]
25macro_rules! span {
26    ($item: expr, $source: ident) => {{
27        $crate::error::get_span($source, &$item.span().start(), &$item.span().end())
28    }};
29}
30
31#[derive(Error, Debug, Diagnostic)]
32#[non_exhaustive]
33pub enum ErrorKind {
34    /// A file parse error.
35    /// This happens because:
36    ///
37    /// 1. These tokens are forming an item not interpreted by [`syn`], the parser we use.
38    /// 2. This item isn't yet implemented.
39    ///
40    /// Being that Rust is a language that is being developed, at any update it could introduce a new item, therefore the list of items needs to be non exhaustive. If this error is highlighting a new Rust feature, you can [open an issue](https://github.com/blyxyas/cargo-is-tested/issues)
41    ///
42    /// [More information about how `syn` parses items](https://docs.rs/syn/latest/syn/enum.Item.html)
43    ///
44    /// [`syn`]: https://docs.rs/syn
45    #[error("Couldn't parse this token")]
46    #[diagnostic(code(FILE_PARSE_ERROR), url(docsrs))]
47    FileParseError {
48        #[source_code]
49        src: NamedSource,
50        #[label("this token")]
51        span: SourceSpan,
52        #[help]
53        note: Option<String>,
54    },
55
56    #[error(transparent)]
57    #[diagnostic(code(IO_ERROR))]
58    IoError(#[from] std::io::Error),
59
60    // #[error("Unknown flag: `{flag}`")]
61    // UnknownFlag {
62    //     src: NamedSource,
63    //     flag: String,
64    //     span: SourceSpan,
65    // },
66    #[error("Unexpected token")]
67    #[diagnostic(
68        code(UNEXPECTED_TOKEN),
69        url(docsrs),
70        help("Try removing the the unexpected token in `{filename:?}`")
71    )]
72    UnexpectedToken {
73        filename: String,
74        // There's no span.
75    },
76
77    #[error("This lint doesn't exist")]
78    #[diagnostic(code(UNEXPECTED_LINT), url(docsrs))]
79    UnknownLint {
80        #[source_code]
81        src: NamedSource,
82        #[label("this lint")]
83        span: SourceSpan,
84        #[help]
85        note: Option<String>,
86    },
87
88    /// This error happens when you activate the `structs` lint, and you don't test a struct.
89    #[error("The {item_kind} `{item_name}` isn't tested")]
90    #[diagnostic(code(ITEM_NOT_TESTED), url(docsrs))]
91    ItemNotTested {
92        #[source_code]
93        src: NamedSource,
94        item_name: String,
95        item_kind: String,
96        #[label("this {item_kind}")]
97        span: SourceSpan,
98    },
99}