use proc_macro2::Ident;
use syn::{AngleBracketedGenericArguments, AssocConst, AssocType, BareFnArg, Constraint, Expr, GenericArgument, ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, ReturnType, Stmt, TraitBound, Type, TypeArray, TypeBareFn, TypeImplTrait, TypeParamBound, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple};
use syn::punctuated::Punctuated;
use crate::ext::MaybeTraitBound;
pub trait Constraints {
fn has_self(&self) -> bool;
fn has_no_self(&self) -> bool { !self.has_self() }
}
impl<T, P> Constraints for Punctuated<T, P> where T: Constraints {
fn has_self(&self) -> bool {
self.iter().any(|p| p.has_self())
}
}
impl Constraints for Constraint {
fn has_self(&self) -> bool {
self.ident.has_self()
}
}
impl Constraints for Ident {
fn has_self(&self) -> bool {
self == "Self"
}
}
impl Constraints for QSelf {
fn has_self(&self) -> bool {
self.ty.has_self()
}
}
impl Constraints for TypeParamBound {
fn has_self(&self) -> bool {
self.maybe_trait_bound().is_some_and(Constraints::has_self)
}
}
impl Constraints for TraitBound {
fn has_self(&self) -> bool {
self.path.has_self()
}
}
impl Constraints for Path {
fn has_self(&self) -> bool {
self.segments.has_self()
}
}
impl Constraints for GenericArgument {
fn has_self(&self) -> bool {
match self {
GenericArgument::Lifetime(_) => false,
GenericArgument::Type(ty) => ty.has_self(),
GenericArgument::Const(_expr) => false, GenericArgument::Constraint(constraint) => constraint.has_self(),
GenericArgument::AssocType(assoc_type) => assoc_type.has_self(),
GenericArgument::AssocConst(assoc_const) => assoc_const.has_self(),
_ => false
}
}
}
impl Constraints for AssocType {
fn has_self(&self) -> bool {
self.ident.eq("Self") || self.ty.has_self() || self.generics.as_ref().map(|generics| generics.has_self()).unwrap_or_default()
}
}
impl Constraints for AssocConst {
fn has_self(&self) -> bool {
self.ident.eq("Self") || self.value.has_self() || self.generics.as_ref().map(|generics| generics.has_self()).unwrap_or_default()
}
}
impl Constraints for Stmt {
fn has_self(&self) -> bool {
match self {
Stmt::Local(local) => local.init.as_ref().map(|aa| aa.expr.has_self() || aa.diverge.as_ref().map(|(_, e)| e.has_self()).unwrap_or_default()).unwrap_or_default(),
Stmt::Item(_) => false,
Stmt::Expr(expr, _) => expr.has_self(),
Stmt::Macro(stmt_macro) => stmt_macro.mac.path.has_self()
}
}
}
impl Constraints for Expr {
fn has_self(&self) -> bool {
match self {
Expr::Array(expr_array) => expr_array.elems.has_self(),
Expr::Assign(expr_assign) => expr_assign.left.has_self() || expr_assign.right.has_self(),
Expr::Binary(expr_binary) => expr_binary.left.has_self() || expr_binary.right.has_self(),
Expr::Block(expr_block) => expr_block.block.stmts.iter().any(Constraints::has_self),
_ => false
}
}
}
impl Constraints for AngleBracketedGenericArguments {
fn has_self(&self) -> bool {
todo!()
}
}
impl Constraints for ReturnType {
fn has_self(&self) -> bool {
if let ReturnType::Type(_, ty) = self {
ty.has_self()
} else {
false
}
}
}
impl Constraints for PathSegment {
fn has_self(&self) -> bool {
self.ident.has_self() || self.arguments.has_self()
}
}
impl Constraints for PathArguments {
fn has_self(&self) -> bool {
match self {
PathArguments::None => false,
PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }) =>
args.has_self(),
PathArguments::Parenthesized(ParenthesizedGenericArguments { inputs, output, .. }) =>
inputs.has_self() || output.has_self()
}
}
}
impl Constraints for Type {
fn has_self(&self) -> bool {
match self {
Type::Array(TypeArray { elem, .. }) |
Type::Paren(TypeParen { elem, .. }) |
Type::Ptr(TypePtr { elem, .. }) |
Type::Reference(TypeReference { elem, .. }) |
Type::Slice(TypeSlice { elem, .. }) => elem.has_self(),
Type::BareFn(TypeBareFn { inputs, output, .. }) =>
inputs.iter().any(|BareFnArg { ty, .. }| ty.has_self()) || output.has_self(),
Type::ImplTrait(TypeImplTrait { bounds, .. }) |
Type::TraitObject(TypeTraitObject { bounds, .. }) => bounds.has_self(),
Type::Path(TypePath { qself, path }) => path.has_self() || qself.as_ref().map(Constraints::has_self).unwrap_or_default(),
Type::Tuple(TypeTuple { elems, .. }) => elems.has_self(),
_ => false,
}
}
}