Skip to content

Commit 5ea5ff7

Browse files
committed
Suggest Span without source changes when source code is unavailable
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
1 parent a06c1ca commit 5ea5ff7

7 files changed

Lines changed: 109 additions & 1 deletion

File tree

compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub struct AnnotateSnippetEmitter {
4747
track_diagnostics: bool,
4848
terminal_url: TerminalUrl,
4949
theme: OutputTheme,
50+
show_suggestions_with_unavailable_source: bool,
5051
}
5152

5253
impl Debug for AnnotateSnippetEmitter {
@@ -63,6 +64,10 @@ impl Debug for AnnotateSnippetEmitter {
6364
.field("track_diagnostics", &self.track_diagnostics)
6465
.field("terminal_url", &self.terminal_url)
6566
.field("theme", &self.theme)
67+
.field(
68+
"show_suggestions_with_unavailable_source",
69+
&self.show_suggestions_with_unavailable_source,
70+
)
6671
.finish()
6772
}
6873
}
@@ -136,6 +141,7 @@ impl AnnotateSnippetEmitter {
136141
track_diagnostics: false,
137142
terminal_url: TerminalUrl::No,
138143
theme: OutputTheme::Ascii,
144+
show_suggestions_with_unavailable_source: false,
139145
}
140146
}
141147

@@ -307,6 +313,11 @@ impl AnnotateSnippetEmitter {
307313
SuggestionStyle::HideCodeInline
308314
| SuggestionStyle::ShowCode
309315
| SuggestionStyle::ShowAlways => {
316+
let unavailable_source_span = if self.show_suggestions_with_unavailable_source {
317+
self.suggestion_span_with_unavailable_source(sm, &suggestion)
318+
} else {
319+
None
320+
};
310321
let substitutions = suggestion
311322
.substitutions
312323
.into_iter()
@@ -356,6 +367,30 @@ impl AnnotateSnippetEmitter {
356367
.collect::<Vec<_>>();
357368

358369
if substitutions.is_empty() {
370+
if let Some(span) = unavailable_source_span {
371+
let msg = format_diag_message(&suggestion.msg, args).to_string();
372+
report.push(std::mem::replace(
373+
&mut group,
374+
Group::with_title(
375+
annotate_snippets::Level::HELP.secondary_title(msg),
376+
),
377+
));
378+
379+
let file_ann = collect_annotations(args, &span, sm);
380+
let level = annotate_snippets::Level::HELP;
381+
for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate()
382+
{
383+
group = self.unannotated_messages(
384+
annotations,
385+
&file.name,
386+
sm,
387+
file_idx,
388+
&mut report,
389+
group,
390+
&level,
391+
);
392+
}
393+
}
359394
continue;
360395
}
361396
let mut msg = format_diag_message(&suggestion.msg, args).to_string();
@@ -645,6 +680,36 @@ impl AnnotateSnippetEmitter {
645680
}
646681
group
647682
}
683+
684+
fn suggestion_span_with_unavailable_source(
685+
&self,
686+
sm: &Arc<SourceMap>,
687+
suggestion: &CodeSuggestion,
688+
) -> Option<MultiSpan> {
689+
let spans = suggestion
690+
.substitutions
691+
.iter()
692+
.flat_map(|subst| &subst.parts)
693+
.filter_map(|part| {
694+
if sm.is_valid_span(part.span).is_err() {
695+
debug!("suggestion contains an invalid span: {:?}", part);
696+
return None;
697+
}
698+
let lines = sm.span_to_lines(part.span).ok()?;
699+
if should_show_source_code(
700+
&self.ignored_directories_in_source_blocks,
701+
sm,
702+
&lines.file,
703+
) {
704+
None
705+
} else {
706+
Some(part.span)
707+
}
708+
})
709+
.collect::<Vec<_>>();
710+
711+
if spans.is_empty() { None } else { Some(MultiSpan::from_spans(spans)) }
712+
}
648713
}
649714

650715
fn emit_to_destination(

compiler/rustc_errors/src/json.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub struct JsonEmitter {
5454
macro_backtrace: bool,
5555
track_diagnostics: bool,
5656
terminal_url: TerminalUrl,
57+
show_suggestions_with_unavailable_source: bool,
5758
}
5859

5960
impl JsonEmitter {
@@ -76,6 +77,7 @@ impl JsonEmitter {
7677
macro_backtrace: false,
7778
track_diagnostics: false,
7879
terminal_url: TerminalUrl::No,
80+
show_suggestions_with_unavailable_source: false,
7981
}
8082
}
8183

@@ -373,6 +375,7 @@ impl Diagnostic {
373375
.terminal_url(je.terminal_url)
374376
.ui_testing(je.ui_testing)
375377
.ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone())
378+
.show_suggestions_with_unavailable_source(je.show_suggestions_with_unavailable_source)
376379
.theme(if je.json_rendered.unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
377380
.emit_diagnostic(diag);
378381

compiler/rustc_session/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,6 +2629,8 @@ written to standard error output)"),
26292629
"make the current crate share its generic instantiations"),
26302630
shell_argfiles: bool = (false, parse_bool, [UNTRACKED],
26312631
"allow argument files to be specified with POSIX \"shell-style\" argument quoting"),
2632+
show_suggestions_with_unavailable_source: bool = (false, parse_bool, [UNTRACKED],
2633+
"show span-only suggestions when the source code is unavailable"),
26322634
simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
26332635
"simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
26342636
to rust's source base directory. only meant for testing purposes"),

compiler/rustc_session/src/session.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,8 @@ impl Session {
947947
fn default_emitter(sopts: &config::Options, source_map: Arc<SourceMap>) -> Box<DynEmitter> {
948948
let macro_backtrace = sopts.unstable_opts.macro_backtrace;
949949
let track_diagnostics = sopts.unstable_opts.track_diagnostics;
950+
let show_suggestions_with_unavailable_source =
951+
sopts.unstable_opts.show_suggestions_with_unavailable_source;
950952
let terminal_url = match sopts.unstable_opts.terminal_urls {
951953
TerminalUrl::Auto => {
952954
match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) {
@@ -974,6 +976,9 @@ fn default_emitter(sopts: &config::Options, source_map: Arc<SourceMap>) -> Box<D
974976
.track_diagnostics(track_diagnostics)
975977
.terminal_url(terminal_url)
976978
.theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
979+
.show_suggestions_with_unavailable_source(
980+
show_suggestions_with_unavailable_source,
981+
)
977982
.ignored_directories_in_source_blocks(
978983
sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(),
979984
);
@@ -995,7 +1000,8 @@ fn default_emitter(sopts: &config::Options, source_map: Arc<SourceMap>) -> Box<D
9951000
.diagnostic_width(sopts.diagnostic_width)
9961001
.macro_backtrace(macro_backtrace)
9971002
.track_diagnostics(track_diagnostics)
998-
.terminal_url(terminal_url),
1003+
.terminal_url(terminal_url)
1004+
.show_suggestions_with_unavailable_source(show_suggestions_with_unavailable_source),
9991005
),
10001006
}
10011007
}

src/tools/compiletest/src/runtest.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,7 @@ impl<'test> TestCx<'test> {
16941694
compiler.args(&["--json", "future-incompat"]);
16951695
}
16961696
compiler.arg("-Zui-testing");
1697+
compiler.arg("-Zshow-suggestions-with-unavailable-source");
16971698
compiler.arg("-Zdeduplicate-diagnostics=no");
16981699
}
16991700
TestMode::Ui => {
@@ -1704,6 +1705,7 @@ impl<'test> TestCx<'test> {
17041705
compiler.arg("-Ccodegen-units=1");
17051706
// Hide line numbers to reduce churn
17061707
compiler.arg("-Zui-testing");
1708+
compiler.arg("-Zshow-suggestions-with-unavailable-source");
17071709
compiler.arg("-Zdeduplicate-diagnostics=no");
17081710
compiler.arg("-Zwrite-long-types-to-disk=no");
17091711
// FIXME: use this for other modes too, for perf?
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ compile-flags: -Zignore-directory-in-diagnostics-source-blocks={{src-base}}/compiletest-self-test
2+
3+
macro_rules! my_assert {
4+
($left:expr, $right:expr) => {
5+
if !($left == $right) {} //~ ERROR can't compare `&isize` with `{integer}` [E0277]
6+
};
7+
}
8+
9+
fn main() {
10+
let y: &isize = &1;
11+
my_assert!(y, 2);
12+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0277]: can't compare `&isize` with `{integer}`
2+
--> $DIR/help-show-std-source.rs:5:19
3+
|
4+
= note: no implementation for `&isize == {integer}`
5+
::: $DIR/help-show-std-source.rs:11:4
6+
|
7+
= note: in this macro invocation
8+
|
9+
= help: the trait `PartialEq<{integer}>` is not implemented for `&isize`
10+
= note: this error originates in the macro `my_assert` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
help: consider dereferencing here
12+
|
13+
LL | my_assert!(*y, 2);
14+
| +
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)