Make diagnostic locus point to the first primary label (#260)

This commit is contained in:
Johann150 2020-07-13 00:13:16 +02:00 committed by GitHub
parent e11625372c
commit 6b06e5f69a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 84 additions and 16 deletions

View File

@ -52,7 +52,7 @@
<foreignObject x="0" y="0" width="882" height="335"> <foreignObject x="0" y="0" width="882" height="335">
<div xmlns="http://www.w3.org/1999/xhtml"> <div xmlns="http://www.w3.org/1999/xhtml">
<pre><span class="fg red bold bright">error[E0308]</span><span class="bold bright">: `case` clauses have incompatible types</span> <pre><span class="fg red bold bright">error[E0308]</span><span class="bold bright">: `case` clauses have incompatible types</span>
<span class="fg blue">┌─</span> FizzBuzz.fun:10:15 <span class="fg blue">┌─</span> FizzBuzz.fun:16:16
<span class="fg blue"></span> <span class="fg blue"></span>
<span class="fg blue">10</span> <span class="fg blue"></span> fizz₂ : Nat → String <span class="fg blue">10</span> <span class="fg blue"></span> fizz₂ : Nat → String
<span class="fg blue"></span> <span class="fg blue">------</span> <span class="fg blue">expected type `String` found here</span> <span class="fg blue"></span> <span class="fg blue">------</span> <span class="fg blue">expected type `String` found here</span>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -81,7 +81,10 @@ fn main() -> anyhow::Result<()> {
Opts::Svg => { Opts::Svg => {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer)); let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer));
let config = codespan_reporting::term::Config::default(); let config = codespan_reporting::term::Config {
styles: codespan_reporting::term::Styles::with_blue(Color::Blue),
..codespan_reporting::term::Config::default()
};
for diagnostic in &diagnostics { for diagnostic in &diagnostics {
term::emit(&mut writer, &config, &file, &diagnostic)?; term::emit(&mut writer, &config, &file, &diagnostic)?;

View File

@ -50,7 +50,7 @@ impl PartialOrd for Severity {
} }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle { pub enum LabelStyle {
/// Labels that describe the primary cause of a diagnostic. /// Labels that describe the primary cause of a diagnostic.
@ -112,6 +112,8 @@ impl<FileId> Label<FileId> {
/// Represents a diagnostic message that can provide information like errors and /// Represents a diagnostic message that can provide information like errors and
/// warnings to the user. /// warnings to the user.
///
/// The position of a Diagnostic is considered to be the position of the [`Label`] with a style of [`LabelStyle::primary`] that has the smallest start position.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> { pub struct Diagnostic<FileId> {

View File

@ -45,6 +45,7 @@ where
location: Location, location: Location,
num_multi_labels: usize, num_multi_labels: usize,
lines: BTreeMap<usize, Line<'diagnostic>>, lines: BTreeMap<usize, Line<'diagnostic>>,
max_label_style: LabelStyle,
} }
impl<'diagnostic, FileId> LabeledFile<'diagnostic, FileId> { impl<'diagnostic, FileId> LabeledFile<'diagnostic, FileId> {
@ -103,14 +104,20 @@ where
.find(|labeled_file| label.file_id == labeled_file.file_id) .find(|labeled_file| label.file_id == labeled_file.file_id)
{ {
Some(labeled_file) => { Some(labeled_file) => {
if labeled_file.start > label.range.start { // another diagnostic also referenced this file
if labeled_file.start > label.range.start
&& labeled_file.max_label_style >= label.style
{
// this label indicates an earlier start and has at least the same level of style
labeled_file.start = label.range.start; labeled_file.start = label.range.start;
labeled_file.location = labeled_file.location =
files.location(label.file_id, label.range.start).unwrap(); files.location(label.file_id, label.range.start).unwrap();
labeled_file.max_label_style = label.style;
} }
labeled_file labeled_file
} }
None => { None => {
// no other diagnostic referenced this file yet
labeled_files.push(LabeledFile { labeled_files.push(LabeledFile {
file_id: label.file_id, file_id: label.file_id,
start: label.range.start, start: label.range.start,
@ -118,6 +125,7 @@ where
location: files.location(label.file_id, label.range.start).unwrap(), location: files.location(label.file_id, label.range.start).unwrap(),
num_multi_labels: 0, num_multi_labels: 0,
lines: BTreeMap::new(), lines: BTreeMap::new(),
max_label_style: label.style,
}); });
labeled_files.last_mut().unwrap() labeled_files.last_mut().unwrap()
} }

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config) expression: TEST_DATA.emit_color(&config)
--- ---
{fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/}
{fg:Blue}┌─{/} FizzBuzz.fun:3:15 {fg:Blue}┌─{/} FizzBuzz.fun:8:12
{fg:Blue}│{/} {fg:Blue}│{/}
{fg:Blue}3{/} {fg:Blue}│{/} fizz₁ : Nat → String {fg:Blue}3{/} {fg:Blue}│{/} fizz₁ : Nat → String
{fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/} {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/}
@ -20,7 +20,7 @@ expression: TEST_DATA.emit_color(&config)
found type `Nat` found type `Nat`
{fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/}
{fg:Blue}┌─{/} FizzBuzz.fun:10:15 {fg:Blue}┌─{/} FizzBuzz.fun:16:16
{fg:Blue}│{/} {fg:Blue}│{/}
{fg:Blue}10{/} {fg:Blue}│{/} fizz₂ : Nat → String {fg:Blue}10{/} {fg:Blue}│{/} fizz₂ : Nat → String
{fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/} {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/}

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config) expression: TEST_DATA.emit_no_color(&config)
--- ---
error[E0308]: `case` clauses have incompatible types error[E0308]: `case` clauses have incompatible types
┌─ FizzBuzz.fun:3:15 ┌─ FizzBuzz.fun:8:12
3 │ fizz₁ : Nat → String 3 │ fizz₁ : Nat → String
│ ------ expected type `String` found here │ ------ expected type `String` found here
@ -20,7 +20,7 @@ error[E0308]: `case` clauses have incompatible types
found type `Nat` found type `Nat`
error[E0308]: `case` clauses have incompatible types error[E0308]: `case` clauses have incompatible types
┌─ FizzBuzz.fun:10:15 ┌─ FizzBuzz.fun:16:16
10 │ fizz₂ : Nat → String 10 │ fizz₂ : Nat → String
│ ------ expected type `String` found here │ ------ expected type `String` found here

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config) expression: TEST_DATA.emit_color(&config)
--- ---
{fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/} {fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/}
{fg:Blue}┌─{/} codespan/src/file.rs:1:9 {fg:Blue}┌─{/} codespan/src/file.rs:4:34
{fg:Blue}│{/} {fg:Blue}│{/}
{fg:Blue}1{/} {fg:Blue}│{/} {fg:Blue}╭{/} match line_index.compare(self.last_line_index()) { {fg:Blue}1{/} {fg:Blue}│{/} {fg:Blue}╭{/} match line_index.compare(self.last_line_index()) {
{fg:Blue}2{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), {fg:Blue}2{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]),

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config) expression: TEST_DATA.emit_no_color(&config)
--- ---
error[E0308]: match arms have incompatible types error[E0308]: match arms have incompatible types
┌─ codespan/src/file.rs:1:9 ┌─ codespan/src/file.rs:4:34
1 │ ╭ match line_index.compare(self.last_line_index()) { 1 │ ╭ match line_index.compare(self.last_line_index()) {
2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), 2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]),

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config) expression: TEST_DATA.emit_color(&config)
--- ---
{fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/} {fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/}
{fg:Blue}┌─{/} nested_impl_trait.rs:5:46 {fg:Blue}┌─{/} nested_impl_trait.rs:5:56
{fg:Blue}│{/} {fg:Blue}│{/}
{fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<{fg:Red}impl Debug{/}> { x } {fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<{fg:Red}impl Debug{/}> { x }
{fg:Blue}│{/} {fg:Blue}----------{fg:Red}^^^^^^^^^^{fg:Blue}-{/} {fg:Blue}│{/} {fg:Blue}----------{fg:Red}^^^^^^^^^^{fg:Blue}-{/}
@ -21,7 +21,7 @@ expression: TEST_DATA.emit_color(&config)
{fg:Blue}│{/} {fg:Blue}help: replace with the correct return type: `i32`{/} {fg:Blue}│{/} {fg:Blue}help: replace with the correct return type: `i32`{/}
{fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
{fg:Blue}┌─{/} typeck_type_placeholder_item.rs:2:24 {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:2:25
{fg:Blue}│{/} {fg:Blue}│{/}
{fg:Blue}2{/} {fg:Blue}│{/} fn fn_test2(x: i32) -> ({fg:Red}_{/}, {fg:Red}_{/}) { (x, x) } {fg:Blue}2{/} {fg:Blue}│{/} fn fn_test2(x: i32) -> ({fg:Red}_{/}, {fg:Red}_{/}) { (x, x) }
{fg:Blue}│{/} {fg:Blue}-{fg:Red}^{fg:Blue}--{fg:Red}^{fg:Blue}-{/} {fg:Blue}│{/} {fg:Blue}-{fg:Red}^{fg:Blue}--{fg:Red}^{fg:Blue}-{/}

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config) expression: TEST_DATA.emit_no_color(&config)
--- ---
error[E0666]: nested `impl Trait` is not allowed error[E0666]: nested `impl Trait` is not allowed
┌─ nested_impl_trait.rs:5:46 ┌─ nested_impl_trait.rs:5:56
5 │ fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } 5 │ fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
│ ----------^^^^^^^^^^- │ ----------^^^^^^^^^^-
@ -21,7 +21,7 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
│ help: replace with the correct return type: `i32` │ help: replace with the correct return type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures
┌─ typeck_type_placeholder_item.rs:2:24 ┌─ typeck_type_placeholder_item.rs:2:25
2 │ fn fn_test2(x: i32) -> (_, _) { (x, x) } 2 │ fn fn_test2(x: i32) -> (_, _) { (x, x) }
│ -^--^- │ -^--^-

View File

@ -0,0 +1,14 @@
---
source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config)
---
warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode
┌─ tests/main.js:4:3
1 │ "use strict";
│ ------------ Strict mode is first declared here
·
4 │ "use strict";
│ ^^^^^^^^^^^^ This strict mode declaration is redundant

View File

@ -0,0 +1,6 @@
---
source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config)
---
tests/main.js:4:3: warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config) expression: TEST_DATA.emit_color(&config)
--- ---
{fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/} {fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/}
{fg:Blue}┌─{/} one_line.rs:3:5 {fg:Blue}┌─{/} one_line.rs:3:12
{fg:Blue}│{/} {fg:Blue}│{/}
{fg:Blue}3{/} {fg:Blue}│{/} v.push({fg:Red}v{/}.pop().unwrap()); {fg:Blue}3{/} {fg:Blue}│{/} v.push({fg:Red}v{/}.pop().unwrap());
{fg:Blue}│{/} {fg:Blue}-{/} {fg:Blue}----{/} {fg:Red}^{/} {fg:Red}second mutable borrow occurs here{/} {fg:Blue}│{/} {fg:Blue}-{/} {fg:Blue}----{/} {fg:Red}^{/} {fg:Red}second mutable borrow occurs here{/}

View File

@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config) expression: TEST_DATA.emit_no_color(&config)
--- ---
error[E0499]: cannot borrow `v` as mutable more than once at a time error[E0499]: cannot borrow `v` as mutable more than once at a time
┌─ one_line.rs:3:5 ┌─ one_line.rs:3:12
3 │ v.push(v.pop().unwrap()); 3 │ v.push(v.pop().unwrap());
│ - ---- ^ second mutable borrow occurs here │ - ---- ^ second mutable borrow occurs here

View File

@ -845,6 +845,41 @@ mod unicode_spans {
test_emit!(short_no_color); test_emit!(short_no_color);
} }
mod position_indicator {
use super::*;
lazy_static::lazy_static! {
static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = {
let file = SimpleFile::new(
"tests/main.js",
[
"\"use strict\";",
"let zero=0;",
"function foo() {",
" \"use strict\";",
" one=1;",
"}",
].join("\n"),
);
let diagnostics = vec![
Diagnostic::warning()
.with_code("ParserWarning")
.with_message("The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode")
.with_labels(vec![
Label::primary((), 45..57)
.with_message("This strict mode declaration is redundant"),
Label::secondary((), 0..12)
.with_message("Strict mode is first declared here"),
]),
];
TestData{files: file, diagnostics }
};
}
test_emit!(rich_no_color);
test_emit!(short_no_color);
}
mod multiline_omit { mod multiline_omit {
use super::*; use super::*;