Account for fully overlapping multiline annotations

When two multiline span labels point at the same span, we special
case the output to avoid weird behavior:

```
        foo(
   _____^
  |_____|
 ||         bar,
 ||     );
 ||      ^
 ||______|
  |______foo
         baz
```

instead showing

```
       foo(
  _____^
 |         bar,
 |     );
 |      ^
 |      |
 |______foo
        baz
```
This commit is contained in:
Esteban Küber 2019-03-27 19:26:47 -07:00
parent 925ca49cf1
commit 326ec800b9
5 changed files with 116 additions and 25 deletions

View file

@ -243,6 +243,7 @@ impl EmitterWriter {
end_col: hi.col_display,
is_primary: span_label.is_primary,
label: span_label.label.clone(),
overlaps: false,
};
multiline_annotations.push((lo.file.clone(), ml.clone()));
AnnotationType::Multiline(ml)
@ -258,10 +259,7 @@ impl EmitterWriter {
};
if !ann.is_multiline() {
add_annotation_to_file(&mut output,
lo.file,
lo.line,
ann);
add_annotation_to_file(&mut output, lo.file, lo.line, ann);
}
}
}
@ -274,10 +272,12 @@ impl EmitterWriter {
let ref mut a = item.1;
// Move all other multiline annotations overlapping with this one
// one level to the right.
if &ann != a &&
if !(ann.same_span(a)) &&
num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
{
a.increase_depth();
} else if ann.same_span(a) && &ann != a {
a.overlaps = true;
} else {
break;
}
@ -289,17 +289,44 @@ impl EmitterWriter {
if ann.depth > max_depth {
max_depth = ann.depth;
}
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
let middle = min(ann.line_start + 4, ann.line_end);
for line in ann.line_start + 1..middle {
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
}
if middle < ann.line_end - 1 {
for line in ann.line_end - 1..ann.line_end {
let mut end_ann = ann.as_end();
if !ann.overlaps {
// avoid output like
//
// | foo(
// | _____^
// | |_____|
// | || bar,
// | || );
// | || ^
// | ||______|
// | |______foo
// | baz
//
// and instead get
//
// | foo(
// | _____^
// | | bar,
// | | );
// | | ^
// | | |
// | |______foo
// | baz
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
let middle = min(ann.line_start + 4, ann.line_end);
for line in ann.line_start + 1..middle {
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
}
if middle < ann.line_end - 1 {
for line in ann.line_end - 1..ann.line_end {
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
}
}
} else {
end_ann.annotation_type = AnnotationType::Singleline;
}
add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end());
add_annotation_to_file(&mut output, file, ann.line_end, end_ann);
}
for file_vec in output.iter_mut() {
file_vec.multiline_depth = max_depth;

View file

@ -18,6 +18,7 @@ pub struct MultilineAnnotation {
pub end_col: usize,
pub is_primary: bool,
pub label: Option<String>,
pub overlaps: bool,
}
impl MultilineAnnotation {
@ -25,6 +26,12 @@ impl MultilineAnnotation {
self.depth += 1;
}
/// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
pub fn same_span(&self, other: &MultilineAnnotation) -> bool {
self.line_start == other.line_start && self.line_end == other.line_end
&& self.start_col == other.start_col && self.end_col == other.end_col
}
pub fn as_start(&self) -> Annotation {
Annotation {
start_col: self.start_col,

View file

@ -374,6 +374,66 @@ error: foo
"#);
}
#[test]
fn triple_exact_overlap() {
test_harness(r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
}
"#,
vec![
SpanLabel {
start: Position {
string: "X0",
count: 1,
},
end: Position {
string: "X2",
count: 1,
},
label: "`X` is a good letter",
},
SpanLabel {
start: Position {
string: "X0",
count: 1,
},
end: Position {
string: "X2",
count: 1,
},
label: "`Y` is a good letter too",
},
SpanLabel {
start: Position {
string: "X0",
count: 1,
},
end: Position {
string: "X2",
count: 1,
},
label: "`Z` label",
},
],
r#"
error: foo
--> test.rs:3:3
|
3 | / X0 Y0 Z0
4 | | X1 Y1 Z1
5 | | X2 Y2 Z2
| | ^
| | |
| | `X` is a good letter
| |____`Y` is a good letter too
| `Z` label
"#);
}
#[test]
fn minimum_depth() {
test_harness(r#"

View file

@ -3,7 +3,7 @@ fn warn(_: &str) {}
macro_rules! intrinsic_match {
($intrinsic:expr) => {
warn(format!("unsupported intrinsic {}", $intrinsic));
//^~ ERROR mismatched types
//~^ ERROR mismatched types
};
}

View file

@ -1,16 +1,13 @@
error[E0308]: mismatched types
--> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:10:5
--> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:11:5
|
LL | intrinsic_match! {
| _____^
| |_____|
| ||
LL | || "abc"
LL | || };
| || ^
| ||______|
| |_______expected &str, found struct `std::string::String`
| in this macro invocation
LL | / intrinsic_match! {
LL | | "abc"
LL | | };
| | ^
| | |
| |______expected &str, found struct `std::string::String`
| in this macro invocation
|
= note: expected type `&str`
found type `std::string::String`