diff --git a/src/lib.rs b/src/lib.rs index 83f7e37..8b7e575 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,11 +114,16 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { } let mut tail = String::new(); let last = &span.text[span.text.len() - 1]; + + // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of + // bounds' access by making sure the index is within the array bounds. + let last_tail_index = last.highlight_end.min(last.text.len()) - 1; + if span.text.len() > 1 { body.push('\n'); - body.push_str(&last.text[indent..last.highlight_end - 1]); + body.push_str(&last.text[indent..last_tail_index]); } - tail.push_str(&last.text[last.highlight_end - 1..]); + tail.push_str(&last.text[last_tail_index..]); Some(Snippet { file_name: span.file_name.clone(), line_range: LineRange { diff --git a/tests/edge-cases/out_of_bounds.recorded.json b/tests/edge-cases/out_of_bounds.recorded.json new file mode 100644 index 0000000..147debb --- /dev/null +++ b/tests/edge-cases/out_of_bounds.recorded.json @@ -0,0 +1,43 @@ +{ + "message": "unterminated double quote string", + "code": null, + "level": "error", + "spans": [ + { + "file_name": "./tests/everything/tab_2.rs", + "byte_start": 485, + "byte_end": 526, + "line_start": 12, + "line_end": 13, + "column_start": 7, + "column_end": 3, + "is_primary": true, + "text": [ + { + "text": " \"\"\"; //~ ERROR unterminated double quote", + "highlight_start": 7, + "highlight_end": 45 + }, + { + "text": "}", + "highlight_start": 1, + "highlight_end": 3 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [], + "rendered": "error: unterminated double quote string\n --> ./tests/everything/tab_2.rs:12:7\n |\n12 | \"\"\"; //~ ERROR unterminated double quote\n | _______^\n13 | | }\n | |__^\n\n" +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": "error: aborting due to previous error\n\n" +} diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 8848988..e787480 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -10,3 +10,12 @@ fn multiple_fix_options_yield_no_suggestions() { .unwrap(); assert!(expected_suggestions.is_empty()); } + +#[test] +fn out_of_bounds_test() { + let json = fs::read_to_string("./tests/edge-cases/out_of_bounds.recorded.json").unwrap(); + let expected_suggestions = + rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) + .unwrap(); + assert!(expected_suggestions.is_empty()); +}