Skip to content

Commit 56e1916

Browse files
authored
Rollup merge of rust-lang#58296 - estebank:hidden-suggestion, r=oli-obk
Hidden suggestion support Add way to hide suggestion snippet window from cli output to avoid cluttered spans that don't enhance understanding. r? @pietroalbini CC @zackmdavis
2 parents 4ad3cf2 + 87dd2e1 commit 56e1916

16 files changed

+245
-69
lines changed

Diff for: src/librustc/lint/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ impl BuiltinLintDiagnostics {
557557
}
558558
BuiltinLintDiagnostics::UnusedImports(message, replaces) => {
559559
if !replaces.is_empty() {
560-
db.multipart_suggestion(
560+
db.tool_only_multipart_suggestion(
561561
&message,
562562
replaces,
563563
Applicability::MachineApplicable,

Diff for: src/librustc_errors/diagnostic.rs

+75-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::CodeSuggestion;
2+
use crate::SuggestionStyle;
23
use crate::SubstitutionPart;
34
use crate::Substitution;
45
use crate::Applicability;
@@ -243,7 +244,33 @@ impl Diagnostic {
243244
.collect(),
244245
}],
245246
msg: msg.to_owned(),
246-
show_code_when_inline: true,
247+
style: SuggestionStyle::ShowCode,
248+
applicability,
249+
});
250+
self
251+
}
252+
253+
/// Prints out a message with for a multipart suggestion without showing the suggested code.
254+
///
255+
/// This is intended to be used for suggestions that are obvious in what the changes need to
256+
/// be from the message, showing the span label inline would be visually unpleasant
257+
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
258+
/// improve understandability.
259+
pub fn tool_only_multipart_suggestion(
260+
&mut self,
261+
msg: &str,
262+
suggestion: Vec<(Span, String)>,
263+
applicability: Applicability,
264+
) -> &mut Self {
265+
self.suggestions.push(CodeSuggestion {
266+
substitutions: vec![Substitution {
267+
parts: suggestion
268+
.into_iter()
269+
.map(|(span, snippet)| SubstitutionPart { snippet, span })
270+
.collect(),
271+
}],
272+
msg: msg.to_owned(),
273+
style: SuggestionStyle::CompletelyHidden,
247274
applicability,
248275
});
249276
self
@@ -277,7 +304,7 @@ impl Diagnostic {
277304
}],
278305
}],
279306
msg: msg.to_owned(),
280-
show_code_when_inline: true,
307+
style: SuggestionStyle::ShowCode,
281308
applicability,
282309
});
283310
self
@@ -295,7 +322,7 @@ impl Diagnostic {
295322
}],
296323
}).collect(),
297324
msg: msg.to_owned(),
298-
show_code_when_inline: true,
325+
style: SuggestionStyle::ShowCode,
299326
applicability,
300327
});
301328
self
@@ -316,7 +343,51 @@ impl Diagnostic {
316343
}],
317344
}],
318345
msg: msg.to_owned(),
319-
show_code_when_inline: false,
346+
style: SuggestionStyle::HideCodeInline,
347+
applicability,
348+
});
349+
self
350+
}
351+
352+
/// Prints out a message with for a suggestion without showing the suggested code.
353+
///
354+
/// This is intended to be used for suggestions that are obvious in what the changes need to
355+
/// be from the message, showing the span label inline would be visually unpleasant
356+
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
357+
/// improve understandability.
358+
pub fn span_suggestion_hidden(
359+
&mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
360+
) -> &mut Self {
361+
self.suggestions.push(CodeSuggestion {
362+
substitutions: vec![Substitution {
363+
parts: vec![SubstitutionPart {
364+
snippet: suggestion,
365+
span: sp,
366+
}],
367+
}],
368+
msg: msg.to_owned(),
369+
style: SuggestionStyle::HideCodeInline,
370+
applicability,
371+
});
372+
self
373+
}
374+
375+
/// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli.
376+
///
377+
/// This is intended to be used for suggestions that are *very* obvious in what the changes
378+
/// need to be from the message, but we still want other tools to be able to apply them.
379+
pub fn tool_only_span_suggestion(
380+
&mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
381+
) -> &mut Self {
382+
self.suggestions.push(CodeSuggestion {
383+
substitutions: vec![Substitution {
384+
parts: vec![SubstitutionPart {
385+
snippet: suggestion,
386+
span: sp,
387+
}],
388+
}],
389+
msg: msg.to_owned(),
390+
style: SuggestionStyle::CompletelyHidden,
320391
applicability: applicability,
321392
});
322393
self

Diff for: src/librustc_errors/diagnostic_builder.rs

+57
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,24 @@ impl<'a> DiagnosticBuilder<'a> {
205205
self
206206
}
207207

208+
pub fn tool_only_multipart_suggestion(
209+
&mut self,
210+
msg: &str,
211+
suggestion: Vec<(Span, String)>,
212+
applicability: Applicability,
213+
) -> &mut Self {
214+
if !self.allow_suggestions {
215+
return self
216+
}
217+
self.diagnostic.tool_only_multipart_suggestion(
218+
msg,
219+
suggestion,
220+
applicability,
221+
);
222+
self
223+
}
224+
225+
208226
pub fn span_suggestion(
209227
&mut self,
210228
sp: Span,
@@ -261,6 +279,45 @@ impl<'a> DiagnosticBuilder<'a> {
261279
);
262280
self
263281
}
282+
283+
pub fn span_suggestion_hidden(
284+
&mut self,
285+
sp: Span,
286+
msg: &str,
287+
suggestion: String,
288+
applicability: Applicability,
289+
) -> &mut Self {
290+
if !self.allow_suggestions {
291+
return self
292+
}
293+
self.diagnostic.span_suggestion_hidden(
294+
sp,
295+
msg,
296+
suggestion,
297+
applicability,
298+
);
299+
self
300+
}
301+
302+
pub fn tool_only_span_suggestion(
303+
&mut self,
304+
sp: Span,
305+
msg: &str,
306+
suggestion: String,
307+
applicability: Applicability,
308+
) -> &mut Self {
309+
if !self.allow_suggestions {
310+
return self
311+
}
312+
self.diagnostic.tool_only_span_suggestion(
313+
sp,
314+
msg,
315+
suggestion,
316+
applicability,
317+
);
318+
self
319+
}
320+
264321
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
265322
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
266323

Diff for: src/librustc_errors/emitter.rs

+64-32
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use Destination::*;
22

33
use syntax_pos::{SourceFile, Span, MultiSpan};
44

5-
use crate::{Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, SourceMapperDyn, DiagnosticId};
5+
use crate::{
6+
Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic,
7+
SuggestionStyle, SourceMapperDyn, DiagnosticId,
8+
};
69
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
710
use crate::styled_buffer::StyledBuffer;
811

@@ -43,9 +46,14 @@ impl Emitter for EmitterWriter {
4346
// don't display long messages as labels
4447
sugg.msg.split_whitespace().count() < 10 &&
4548
// don't display multiline suggestions as labels
46-
!sugg.substitutions[0].parts[0].snippet.contains('\n') {
49+
!sugg.substitutions[0].parts[0].snippet.contains('\n') &&
50+
// when this style is set we want the suggestion to be a message, not inline
51+
sugg.style != SuggestionStyle::HideCodeAlways &&
52+
// trivial suggestion for tooling's sake, never shown
53+
sugg.style != SuggestionStyle::CompletelyHidden
54+
{
4755
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
48-
let msg = if substitution.len() == 0 || !sugg.show_code_when_inline {
56+
let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
4957
// This substitution is only removal or we explicitly don't want to show the
5058
// code inline, don't show it
5159
format!("help: {}", sugg.msg)
@@ -942,14 +950,15 @@ impl EmitterWriter {
942950
}
943951
}
944952

945-
fn emit_message_default(&mut self,
946-
msp: &MultiSpan,
947-
msg: &[(String, Style)],
948-
code: &Option<DiagnosticId>,
949-
level: &Level,
950-
max_line_num_len: usize,
951-
is_secondary: bool)
952-
-> io::Result<()> {
953+
fn emit_message_default(
954+
&mut self,
955+
msp: &MultiSpan,
956+
msg: &[(String, Style)],
957+
code: &Option<DiagnosticId>,
958+
level: &Level,
959+
max_line_num_len: usize,
960+
is_secondary: bool,
961+
) -> io::Result<()> {
953962
let mut buffer = StyledBuffer::new();
954963
let header_style = if is_secondary {
955964
Style::HeaderMsg
@@ -1184,11 +1193,12 @@ impl EmitterWriter {
11841193

11851194
}
11861195

1187-
fn emit_suggestion_default(&mut self,
1188-
suggestion: &CodeSuggestion,
1189-
level: &Level,
1190-
max_line_num_len: usize)
1191-
-> io::Result<()> {
1196+
fn emit_suggestion_default(
1197+
&mut self,
1198+
suggestion: &CodeSuggestion,
1199+
level: &Level,
1200+
max_line_num_len: usize,
1201+
) -> io::Result<()> {
11921202
if let Some(ref sm) = self.sm {
11931203
let mut buffer = StyledBuffer::new();
11941204

@@ -1198,11 +1208,13 @@ impl EmitterWriter {
11981208
buffer.append(0, &level_str, Style::Level(level.clone()));
11991209
buffer.append(0, ": ", Style::HeaderMsg);
12001210
}
1201-
self.msg_to_buffer(&mut buffer,
1202-
&[(suggestion.msg.to_owned(), Style::NoStyle)],
1203-
max_line_num_len,
1204-
"suggestion",
1205-
Some(Style::HeaderMsg));
1211+
self.msg_to_buffer(
1212+
&mut buffer,
1213+
&[(suggestion.msg.to_owned(), Style::NoStyle)],
1214+
max_line_num_len,
1215+
"suggestion",
1216+
Some(Style::HeaderMsg),
1217+
);
12061218

12071219
// Render the replacements for each suggestion
12081220
let suggestions = suggestion.splice_lines(&**sm);
@@ -1340,22 +1352,42 @@ impl EmitterWriter {
13401352
if !self.short_message {
13411353
for child in children {
13421354
let span = child.render_span.as_ref().unwrap_or(&child.span);
1343-
match self.emit_message_default(&span,
1344-
&child.styled_message(),
1345-
&None,
1346-
&child.level,
1347-
max_line_num_len,
1348-
true) {
1355+
match self.emit_message_default(
1356+
&span,
1357+
&child.styled_message(),
1358+
&None,
1359+
&child.level,
1360+
max_line_num_len,
1361+
true,
1362+
) {
13491363
Err(e) => panic!("failed to emit error: {}", e),
13501364
_ => ()
13511365
}
13521366
}
13531367
for sugg in suggestions {
1354-
match self.emit_suggestion_default(sugg,
1355-
&Level::Help,
1356-
max_line_num_len) {
1357-
Err(e) => panic!("failed to emit error: {}", e),
1358-
_ => ()
1368+
if sugg.style == SuggestionStyle::CompletelyHidden {
1369+
// do not display this suggestion, it is meant only for tools
1370+
} else if sugg.style == SuggestionStyle::HideCodeAlways {
1371+
match self.emit_message_default(
1372+
&MultiSpan::new(),
1373+
&[(sugg.msg.to_owned(), Style::HeaderMsg)],
1374+
&None,
1375+
&Level::Help,
1376+
max_line_num_len,
1377+
true,
1378+
) {
1379+
Err(e) => panic!("failed to emit error: {}", e),
1380+
_ => ()
1381+
}
1382+
} else {
1383+
match self.emit_suggestion_default(
1384+
sugg,
1385+
&Level::Help,
1386+
max_line_num_len,
1387+
) {
1388+
Err(e) => panic!("failed to emit error: {}", e),
1389+
_ => ()
1390+
}
13591391
}
13601392
}
13611393
}

Diff for: src/librustc_errors/lib.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@ pub enum Applicability {
6969
Unspecified,
7070
}
7171

72+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, RustcEncodable, RustcDecodable)]
73+
pub enum SuggestionStyle {
74+
/// Hide the suggested code when displaying this suggestion inline.
75+
HideCodeInline,
76+
/// Always hide the suggested code but display the message.
77+
HideCodeAlways,
78+
/// Do not display this suggestion in the cli output, it is only meant for tools.
79+
CompletelyHidden,
80+
/// Always show the suggested code.
81+
/// This will *not* show the code if the suggestion is inline *and* the suggested code is
82+
/// empty.
83+
ShowCode,
84+
}
85+
86+
impl SuggestionStyle {
87+
fn hide_inline(&self) -> bool {
88+
match *self {
89+
SuggestionStyle::ShowCode => false,
90+
_ => true,
91+
}
92+
}
93+
}
94+
7295
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
7396
pub struct CodeSuggestion {
7497
/// Each substitute can have multiple variants due to multiple
@@ -94,7 +117,8 @@ pub struct CodeSuggestion {
94117
/// ```
95118
pub substitutions: Vec<Substitution>,
96119
pub msg: String,
97-
pub show_code_when_inline: bool,
120+
/// Visual representation of this suggestion.
121+
pub style: SuggestionStyle,
98122
/// Whether or not the suggestion is approximate
99123
///
100124
/// Sometimes we may show suggestions with placeholders,

Diff for: src/test/ui/bad/bad-lint-cap2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: unused import: `std::option`
22
--> $DIR/bad-lint-cap2.rs:6:5
33
|
44
LL | use std::option; //~ ERROR
5-
| ----^^^^^^^^^^^- help: remove the whole `use` item
5+
| ^^^^^^^^^^^
66
|
77
note: lint level defined here
88
--> $DIR/bad-lint-cap2.rs:4:9

Diff for: src/test/ui/bad/bad-lint-cap3.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ warning: unused import: `std::option`
22
--> $DIR/bad-lint-cap3.rs:7:5
33
|
44
LL | use std::option; //~ WARN
5-
| ----^^^^^^^^^^^- help: remove the whole `use` item
5+
| ^^^^^^^^^^^
66
|
77
note: lint level defined here
88
--> $DIR/bad-lint-cap3.rs:4:9

0 commit comments

Comments
 (0)