//! This module implements some validity checks for attributes. //! In particular it verifies that `#[inline]` and `#[repr]` attributes are //! attached to items that actually support them and if there are //! conflicts between multiple such attributes attached to the same //! item. use std::fmt::{self, Display}; use rustc_ast::visit::AssocCtxt; use rustc_ast::{AssocItemKind, ForeignItemKind, ast}; use rustc_macros::HashStable_Generic; use crate::def::DefKind; use crate::{Item, ItemKind, TraitItem, TraitItemKind, hir}; #[derive(Copy, Clone, PartialEq, Debug, Eq, HashStable_Generic)] pub enum GenericParamKind { Type, Lifetime, Const, } #[derive(Copy, Clone, PartialEq, Debug, Eq, HashStable_Generic)] pub enum MethodKind { /// Method in a `trait Trait` block Trait { /// Whether a default is provided for this method body: bool, }, /// Method in a `impl Trait for Type` block TraitImpl, /// Method in a `impl Type` block Inherent, } #[derive(Copy, Clone, PartialEq, Debug, Eq, HashStable_Generic)] pub enum Target { ExternCrate, Use, Static, Const, Fn, Closure, Mod, ForeignMod, GlobalAsm, TyAlias, Enum, Variant, Struct, Field, Union, Trait, TraitAlias, Impl { of_trait: bool }, Expression, Statement, Arm, AssocConst, Method(MethodKind), AssocTy, ForeignFn, ForeignStatic, ForeignTy, GenericParam { kind: GenericParamKind, has_default: bool }, MacroDef, Param, PatField, ExprField, WherePredicate, MacroCall, Crate, Delegation { mac: bool }, } impl Display for Target { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::name(*self)) } } rustc_error_messages::into_diag_arg_using_display!(Target); impl Target { pub fn is_associated_item(self) -> bool { match self { Target::AssocConst | Target::AssocTy | Target::Method(_) => true, Target::ExternCrate | Target::Use | Target::Static | Target::Const | Target::Fn | Target::Closure | Target::Mod | Target::ForeignMod | Target::GlobalAsm | Target::TyAlias | Target::Enum | Target::Variant | Target::Struct | Target::Field | Target::Union | Target::Trait | Target::TraitAlias | Target::Impl { .. } | Target::Expression | Target::Statement | Target::Arm | Target::ForeignFn | Target::ForeignStatic | Target::ForeignTy | Target::GenericParam { .. } | Target::MacroDef | Target::Param | Target::PatField | Target::ExprField | Target::MacroCall | Target::Crate | Target::WherePredicate | Target::Delegation { .. } => false, } } pub fn from_item(item: &Item<'_>) -> Target { match item.kind { ItemKind::ExternCrate(..) => Target::ExternCrate, ItemKind::Use(..) => Target::Use, ItemKind::Static { .. } => Target::Static, ItemKind::Const(..) => Target::Const, ItemKind::Fn { .. } => Target::Fn, ItemKind::Macro(..) => Target::MacroDef, ItemKind::Mod(..) => Target::Mod, ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm { .. } => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, ItemKind::Union(..) => Target::Union, ItemKind::Trait(..) => Target::Trait, ItemKind::TraitAlias(..) => Target::TraitAlias, ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() }, } } // FIXME: For now, should only be used with def_kinds from ItemIds pub fn from_def_kind(def_kind: DefKind) -> Target { match def_kind { DefKind::ExternCrate => Target::ExternCrate, DefKind::Use => Target::Use, DefKind::Static { .. } => Target::Static, DefKind::Const => Target::Const, DefKind::Fn => Target::Fn, DefKind::Macro(..) => Target::MacroDef, DefKind::Mod => Target::Mod, DefKind::ForeignMod => Target::ForeignMod, DefKind::GlobalAsm => Target::GlobalAsm, DefKind::TyAlias => Target::TyAlias, DefKind::Enum => Target::Enum, DefKind::Struct => Target::Struct, DefKind::Union => Target::Union, DefKind::Trait => Target::Trait, DefKind::TraitAlias => Target::TraitAlias, DefKind::Impl { of_trait } => Target::Impl { of_trait }, _ => panic!("impossible case reached"), } } pub fn from_ast_item(item: &ast::Item) -> Target { match item.kind { ast::ItemKind::ExternCrate(..) => Target::ExternCrate, ast::ItemKind::Use(..) => Target::Use, ast::ItemKind::Static { .. } => Target::Static, ast::ItemKind::Const(..) => Target::Const, ast::ItemKind::Fn { .. } => Target::Fn, ast::ItemKind::Mod(..) => Target::Mod, ast::ItemKind::ForeignMod { .. } => Target::ForeignMod, ast::ItemKind::GlobalAsm { .. } => Target::GlobalAsm, ast::ItemKind::TyAlias(..) => Target::TyAlias, ast::ItemKind::Enum(..) => Target::Enum, ast::ItemKind::Struct(..) => Target::Struct, ast::ItemKind::Union(..) => Target::Union, ast::ItemKind::Trait(..) => Target::Trait, ast::ItemKind::TraitAlias(..) => Target::TraitAlias, ast::ItemKind::Impl(ref i) => Target::Impl { of_trait: i.of_trait.is_some() }, ast::ItemKind::MacCall(..) => Target::MacroCall, ast::ItemKind::MacroDef(..) => Target::MacroDef, ast::ItemKind::Delegation(..) => Target::Delegation { mac: false }, ast::ItemKind::DelegationMac(..) => Target::Delegation { mac: true }, } } pub fn from_foreign_item_kind(kind: &ast::ForeignItemKind) -> Target { match kind { ForeignItemKind::Static(_) => Target::ForeignStatic, ForeignItemKind::Fn(_) => Target::ForeignFn, ForeignItemKind::TyAlias(_) => Target::ForeignTy, ForeignItemKind::MacCall(_) => Target::MacroCall, } } pub fn from_trait_item(trait_item: &TraitItem<'_>) -> Target { match trait_item.kind { TraitItemKind::Const(..) => Target::AssocConst, TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { Target::Method(MethodKind::Trait { body: false }) } TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { Target::Method(MethodKind::Trait { body: true }) } TraitItemKind::Type(..) => Target::AssocTy, } } pub fn from_foreign_item(foreign_item: &hir::ForeignItem<'_>) -> Target { match foreign_item.kind { hir::ForeignItemKind::Fn(..) => Target::ForeignFn, hir::ForeignItemKind::Static(..) => Target::ForeignStatic, hir::ForeignItemKind::Type => Target::ForeignTy, } } pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target { match generic_param.kind { hir::GenericParamKind::Type { default, .. } => Target::GenericParam { kind: GenericParamKind::Type, has_default: default.is_some(), }, hir::GenericParamKind::Lifetime { .. } => { Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false } } hir::GenericParamKind::Const { default, .. } => Target::GenericParam { kind: GenericParamKind::Const, has_default: default.is_some(), }, } } pub fn from_assoc_item_kind(kind: &ast::AssocItemKind, assoc_ctxt: AssocCtxt) -> Target { match kind { AssocItemKind::Const(_) => Target::AssocConst, AssocItemKind::Fn(f) => Target::Method(match assoc_ctxt { AssocCtxt::Trait => MethodKind::Trait { body: f.body.is_some() }, AssocCtxt::Impl { of_trait } => { if of_trait { MethodKind::TraitImpl } else { MethodKind::Inherent } } }), AssocItemKind::Type(_) => Target::AssocTy, AssocItemKind::Delegation(_) => Target::Delegation { mac: false }, AssocItemKind::DelegationMac(_) => Target::Delegation { mac: true }, AssocItemKind::MacCall(_) => Target::MacroCall, } } pub fn from_expr(expr: &ast::Expr) -> Self { match &expr.kind { ast::ExprKind::Closure(..) | ast::ExprKind::Gen(..) => Self::Closure, ast::ExprKind::Paren(e) => Self::from_expr(&e), _ => Self::Expression, } } pub fn name(self) -> &'static str { match self { Target::ExternCrate => "extern crate", Target::Use => "use", Target::Static => "static", Target::Const => "constant", Target::Fn => "function", Target::Closure => "closure", Target::Mod => "module", Target::ForeignMod => "foreign module", Target::GlobalAsm => "global asm", Target::TyAlias => "type alias", Target::Enum => "enum", Target::Variant => "enum variant", Target::Struct => "struct", Target::Field => "struct field", Target::Union => "union", Target::Trait => "trait", Target::TraitAlias => "trait alias", Target::Impl { .. } => "implementation block", Target::Expression => "expression", Target::Statement => "statement", Target::Arm => "match arm", Target::AssocConst => "associated const", Target::Method(kind) => match kind { MethodKind::Inherent => "inherent method", MethodKind::Trait { body: false } => "required trait method", MethodKind::Trait { body: true } => "provided trait method", MethodKind::TraitImpl => "trait method in an impl block", }, Target::AssocTy => "associated type", Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", Target::ForeignTy => "foreign type", Target::GenericParam { kind, .. } => match kind { GenericParamKind::Type => "type parameter", GenericParamKind::Lifetime => "lifetime parameter", GenericParamKind::Const => "const parameter", }, Target::MacroDef => "macro def", Target::Param => "function param", Target::PatField => "pattern field", Target::ExprField => "struct field", Target::WherePredicate => "where predicate", Target::MacroCall => "macro call", Target::Crate => "crate", Target::Delegation { .. } => "delegation", } } pub fn plural_name(self) -> &'static str { match self { Target::ExternCrate => "extern crates", Target::Use => "use statements", Target::Static => "statics", Target::Const => "constants", Target::Fn => "functions", Target::Closure => "closures", Target::Mod => "modules", Target::ForeignMod => "foreign modules", Target::GlobalAsm => "global asms", Target::TyAlias => "type aliases", Target::Enum => "enums", Target::Variant => "enum variants", Target::Struct => "structs", Target::Field => "struct fields", Target::Union => "unions", Target::Trait => "traits", Target::TraitAlias => "trait aliases", Target::Impl { of_trait: false } => "inherent impl blocks", Target::Impl { of_trait: true } => "trait impl blocks", Target::Expression => "expressions", Target::Statement => "statements", Target::Arm => "match arms", Target::AssocConst => "associated consts", Target::Method(kind) => match kind { MethodKind::Inherent => "inherent methods", MethodKind::Trait { body: false } => "required trait methods", MethodKind::Trait { body: true } => "provided trait methods", MethodKind::TraitImpl => "trait methods in impl blocks", }, Target::AssocTy => "associated types", Target::ForeignFn => "foreign functions", Target::ForeignStatic => "foreign statics", Target::ForeignTy => "foreign types", Target::GenericParam { kind, has_default: _ } => match kind { GenericParamKind::Type => "type parameters", GenericParamKind::Lifetime => "lifetime parameters", GenericParamKind::Const => "const parameters", }, Target::MacroDef => "macro defs", Target::Param => "function params", Target::PatField => "pattern fields", Target::ExprField => "struct fields", Target::WherePredicate => "where predicates", Target::MacroCall => "macro calls", Target::Crate => "crates", Target::Delegation { .. } => "delegations", } } }