1
Fork 0

Rollup merge of #97028 - ridwanabdillahi:pretty-printer, r=michaelwoerister

Add support for embedding pretty printers via `#[debugger_visualizer]` attribute

Initial support for [RFC 3191](https://github.com/rust-lang/rfcs/pull/3191) in PR https://github.com/rust-lang/rust/pull/91779 was scoped to supporting embedding NatVis files using a new attribute. This PR implements the pretty printer support as stated in the RFC mentioned above.

This change includes embedding pretty printers in the `.debug_gdb_scripts` just as the pretty printers for rustc are embedded today. Also added additional tests for embedded pretty printers. Additionally cleaned up error checking so all error checking is done up front regardless of the current target.

RFC: https://github.com/rust-lang/rfcs/pull/3191
This commit is contained in:
Guillaume Gomez 2022-05-29 01:12:30 +02:00 committed by GitHub
commit 239287f013
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 462 additions and 200 deletions

View file

@ -8,6 +8,7 @@ use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_expand::base::resolve_path;
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@ -1982,49 +1983,64 @@ impl CheckAttrVisitor<'_> {
}
}
let hints = match attr.meta_item_list() {
Some(meta_item_list) => meta_item_list,
None => {
self.emit_debugger_visualizer_err(attr);
return false;
}
let Some(hints) = attr.meta_item_list() else {
self.emit_debugger_visualizer_err(attr.span);
return false;
};
let hint = match hints.len() {
1 => &hints[0],
_ => {
self.emit_debugger_visualizer_err(attr);
self.emit_debugger_visualizer_err(attr.span);
return false;
}
};
if !hint.has_name(sym::natvis_file) {
self.emit_debugger_visualizer_err(attr);
let Some(meta_item) = hint.meta_item() else {
self.emit_debugger_visualizer_err(attr.span);
return false;
}
};
let meta_item = match hint.meta_item() {
Some(meta_item) => meta_item,
None => {
self.emit_debugger_visualizer_err(attr);
let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) {
(sym::natvis_file, Some(value)) => value,
(sym::gdb_script_file, Some(value)) => value,
(_, _) => {
self.emit_debugger_visualizer_err(meta_item.span);
return false;
}
};
match (meta_item.name_or_empty(), meta_item.value_str()) {
(sym::natvis_file, Some(_)) => true,
(_, _) => {
self.emit_debugger_visualizer_err(attr);
let file =
match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) {
Ok(file) => file,
Err(mut err) => {
err.emit();
return false;
}
};
match std::fs::File::open(&file) {
Ok(_) => true,
Err(err) => {
self.tcx
.sess
.struct_span_err(
meta_item.span,
&format!("couldn't read {}: {}", file.display(), err),
)
.emit();
false
}
}
}
fn emit_debugger_visualizer_err(&self, attr: &Attribute) {
fn emit_debugger_visualizer_err(&self, span: Span) {
self.tcx
.sess
.struct_span_err(attr.span, "invalid argument")
.struct_span_err(span, "invalid argument")
.note(r#"expected: `natvis_file = "..."`"#)
.note(r#"OR"#)
.note(r#"expected: `gdb_script_file = "..."`"#)
.emit();
}

View file

@ -21,9 +21,8 @@ fn check_for_debugger_visualizer<'tcx>(
let attrs = tcx.hir().attrs(hir_id);
for attr in attrs {
if attr.has_name(sym::debugger_visualizer) {
let list = match attr.meta_item_list() {
Some(list) => list,
_ => continue,
let Some(list) = attr.meta_item_list() else {
continue
};
let meta_item = match list.len() {
@ -34,45 +33,35 @@ fn check_for_debugger_visualizer<'tcx>(
_ => continue,
};
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
(sym::natvis_file, Some(value)) => {
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
Ok(file) => file,
Err(mut err) => {
err.emit();
continue;
}
}
}
(_, _) => continue,
let visualizer_type = match meta_item.name_or_empty() {
sym::natvis_file => DebuggerVisualizerType::Natvis,
sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
_ => continue,
};
if file.is_file() {
let contents = match std::fs::read(&file) {
Ok(contents) => contents,
Err(err) => {
tcx.sess
.struct_span_err(
attr.span,
&format!(
"Unable to read contents of file `{}`. {}",
file.display(),
err
),
)
.emit();
continue;
let file = match meta_item.value_str() {
Some(value) => {
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
Ok(file) => file,
_ => continue,
}
};
}
None => continue,
};
debugger_visualizers.insert(DebuggerVisualizerFile::new(
Arc::from(contents),
DebuggerVisualizerType::Natvis,
));
} else {
tcx.sess
.struct_span_err(attr.span, &format!("{} is not a valid file", file.display()))
.emit();
match std::fs::read(&file) {
Ok(contents) => {
debugger_visualizers
.insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
}
Err(err) => {
tcx.sess
.struct_span_err(
meta_item.span,
&format!("couldn't read {}: {}", file.display(), err),
)
.emit();
}
}
}
}