Skip to main content

rustc_ast_passes/
show_spans.rs

1use rustc_ast::visit::{self, Visitor};
2use rustc_ast::{self as ast, ItemKind};
3use rustc_attr_ir::{Attribute, AttributeKind, RustcShowSpansKind};
4use rustc_attr_parsing::AttributeParser;
5use rustc_session::Session;
6use rustc_span::sym;
7
8use crate::diagnostics;
9
10struct ShowSpans<'a> {
11    sess: &'a Session,
12    expr: bool,
13    ty: bool,
14    path: bool,
15}
16
17impl<'a> Visitor<'a> for ShowSpans<'a> {
18    fn visit_item(&mut self, item: &'a ast::Item) {
19        let saved = (self.expr, self.ty, self.path);
20        (self.expr, self.ty, self.path) = (false, false, false);
21
22        if let ItemKind::Fn(_) = &item.kind
23            && let Some(Attribute::Parsed(AttributeKind::RustcShowSpans(kinds))) =
24                AttributeParser::parse_limited_sym(self.sess, &item.attrs, &[sym::rustc_show_spans])
25        {
26            for kind in kinds {
27                match kind {
28                    RustcShowSpansKind::Expr => self.expr = true,
29                    RustcShowSpansKind::Ty => self.ty = true,
30                    RustcShowSpansKind::Path => self.path = true,
31                }
32            }
33        }
34        visit::walk_item(self, item);
35
36        // Recover the state. Needed if we are looking into nested items.
37        (self.expr, self.ty, self.path) = saved;
38    }
39
40    // We override it as to not report attribute paths as paths.
41    fn visit_attribute(&mut self, _: &'a ast::Attribute) {}
42
43    fn visit_expr(&mut self, e: &'a ast::Expr) {
44        if self.expr {
45            self.sess.dcx().emit_note(diagnostics::ShowSpan { span: e.span, kind: "expr" });
46        }
47        visit::walk_expr(self, e);
48    }
49
50    fn visit_ty(&mut self, t: &'a ast::Ty) {
51        if self.ty {
52            self.sess.dcx().emit_note(diagnostics::ShowSpan { span: t.span, kind: "ty" });
53        }
54        visit::walk_ty(self, t);
55    }
56
57    fn visit_path(&mut self, p: &'a ast::Path) {
58        if self.path {
59            self.sess.dcx().emit_note(diagnostics::ShowSpan { span: p.span, kind: "path" });
60        }
61        visit::walk_path(self, p);
62    }
63}
64
65pub fn check_crate(sess: &Session, krate: &ast::Crate) {
66    visit::walk_crate(&mut ShowSpans { sess, expr: false, ty: false, path: false }, krate);
67}