1
Fork 0

Rollup merge of #127022 - adwinwhite:attrs, r=celinval

Support fetching `Attribute` of items.

Fixes [https://github.com/rust-lang/project-stable-mir/issues/83](https://github.com/rust-lang/project-stable-mir/issues/83)

`rustc_ast::ast::Attribute` doesn't impl `Hash` and `Eq`. Thus it cannot be directly used as key of `IndexMap` in `rustc_smir::rustc_smir::Tables` and we cannot define stable `Attribute` as index to `rustc_ast::ast::Attribute` like `Span` and many other stable definitions.

Since an string (or tokens) and its span contain all info about an attribute, I defined a simple `Attribute` struct on stable side.

I choose to fetch attributes via `tcx::get_attrs_by_path()` due to `get_attrs()` is marked as deprecated and `get_attrs_by_name()` cannot handle name of multiple segments like `rustfmt::skip`.

r? `@celinval`
This commit is contained in:
Matthias Krüger 2024-06-28 08:34:09 +02:00 committed by GitHub
commit d730f27fc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 246 additions and 0 deletions

View file

@ -6,6 +6,8 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
rustc_middle = { path = "../rustc_middle" }

View file

@ -228,6 +228,46 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn get_attrs_by_path(
&self,
def_id: stable_mir::DefId,
attr: &[stable_mir::Symbol],
) -> Vec<stable_mir::crate_def::Attribute> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let did = tables[def_id];
let attr_name: Vec<_> =
attr.iter().map(|seg| rustc_span::symbol::Symbol::intern(&seg)).collect();
tcx.get_attrs_by_path(did, &attr_name)
.map(|attribute| {
let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute);
let span = attribute.span;
stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables))
})
.collect()
}
fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let did = tables[def_id];
let filter_fn = move |a: &&rustc_ast::ast::Attribute| {
matches!(a.kind, rustc_ast::ast::AttrKind::Normal(_))
};
let attrs_iter = if let Some(did) = did.as_local() {
tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else {
tcx.item_attrs(did).iter().filter(filter_fn)
};
attrs_iter
.map(|attribute| {
let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute);
let span = attribute.span;
stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables))
})
.collect()
}
fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
let tables = self.0.borrow();
tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])

View file

@ -6,6 +6,7 @@
use std::cell::Cell;
use crate::abi::{FnAbi, Layout, LayoutShape};
use crate::crate_def::Attribute;
use crate::mir::alloc::{AllocId, GlobalAlloc};
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
use crate::mir::{BinOp, Body, Place, UnOp};
@ -55,6 +56,15 @@ pub trait Context {
/// Returns the name of given `DefId`
fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
/// Return attributes with the given attribute name.
///
/// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`.
/// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>;
/// Get all attributes of a definition.
fn get_all_attrs(&self, def_id: DefId) -> Vec<Attribute>;
/// Returns printable, human readable form of `Span`
fn span_to_string(&self, span: Span) -> String;

View file

@ -50,6 +50,21 @@ pub trait CrateDef {
let def_id = self.def_id();
with(|cx| cx.span_of_an_item(def_id))
}
/// Return attributes with the given attribute name.
///
/// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`.
/// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
fn attrs_by_path(&self, attr: &[Symbol]) -> Vec<Attribute> {
let def_id = self.def_id();
with(|cx| cx.get_attrs_by_path(def_id, attr))
}
/// Return all attributes of this definition.
fn all_attrs(&self) -> Vec<Attribute> {
let def_id = self.def_id();
with(|cx| cx.get_all_attrs(def_id))
}
}
/// A trait that can be used to retrieve a definition's type.
@ -69,6 +84,28 @@ pub trait CrateDefType: CrateDef {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Attribute {
value: String,
span: Span,
}
impl Attribute {
pub fn new(value: String, span: Span) -> Attribute {
Attribute { value, span }
}
/// Get the span of this attribute.
pub fn span(&self) -> Span {
self.span
}
/// Get the string representation of this attribute.
pub fn as_str(&self) -> &str {
&self.value
}
}
macro_rules! crate_def {
( $(#[$attr:meta])*
$vis:vis $name:ident $(;)?