Skip to content

Add approximate suggestions for rustfix #47540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 1, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
@@ -1288,6 +1288,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
"in dep-info output, omit targets for tracking dependencies of the dep-info files \
themselves"),
approximate_suggestions: bool = (false, parse_bool, [UNTRACKED],
"include machine-applicability of suggestions in JSON output"),
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
"Present the input source, unstable (and less-pretty) variants;
valid types are any of the types for `--pretty`, as well as:
6 changes: 4 additions & 2 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
@@ -910,10 +910,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false))
}
(config::ErrorOutputType::Json(pretty), None) => {
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(),
pretty, sopts.debugging_opts.approximate_suggestions))
}
(config::ErrorOutputType::Json(pretty), Some(dst)) => {
Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(),
pretty, sopts.debugging_opts.approximate_suggestions))
}
(config::ErrorOutputType::Short(color_config), None) => {
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true))
37 changes: 37 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -222,6 +222,7 @@ impl Diagnostic {
}],
msg: msg.to_owned(),
show_code_when_inline: false,
approximate: false,
});
self
}
@@ -252,6 +253,7 @@ impl Diagnostic {
}],
msg: msg.to_owned(),
show_code_when_inline: true,
approximate: false,
});
self
}
@@ -267,6 +269,41 @@ impl Diagnostic {
}).collect(),
msg: msg.to_owned(),
show_code_when_inline: true,
approximate: false,
});
self
}

/// This is a suggestion that may contain mistakes or fillers and should
/// be read and understood by a human.
pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str,
suggestion: String) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart {
snippet: suggestion,
span: sp,
}],
}],
msg: msg.to_owned(),
show_code_when_inline: true,
approximate: true,
});
self
}

pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str,
suggestions: Vec<String>) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: suggestions.into_iter().map(|snippet| Substitution {
parts: vec![SubstitutionPart {
snippet,
span: sp,
}],
}).collect(),
msg: msg.to_owned(),
show_code_when_inline: true,
approximate: true,
});
self
}
10 changes: 10 additions & 0 deletions src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
@@ -186,6 +186,16 @@ impl<'a> DiagnosticBuilder<'a> {
msg: &str,
suggestions: Vec<String>)
-> &mut Self);
forward!(pub fn span_approximate_suggestion(&mut self,
sp: Span,
msg: &str,
suggestion: String)
-> &mut Self);
forward!(pub fn span_approximate_suggestions(&mut self,
sp: Span,
msg: &str,
suggestions: Vec<String>)
-> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);

6 changes: 6 additions & 0 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
@@ -83,6 +83,12 @@ pub struct CodeSuggestion {
pub substitutions: Vec<Substitution>,
pub msg: String,
pub show_code_when_inline: bool,
/// Whether or not the suggestion is approximate
///
/// Sometimes we may show suggestions with placeholders,
/// which are useful for users but not useful for
/// tools like rustfix
pub approximate: bool,
}

#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
5 changes: 5 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -788,6 +788,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_serialize_exclude_null]` attribute \
is an internal-only feature",
cfg_fn!(rustc_attrs))),
("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"this attribute \
40 changes: 30 additions & 10 deletions src/libsyntax/json.rs
Original file line number Diff line number Diff line change
@@ -38,34 +38,41 @@ pub struct JsonEmitter {
registry: Option<Registry>,
cm: Rc<CodeMapper + 'static>,
pretty: bool,
/// Whether "approximate suggestions" are enabled in the config
approximate_suggestions: bool,
}

impl JsonEmitter {
pub fn stderr(registry: Option<Registry>,
code_map: Rc<CodeMap>,
pretty: bool) -> JsonEmitter {
pretty: bool,
approximate_suggestions: bool) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
registry,
cm: code_map,
pretty,
approximate_suggestions,
}
}

pub fn basic(pretty: bool) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)),
pretty, false)
}

pub fn new(dst: Box<Write + Send>,
registry: Option<Registry>,
code_map: Rc<CodeMap>,
pretty: bool) -> JsonEmitter {
pretty: bool,
approximate_suggestions: bool) -> JsonEmitter {
JsonEmitter {
dst,
registry,
cm: code_map,
pretty,
approximate_suggestions,
}
}
}
@@ -101,6 +108,7 @@ struct Diagnostic {
}

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

impl DiagnosticSpan {
fn from_span_label(span: SpanLabel,
suggestion: Option<&String>,
suggestion: Option<(&String, bool)>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it a bit weird that we have three different ways to represent the suggestion and whether it is machine applicable (two options, one option and a bool, one option of a tuple). It would be good to stick to one representation, if possible.

je: &JsonEmitter)
-> DiagnosticSpan {
Self::from_span_etc(span.span,
@@ -233,7 +244,7 @@ impl DiagnosticSpan {
fn from_span_etc(span: Span,
is_primary: bool,
label: Option<String>,
suggestion: Option<&String>,
suggestion: Option<(&String, bool)>,
je: &JsonEmitter)
-> DiagnosticSpan {
// obtain the full backtrace from the `macro_backtrace`
@@ -253,7 +264,7 @@ impl DiagnosticSpan {
fn from_span_full(span: Span,
is_primary: bool,
label: Option<String>,
suggestion: Option<&String>,
suggestion: Option<(&String, bool)>,
mut backtrace: vec::IntoIter<MacroBacktrace>,
je: &JsonEmitter)
-> DiagnosticSpan {
@@ -281,6 +292,13 @@ impl DiagnosticSpan {
def_site_span,
})
});

let suggestion_approximate = if je.approximate_suggestions {
suggestion.map(|x| x.1)
} else {
None
};

DiagnosticSpan {
file_name: start.file.name.to_string(),
byte_start: span.lo().0 - start.file.start_pos.0,
@@ -291,7 +309,8 @@ impl DiagnosticSpan {
column_end: end.col.0 + 1,
is_primary,
text: DiagnosticSpanLine::from_span(span, je),
suggested_replacement: suggestion.cloned(),
suggested_replacement: suggestion.map(|x| x.0.clone()),
suggestion_approximate,
expansion: backtrace_step,
label,
}
@@ -309,14 +328,15 @@ impl DiagnosticSpan {
suggestion.substitutions
.iter()
.flat_map(|substitution| {
substitution.parts.iter().map(move |suggestion| {
substitution.parts.iter().map(move |suggestion_inner| {
let span_label = SpanLabel {
span: suggestion.span,
span: suggestion_inner.span,
is_primary: true,
label: None,
};
DiagnosticSpan::from_span_label(span_label,
Some(&suggestion.snippet),
Some((&suggestion_inner.snippet,
suggestion.approximate)),
je)
})
})
1 change: 1 addition & 0 deletions src/libsyntax/lib.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
#![feature(match_default_bindings)]
#![feature(i128_type)]
#![feature(const_atomic_usize_new)]
#![feature(rustc_attrs)]

// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
16 changes: 14 additions & 2 deletions src/libsyntax_ext/deriving/encodable.rs
Original file line number Diff line number Diff line change
@@ -190,7 +190,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
Struct(_, ref fields) => {
let emit_struct_field = cx.ident_of("emit_struct_field");
let mut stmts = Vec::new();
for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() {
let name = match name {
Some(id) => id.name,
None => Symbol::intern(&format!("_field{}", i)),
@@ -212,7 +212,19 @@ fn encodable_substructure(cx: &mut ExtCtxt,
} else {
cx.expr(span, ExprKind::Ret(Some(call)))
};
stmts.push(cx.stmt_expr(call));

// This exists for https://github.com/rust-lang/rust/pull/47540
//
// If we decide to stabilize that flag this can be removed
let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) {
let is_some = cx.ident_of("is_some");
let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]);
cx.expr_if(span, condition, call, None)
} else {
call
};
let stmt = cx.stmt_expr(expr);
stmts.push(stmt);
}

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