Add hir::Attribute

This commit is contained in:
Jonathan Dönszelmann
2024-10-17 01:14:01 +02:00
parent 53b2c7cc95
commit d50c0a5480
89 changed files with 1144 additions and 659 deletions

View File

@@ -1,10 +1,13 @@
use std::fmt;
use rustc_abi::ExternAbi;
// ignore-tidy-filelength
use rustc_ast::attr::AttributeExt;
use rustc_ast::token::CommentKind;
use rustc_ast::util::parser::{AssocOp, ExprPrecedence};
use rustc_ast::{
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
LitKind, TraitObjectSyntax, UintTy,
self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece,
IntTy, Label, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy,
};
pub use rustc_ast::{
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
@@ -21,6 +24,7 @@ use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span};
use rustc_target::asm::InlineAsmRegOrRegClass;
use smallvec::SmallVec;
use thin_vec::ThinVec;
use tracing::debug;
use crate::LangItem;
@@ -937,6 +941,250 @@ pub struct ParentedNode<'tcx> {
pub node: Node<'tcx>,
}
/// Arguments passed to an attribute macro.
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub enum AttrArgs {
/// No arguments: `#[attr]`.
Empty,
/// Delimited arguments: `#[attr()/[]/{}]`.
Delimited(DelimArgs),
/// Arguments of a key-value attribute: `#[attr = "value"]`.
Eq {
/// Span of the `=` token.
eq_span: Span,
/// The "value".
expr: MetaItemLit,
},
}
#[derive(Clone, Debug, Encodable, Decodable)]
pub enum AttrKind {
/// A normal attribute.
Normal(Box<AttrItem>),
/// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
/// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
/// variant (which is much less compact and thus more expensive).
DocComment(CommentKind, Symbol),
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrPath {
pub segments: Box<[Ident]>,
pub span: Span,
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrItem {
pub unsafety: Safety,
// Not lowered to hir::Path because we have no NodeId to resolve to.
pub path: AttrPath,
pub args: AttrArgs,
}
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct Attribute {
pub kind: AttrKind,
pub id: AttrId,
/// Denotes if the attribute decorates the following construct (outer)
/// or the construct this attribute is contained within (inner).
pub style: AttrStyle,
pub span: Span,
}
impl Attribute {
pub fn get_normal_item(&self) -> &AttrItem {
match &self.kind {
AttrKind::Normal(normal) => &normal,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => *normal,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn value_lit(&self) -> Option<&MetaItemLit> {
match &self.kind {
AttrKind::Normal(n) => match n.as_ref() {
AttrItem { args: AttrArgs::Eq { expr, .. }, .. } => Some(expr),
_ => None,
},
_ => None,
}
}
}
impl AttributeExt for Attribute {
fn id(&self) -> AttrId {
self.id
}
fn meta_item_list(&self) -> Option<ThinVec<ast::MetaItemInner>> {
match &self.kind {
AttrKind::Normal(n) => match n.as_ref() {
AttrItem { args: AttrArgs::Delimited(d), .. } => {
ast::MetaItemKind::list_from_tokens(d.tokens.clone())
}
_ => None,
},
_ => None,
}
}
fn value_str(&self) -> Option<Symbol> {
self.value_lit().and_then(|x| x.value_str())
}
fn value_span(&self) -> Option<Span> {
self.value_lit().map(|i| i.span)
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
fn ident(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(n) => {
if let [ident] = n.path.segments.as_ref() {
Some(*ident)
} else {
None
}
}
AttrKind::DocComment(..) => None,
}
}
fn path_matches(&self, name: &[Symbol]) -> bool {
match &self.kind {
AttrKind::Normal(n) => {
n.path.segments.len() == name.len()
&& n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n)
}
AttrKind::DocComment(..) => false,
}
}
fn is_doc_comment(&self) -> bool {
matches!(self.kind, AttrKind::DocComment(..))
}
fn span(&self) -> Span {
self.span
}
fn is_word(&self) -> bool {
match &self.kind {
AttrKind::Normal(n) => {
matches!(n.args, AttrArgs::Empty)
}
AttrKind::DocComment(..) => false,
}
}
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
match &self.kind {
AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()),
AttrKind::DocComment(..) => None,
}
}
fn doc_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::DocComment(.., data) => Some(*data),
AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(),
_ => None,
}
}
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
match &self.kind {
AttrKind::DocComment(kind, data) => Some((*data, *kind)),
AttrKind::Normal(_) if self.name_or_empty() == sym::doc => {
self.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
fn style(&self) -> AttrStyle {
self.style
}
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding
impl Attribute {
pub fn id(&self) -> AttrId {
AttributeExt::id(self)
}
pub fn name_or_empty(&self) -> Symbol {
AttributeExt::name_or_empty(self)
}
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
AttributeExt::meta_item_list(self)
}
pub fn value_str(&self) -> Option<Symbol> {
AttributeExt::value_str(self)
}
pub fn value_span(&self) -> Option<Span> {
AttributeExt::value_span(self)
}
pub fn ident(&self) -> Option<Ident> {
AttributeExt::ident(self)
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
AttributeExt::path_matches(self, name)
}
pub fn is_doc_comment(&self) -> bool {
AttributeExt::is_doc_comment(self)
}
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
AttributeExt::has_name(self, name)
}
pub fn span(&self) -> Span {
AttributeExt::span(self)
}
pub fn is_word(&self) -> bool {
AttributeExt::is_word(self)
}
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
AttributeExt::path(self)
}
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
AttributeExt::ident_path(self)
}
pub fn doc_str(&self) -> Option<Symbol> {
AttributeExt::doc_str(self)
}
pub fn is_proc_macro_attr(&self) -> bool {
AttributeExt::is_proc_macro_attr(self)
}
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
AttributeExt::doc_str_and_comment_kind(self)
}
pub fn style(&self) -> AttrStyle {
AttributeExt::style(self)
}
}
/// Attributes owned by a HIR owner.
#[derive(Debug)]
pub struct AttributeMap<'tcx> {