Skip to content

Commit 26792f0

Browse files
committed
Auto merge of #47540 - Manishearth:suggestion, r=nrc
Add approximate suggestions for rustfix This adds `span_approximate_suggestion()` that lets you emit a suggestion marked as "non-machine applicable" in the JSON output. UI users see no difference. This is for when rustc and clippy wish to emit suggestions which will make sense to the reader (e.g. they may have placeholders like `<type>`) but are not source-applicable, so that rustfix/etc can ignore these. fixes #39254
2 parents 8ccab7e + 540f95d commit 26792f0

File tree

9 files changed

+109
-14
lines changed

9 files changed

+109
-14
lines changed

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
12881288
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
12891289
"in dep-info output, omit targets for tracking dependencies of the dep-info files \
12901290
themselves"),
1291+
approximate_suggestions: bool = (false, parse_bool, [UNTRACKED],
1292+
"include machine-applicability of suggestions in JSON output"),
12911293
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
12921294
"Present the input source, unstable (and less-pretty) variants;
12931295
valid types are any of the types for `--pretty`, as well as:

src/librustc/session/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -913,10 +913,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
913913
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false, false))
914914
}
915915
(config::ErrorOutputType::Json(pretty), None) => {
916-
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
916+
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(),
917+
pretty, sopts.debugging_opts.approximate_suggestions))
917918
}
918919
(config::ErrorOutputType::Json(pretty), Some(dst)) => {
919-
Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
920+
Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(),
921+
pretty, sopts.debugging_opts.approximate_suggestions))
920922
}
921923
(config::ErrorOutputType::Short(color_config), None) => {
922924
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false))

src/librustc_errors/diagnostic.rs

+37
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ impl Diagnostic {
222222
}],
223223
msg: msg.to_owned(),
224224
show_code_when_inline: false,
225+
approximate: false,
225226
});
226227
self
227228
}
@@ -252,6 +253,7 @@ impl Diagnostic {
252253
}],
253254
msg: msg.to_owned(),
254255
show_code_when_inline: true,
256+
approximate: false,
255257
});
256258
self
257259
}
@@ -267,6 +269,41 @@ impl Diagnostic {
267269
}).collect(),
268270
msg: msg.to_owned(),
269271
show_code_when_inline: true,
272+
approximate: false,
273+
});
274+
self
275+
}
276+
277+
/// This is a suggestion that may contain mistakes or fillers and should
278+
/// be read and understood by a human.
279+
pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str,
280+
suggestion: String) -> &mut Self {
281+
self.suggestions.push(CodeSuggestion {
282+
substitutions: vec![Substitution {
283+
parts: vec![SubstitutionPart {
284+
snippet: suggestion,
285+
span: sp,
286+
}],
287+
}],
288+
msg: msg.to_owned(),
289+
show_code_when_inline: true,
290+
approximate: true,
291+
});
292+
self
293+
}
294+
295+
pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str,
296+
suggestions: Vec<String>) -> &mut Self {
297+
self.suggestions.push(CodeSuggestion {
298+
substitutions: suggestions.into_iter().map(|snippet| Substitution {
299+
parts: vec![SubstitutionPart {
300+
snippet,
301+
span: sp,
302+
}],
303+
}).collect(),
304+
msg: msg.to_owned(),
305+
show_code_when_inline: true,
306+
approximate: true,
270307
});
271308
self
272309
}

src/librustc_errors/diagnostic_builder.rs

+10
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ impl<'a> DiagnosticBuilder<'a> {
186186
msg: &str,
187187
suggestions: Vec<String>)
188188
-> &mut Self);
189+
forward!(pub fn span_approximate_suggestion(&mut self,
190+
sp: Span,
191+
msg: &str,
192+
suggestion: String)
193+
-> &mut Self);
194+
forward!(pub fn span_approximate_suggestions(&mut self,
195+
sp: Span,
196+
msg: &str,
197+
suggestions: Vec<String>)
198+
-> &mut Self);
189199
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
190200
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
191201

src/librustc_errors/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ pub struct CodeSuggestion {
8383
pub substitutions: Vec<Substitution>,
8484
pub msg: String,
8585
pub show_code_when_inline: bool,
86+
/// Whether or not the suggestion is approximate
87+
///
88+
/// Sometimes we may show suggestions with placeholders,
89+
/// which are useful for users but not useful for
90+
/// tools like rustfix
91+
pub approximate: bool,
8692
}
8793

8894
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]

src/libsyntax/feature_gate.rs

+5
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
788788
is just used for rustc unit tests \
789789
and will never be stable",
790790
cfg_fn!(rustc_attrs))),
791+
("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable,
792+
"rustc_attrs",
793+
"the `#[rustc_serialize_exclude_null]` attribute \
794+
is an internal-only feature",
795+
cfg_fn!(rustc_attrs))),
791796
("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
792797
"rustc_attrs",
793798
"this attribute \

src/libsyntax/json.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,41 @@ pub struct JsonEmitter {
3838
registry: Option<Registry>,
3939
cm: Rc<CodeMapper + 'static>,
4040
pretty: bool,
41+
/// Whether "approximate suggestions" are enabled in the config
42+
approximate_suggestions: bool,
4143
}
4244

4345
impl JsonEmitter {
4446
pub fn stderr(registry: Option<Registry>,
4547
code_map: Rc<CodeMap>,
46-
pretty: bool) -> JsonEmitter {
48+
pretty: bool,
49+
approximate_suggestions: bool) -> JsonEmitter {
4750
JsonEmitter {
4851
dst: Box::new(io::stderr()),
4952
registry,
5053
cm: code_map,
5154
pretty,
55+
approximate_suggestions,
5256
}
5357
}
5458

5559
pub fn basic(pretty: bool) -> JsonEmitter {
5660
let file_path_mapping = FilePathMapping::empty();
57-
JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
61+
JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)),
62+
pretty, false)
5863
}
5964

6065
pub fn new(dst: Box<Write + Send>,
6166
registry: Option<Registry>,
6267
code_map: Rc<CodeMap>,
63-
pretty: bool) -> JsonEmitter {
68+
pretty: bool,
69+
approximate_suggestions: bool) -> JsonEmitter {
6470
JsonEmitter {
6571
dst,
6672
registry,
6773
cm: code_map,
6874
pretty,
75+
approximate_suggestions,
6976
}
7077
}
7178
}
@@ -101,6 +108,7 @@ struct Diagnostic {
101108
}
102109

103110
#[derive(RustcEncodable)]
111+
#[allow(unused_attributes)]
104112
struct DiagnosticSpan {
105113
file_name: String,
106114
byte_start: u32,
@@ -121,6 +129,9 @@ struct DiagnosticSpan {
121129
/// If we are suggesting a replacement, this will contain text
122130
/// that should be sliced in atop this span.
123131
suggested_replacement: Option<String>,
132+
/// If the suggestion is approximate
133+
#[rustc_serialize_exclude_null]
134+
suggestion_approximate: Option<bool>,
124135
/// Macro invocations that created the code at this span, if any.
125136
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
126137
}
@@ -220,7 +231,7 @@ impl Diagnostic {
220231

221232
impl DiagnosticSpan {
222233
fn from_span_label(span: SpanLabel,
223-
suggestion: Option<&String>,
234+
suggestion: Option<(&String, bool)>,
224235
je: &JsonEmitter)
225236
-> DiagnosticSpan {
226237
Self::from_span_etc(span.span,
@@ -233,7 +244,7 @@ impl DiagnosticSpan {
233244
fn from_span_etc(span: Span,
234245
is_primary: bool,
235246
label: Option<String>,
236-
suggestion: Option<&String>,
247+
suggestion: Option<(&String, bool)>,
237248
je: &JsonEmitter)
238249
-> DiagnosticSpan {
239250
// obtain the full backtrace from the `macro_backtrace`
@@ -253,7 +264,7 @@ impl DiagnosticSpan {
253264
fn from_span_full(span: Span,
254265
is_primary: bool,
255266
label: Option<String>,
256-
suggestion: Option<&String>,
267+
suggestion: Option<(&String, bool)>,
257268
mut backtrace: vec::IntoIter<MacroBacktrace>,
258269
je: &JsonEmitter)
259270
-> DiagnosticSpan {
@@ -281,6 +292,13 @@ impl DiagnosticSpan {
281292
def_site_span,
282293
})
283294
});
295+
296+
let suggestion_approximate = if je.approximate_suggestions {
297+
suggestion.map(|x| x.1)
298+
} else {
299+
None
300+
};
301+
284302
DiagnosticSpan {
285303
file_name: start.file.name.to_string(),
286304
byte_start: span.lo().0 - start.file.start_pos.0,
@@ -291,7 +309,8 @@ impl DiagnosticSpan {
291309
column_end: end.col.0 + 1,
292310
is_primary,
293311
text: DiagnosticSpanLine::from_span(span, je),
294-
suggested_replacement: suggestion.cloned(),
312+
suggested_replacement: suggestion.map(|x| x.0.clone()),
313+
suggestion_approximate,
295314
expansion: backtrace_step,
296315
label,
297316
}
@@ -309,14 +328,15 @@ impl DiagnosticSpan {
309328
suggestion.substitutions
310329
.iter()
311330
.flat_map(|substitution| {
312-
substitution.parts.iter().map(move |suggestion| {
331+
substitution.parts.iter().map(move |suggestion_inner| {
313332
let span_label = SpanLabel {
314-
span: suggestion.span,
333+
span: suggestion_inner.span,
315334
is_primary: true,
316335
label: None,
317336
};
318337
DiagnosticSpan::from_span_label(span_label,
319-
Some(&suggestion.snippet),
338+
Some((&suggestion_inner.snippet,
339+
suggestion.approximate)),
320340
je)
321341
})
322342
})

src/libsyntax/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(match_default_bindings)]
2626
#![feature(i128_type)]
2727
#![feature(const_atomic_usize_new)]
28+
#![feature(rustc_attrs)]
2829

2930
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
3031
#[allow(unused_extern_crates)]

src/libsyntax_ext/deriving/encodable.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
190190
Struct(_, ref fields) => {
191191
let emit_struct_field = cx.ident_of("emit_struct_field");
192192
let mut stmts = Vec::new();
193-
for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
193+
for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() {
194194
let name = match name {
195195
Some(id) => id.name,
196196
None => Symbol::intern(&format!("_field{}", i)),
@@ -212,7 +212,19 @@ fn encodable_substructure(cx: &mut ExtCtxt,
212212
} else {
213213
cx.expr(span, ExprKind::Ret(Some(call)))
214214
};
215-
stmts.push(cx.stmt_expr(call));
215+
216+
// This exists for https://github.com/rust-lang/rust/pull/47540
217+
//
218+
// If we decide to stabilize that flag this can be removed
219+
let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) {
220+
let is_some = cx.ident_of("is_some");
221+
let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]);
222+
cx.expr_if(span, condition, call, None)
223+
} else {
224+
call
225+
};
226+
let stmt = cx.stmt_expr(expr);
227+
stmts.push(stmt);
216228
}
217229

218230
// unit structs have no fields and need to return Ok()

0 commit comments

Comments
 (0)