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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use code::Span;

/// Describes some kind of problem or occurrence in the code. Contains one or
/// more remarks with descriptions and separate code spans.
///
/// This type doesn't provide a `Display` impl, since all spans reference an
/// external filemap which needs to be provided. Use `print` methods of the
/// `diag` module instead.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Report {
    /// Kind of the report (usually the same as the first remark kind)
    pub kind: ReportKind,
    /// Span of the main code snippet
    pub span: Option<Span>,
    /// List of remarks describing the report
    pub remarks: Vec<Remark>,
}

impl Report {
    /// Creates a error report with one message and one span
    pub fn simple_error<S: Into<String>>(msg: S, span: Span) -> Report {
        Report {
            kind: ReportKind::Error,
            span: Some(span),
            remarks: vec![Remark::error(msg, Snippet::Orig(span))],
        }
    }

    /// Creates a error report with one message, but without span
    pub fn simple_spanless_error<S: Into<String>>(msg: S) -> Report {
        Report {
            kind: ReportKind::Error,
            span: None,
            remarks: vec![Remark::error(msg, Snippet::None)],
        }
    }

    /// Creates a warning report with one message and one span
    pub fn simple_warning<S: Into<String>>(msg: S, span: Span) -> Report {
        Report {
            kind: ReportKind::Warning,
            span: Some(span),
            remarks: vec![Remark::warning(msg, Snippet::Orig(span))],
        }
    }

    /// Adds a note without a span/code snippet to the existing Report
    pub fn with_note<S: Into<String>>(self, msg: S) -> Report {
        self.with_remark(Remark::note(msg, Snippet::None))
    }

    /// Adds a note with a span/code snippet to the existing Report
    pub fn with_span_note<S: Into<String>>(self, msg: S, span: Span)
        -> Report
    {
        self.with_remark(Remark::note(msg, Snippet::Orig(span)))
    }

    /// Adds a remark to the returned Report
    pub fn with_remark(mut self, rem: Remark) -> Report {
        self.remarks.push(rem);
        self
    }
}

/// A report can either be an `Error` or a `Warning`. Still pretty similar to
/// `RemarkType` -- may be merged with it in the future.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ReportKind {
    /// Something went very wrong and will stop further processing
    Error,
    /// Something important should be fixed, but doesn't stop processing
    Warning,
}

/// Part of a Report that describes the occurrence with an optional code
/// snippet.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Remark {
    pub kind: RemarkKind,
    /// Remark description
    pub desc: String,
    pub snippet: Snippet,
}

impl Remark {
    /// Creates a new remark with the given parameters
    pub fn new<S: Into<String>>(kind: RemarkKind, desc: S, snippet: Snippet)
        -> Self
    {
        Remark {
            kind: kind,
            desc: desc.into(),
            snippet: snippet,
        }
    }

    /// Creates a new remark of kind `Error` with the given parameters
    pub fn error<S: Into<String>>(desc: S, snippet: Snippet) -> Self {
        Self::new(RemarkKind::Error, desc, snippet)
    }

    /// Creates a new remark of kind `Warning` with the given parameters
    pub fn warning<S: Into<String>>(desc: S, snippet: Snippet) -> Self {
        Self::new(RemarkKind::Warning, desc, snippet)
    }

    /// Creates a new remark of kind `Note` with the given parameters
    pub fn note<S: Into<String>>(desc: S, snippet: Snippet) -> Self {
        Self::new(RemarkKind::Note, desc, snippet)
    }
}

/// Kinds of remarks
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum RemarkKind {
    /// Something went very wrong and will stop further processing
    Error,
    /// Something important should be fixed, but doesn't stop processing
    Warning,
    /// Additional information about an error or a warning
    Note,
}


#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Snippet {
    /// No snippet
    None,
    /// Show the original code with this highlighted span
    Orig(Span),
    /// Show original code, but replace a part of it with something new and
    /// highlight the new part. Hint: also able to only insert.
    Replace {
        span: Span,
        with: String,
    }
}

impl Snippet {
    /// Returns the span if it exists
    pub fn span(&self) -> Option<Span> {
        match *self {
            Snippet::None => None,
            Snippet::Orig(span) => Some(span),
            Snippet::Replace { span, ..} => Some(span),
        }
    }
}