1
Fork 0

Add support for embedding pretty printers via the #[debugger_visualizer] attribute. Add tests for embedding pretty printers and update documentation.

Ensure all error checking for `#[debugger_visualizer]` is done up front and not when the `debugger_visualizer` query is run.

Clean up potential ODR violations when embedding pretty printers into the `__rustc_debug_gdb_scripts_section__` section.

Respond to PR comments and update documentation.
This commit is contained in:
ridwanabdillahi 2022-05-24 11:14:48 -07:00
parent ee9726cb10
commit 60458b97e7
27 changed files with 455 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,28 @@ 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));
}
_ => {}
}
}
}