//! Compound types (unions and structs) in our intermediate representation.

use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::{TemplateDeclaration, Type};
use clang;
use parse::{ClangItemParser, ParseError};
use std::cell::Cell;

/// The kind of compound type.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CompKind {
    /// A struct.
    Struct,
    /// A union.
    Union,
}

/// The kind of C++ method.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MethodKind {
    /// A constructor. We represent it as method for convenience, to avoid code
    /// duplication.
    Constructor,
    /// A static method.
    Static,
    /// A normal method.
    Normal,
    /// A virtual method.
    Virtual,
}

/// A struct representing a C++ method, either static, normal, or virtual.
#[derive(Debug)]
pub struct Method {
    kind: MethodKind,
    /// The signature of the method. Take into account this is not a `Type`
    /// item, but a `Function` one.
    ///
    /// This is tricky and probably this field should be renamed.
    signature: ItemId,
    is_const: bool,
}

impl Method {
    /// Construct a new `Method`.
    pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
        Method {
            kind: kind,
            signature: signature,
            is_const: is_const,
        }
    }

    /// What kind of method is this?
    pub fn kind(&self) -> MethodKind {
        self.kind
    }

    /// Is this a constructor?
    pub fn is_constructor(&self) -> bool {
        self.kind == MethodKind::Constructor
    }

    /// Is this a virtual method?
    pub fn is_virtual(&self) -> bool {
        self.kind == MethodKind::Virtual
    }

    /// Is this a static method?
    pub fn is_static(&self) -> bool {
        self.kind == MethodKind::Static
    }

    /// Get the `ItemId` for the `Function` signature for this method.
    pub fn signature(&self) -> ItemId {
        self.signature
    }

    /// Is this a const qualified method?
    pub fn is_const(&self) -> bool {
        self.is_const
    }
}

/// A struct representing a C++ field.
#[derive(Clone, Debug)]
pub struct Field {
    /// The name of the field, empty if it's an unnamed bitfield width.
    name: Option<String>,
    /// The inner type.
    ty: ItemId,
    /// The doc comment on the field if any.
    comment: Option<String>,
    /// Annotations for this field, or the default.
    annotations: Annotations,
    /// If this field is a bitfield, and how many bits does it contain if it is.
    bitfield: Option<u32>,
    /// If the C++ field is marked as `mutable`
    mutable: bool,
    /// The offset of the field (in bits)
    offset: Option<usize>,
}

impl Field {
    /// Construct a new `Field`.
    pub fn new(name: Option<String>,
               ty: ItemId,
               comment: Option<String>,
               annotations: Option<Annotations>,
               bitfield: Option<u32>,
               mutable: bool,
               offset: Option<usize>)
               -> Field {
        Field {
            name: name,
            ty: ty,
            comment: comment,
            annotations: annotations.unwrap_or_default(),
            bitfield: bitfield,
            mutable: mutable,
            offset: offset,
        }
    }

    /// Get the name of this field.
    pub fn name(&self) -> Option<&str> {
        self.name.as_ref().map(|n| &**n)
    }

    /// Get the type of this field.
    pub fn ty(&self) -> ItemId {
        self.ty
    }

    /// Get the comment for this field.
    pub fn comment(&self) -> Option<&str> {
        self.comment.as_ref().map(|c| &**c)
    }

    /// If this is a bitfield, how many bits does it need?
    pub fn bitfield(&self) -> Option<u32> {
        self.bitfield
    }

    /// Is this field marked as `mutable`?
    pub fn is_mutable(&self) -> bool {
        self.mutable
    }

    /// Get the annotations for this field.
    pub fn annotations(&self) -> &Annotations {
        &self.annotations
    }

    /// The offset of the field (in bits)
    pub fn offset(&self) -> Option<usize> {
        self.offset
    }
}

impl CanDeriveDebug for Field {
    type Extra = ();

    fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.ty.can_derive_debug(ctx, ())
    }
}

impl CanDeriveDefault for Field {
    type Extra = ();

    fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.ty.can_derive_default(ctx, ())
    }
}

impl<'a> CanDeriveCopy<'a> for Field {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.ty.can_derive_copy(ctx, ())
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.ty.can_derive_copy_in_array(ctx, ())
    }
}


/// The kind of inheritance a base class is using.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BaseKind {
    /// Normal inheritance, like:
    ///
    /// ```cpp
    /// class A : public B {};
    /// ```
    Normal,
    /// Virtual inheritance, like:
    ///
    /// ```cpp
    /// class A: public virtual B {};
    /// ```
    Virtual,
}

/// A base class.
#[derive(Clone, Debug)]
pub struct Base {
    /// The type of this base class.
    pub ty: ItemId,
    /// The kind of inheritance we're doing.
    pub kind: BaseKind,
}

impl Base {
    /// Whether this base class is inheriting virtually.
    pub fn is_virtual(&self) -> bool {
        self.kind == BaseKind::Virtual
    }
}

/// A compound type.
///
/// Either a struct or union, a compound type is built up from the combination
/// of fields which also are associated with their own (potentially compound)
/// type.
#[derive(Debug)]
pub struct CompInfo {
    /// Whether this is a struct or a union.
    kind: CompKind,

    /// The members of this struct or union.
    fields: Vec<Field>,

    /// The template parameters of this class. These are non-concrete, and
    /// should always be a Type(TypeKind::Named(name)), but still they need to
    /// be registered with an unique type id in the context.
    template_args: Vec<ItemId>,

    /// The method declarations inside this class, if in C++ mode.
    methods: Vec<Method>,

    /// The different constructors this struct or class contains.
    constructors: Vec<ItemId>,

    /// Vector of classes this one inherits from.
    base_members: Vec<Base>,

    /// The parent reference template if any.
    ref_template: Option<ItemId>,

    /// The inner types that were declared inside this class, in something like:
    ///
    /// class Foo {
    ///     typedef int FooTy;
    ///     struct Bar {
    ///         int baz;
    ///     };
    /// }
    ///
    /// static Foo::Bar const = {3};
    inner_types: Vec<ItemId>,

    /// Set of static constants declared inside this class.
    inner_vars: Vec<ItemId>,

    /// Whether this type should generate an vtable (TODO: Should be able to
    /// look at the virtual methods and ditch this field).
    has_vtable: bool,

    /// Whether this type has destructor.
    has_destructor: bool,

    /// Whether this type has a base type with more than one member.
    ///
    /// TODO: We should be able to compute this.
    has_nonempty_base: bool,

    /// If this type has a template parameter which is not a type (e.g.: a
    /// size_t)
    has_non_type_template_params: bool,

    /// Whether this struct layout is packed.
    packed: bool,

    /// Used to know if we've found an opaque attribute that could cause us to
    /// generate a type with invalid layout. This is explicitly used to avoid us
    /// generating bad alignments when parsing types like max_align_t.
    ///
    /// It's not clear what the behavior should be here, if generating the item
    /// and pray, or behave as an opaque type.
    found_unknown_attr: bool,

    /// Used to detect if we've run in a can_derive_debug cycle while cycling
    /// around the template arguments.
    detect_derive_debug_cycle: Cell<bool>,

    /// Used to detect if we've run in a can_derive_default cycle while cycling
    /// around the template arguments.
    detect_derive_default_cycle: Cell<bool>,

    /// Used to detect if we've run in a has_destructor cycle while cycling
    /// around the template arguments.
    detect_has_destructor_cycle: Cell<bool>,

    /// Used to indicate when a struct has been forward declared. Usually used
    /// in headers so that APIs can't modify them directly.
    is_forward_declaration: bool,
}

impl CompInfo {
    /// Construct a new compound type.
    pub fn new(kind: CompKind) -> Self {
        CompInfo {
            kind: kind,
            fields: vec![],
            template_args: vec![],
            methods: vec![],
            constructors: vec![],
            base_members: vec![],
            ref_template: None,
            inner_types: vec![],
            inner_vars: vec![],
            has_vtable: false,
            has_destructor: false,
            has_nonempty_base: false,
            has_non_type_template_params: false,
            packed: false,
            found_unknown_attr: false,
            detect_derive_debug_cycle: Cell::new(false),
            detect_derive_default_cycle: Cell::new(false),
            detect_has_destructor_cycle: Cell::new(false),
            is_forward_declaration: false,
        }
    }

    /// Is this compound type unsized?
    pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
        !self.has_vtable(ctx) && self.fields.is_empty() &&
        self.base_members.iter().all(|base| {
            ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
        }) &&
        self.ref_template
            .map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx))
    }

    /// Does this compound type have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        if self.detect_has_destructor_cycle.get() {
            warn!("Cycle detected looking for destructors");
            // Assume no destructor, since we don't have an explicit one.
            return false;
        }

        self.detect_has_destructor_cycle.set(true);

        let has_destructor = self.has_destructor ||
                             match self.kind {
            CompKind::Union => false,
            CompKind::Struct => {
                // NB: We can't rely on a type with type parameters
                // not having destructor.
                //
                // This is unfortunate, but...
                self.ref_template.as_ref().map_or(false, |t| {
                    ctx.resolve_type(*t).has_destructor(ctx)
                }) ||
                self.template_args.iter().any(|t| {
                    ctx.resolve_type(*t).has_destructor(ctx)
                }) ||
                self.base_members.iter().any(|base| {
                    ctx.resolve_type(base.ty).has_destructor(ctx)
                }) ||
                self.fields.iter().any(|field| {
                    ctx.resolve_type(field.ty)
                        .has_destructor(ctx)
                })
            }
        };

        self.detect_has_destructor_cycle.set(false);

        has_destructor
    }

    /// Is this type a template specialization?
    pub fn is_template_specialization(&self) -> bool {
        self.ref_template.is_some()
    }

    /// Get the template declaration this specialization is specializing.
    pub fn specialized_template(&self) -> Option<ItemId> {
        self.ref_template
    }

    /// Compute the layout of this type.
    ///
    /// This is called as a fallback under some circumstances where LLVM doesn't
    /// give us the correct layout.
    ///
    /// If we're a union without known layout, we try to compute it from our
    /// members. This is not ideal, but clang fails to report the size for these
    /// kind of unions, see test/headers/template_union.hpp
    pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
        // We can't do better than clang here, sorry.
        if self.kind == CompKind::Struct {
            None
        } else {
            self.calc_layout(ctx)
        }
    }

    /// Compute the layout of this type.
    pub fn calc_layout(&self, ctx: &BindgenContext) -> Option<Layout> {
        use std::cmp;
        use std::mem;

        if self.kind == CompKind::Struct {
            let mut latest_offset_in_bits = 0;
            let mut max_align = 0;

            if self.needs_explicit_vtable(ctx) {
                latest_offset_in_bits += mem::size_of::<*mut ()>() * 8;
                max_align = mem::size_of::<*mut ()>();
            }

            for field in &self.fields {
                if let Some(bits) = field.bitfield() {
                    latest_offset_in_bits += bits as usize;
                } else {
                    let field_ty = ctx.resolve_type(field.ty);

                    if let Some(field_layout) =
                        field_ty.as_comp()
                            .and_then(|comp| comp.calc_layout(ctx))
                            .or_else(|| field_ty.layout(ctx)) {

                        let n = (latest_offset_in_bits / 8) %
                                field_layout.align;

                        if !self.packed && n != 0 {
                            latest_offset_in_bits += (field_layout.align - n) *
                                                     8;
                        }

                        latest_offset_in_bits += field_layout.size * 8;
                        max_align = cmp::max(max_align, field_layout.align);
                    }
                }
            }

            if latest_offset_in_bits == 0 && max_align == 0 {
                None
            } else {
                Some(Layout::new((latest_offset_in_bits + 7) / 8, max_align))
            }
        } else {
            let mut max_size = 0;
            let mut max_align = 0;
            for field in &self.fields {
                let field_layout = ctx.resolve_type(field.ty)
                    .layout(ctx);

                if let Some(layout) = field_layout {
                    max_size = cmp::max(max_size, layout.size);
                    max_align = cmp::max(max_align, layout.align);
                }
            }

            Some(Layout::new(max_size, max_align))
        }
    }

    /// Get this type's set of fields.
    pub fn fields(&self) -> &[Field] {
        &self.fields
    }

    /// Get this type's set of free template arguments. Empty if this is not a
    /// template.
    pub fn template_args(&self) -> &[ItemId] {
        &self.template_args
    }

    /// Does this type have any template parameters that aren't types
    /// (e.g. int)?
    pub fn has_non_type_template_params(&self) -> bool {
        self.has_non_type_template_params
    }

    /// Does this type have a virtual table?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        self.has_vtable ||
        self.base_members().iter().any(|base| {
            ctx.resolve_type(base.ty)
                .has_vtable(ctx)
        }) ||
        self.ref_template.map_or(false, |template| {
            ctx.resolve_type(template).has_vtable(ctx)
        })
    }

    /// Get this type's set of methods.
    pub fn methods(&self) -> &[Method] {
        &self.methods
    }

    /// Get this type's set of constructors.
    pub fn constructors(&self) -> &[ItemId] {
        &self.constructors
    }

    /// What kind of compound type is this?
    pub fn kind(&self) -> CompKind {
        self.kind
    }

    /// The set of types that this one inherits from.
    pub fn base_members(&self) -> &[Base] {
        &self.base_members
    }

    /// Construct a new compound type from a Clang type.
    pub fn from_ty(potential_id: ItemId,
                   ty: &clang::Type,
                   location: Option<clang::Cursor>,
                   ctx: &mut BindgenContext)
                   -> Result<Self, ParseError> {
        use clang_sys::*;
        // Sigh... For class templates we want the location, for
        // specialisations, we want the declaration...  So just try both.
        //
        // TODO: Yeah, this code reads really bad.
        let mut cursor = ty.declaration();
        let mut kind = Self::kind_from_cursor(&cursor);
        if kind.is_err() {
            if let Some(location) = location {
                kind = Self::kind_from_cursor(&location);
                cursor = location;
            }
        }

        let kind = try!(kind);

        debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);

        let mut ci = CompInfo::new(kind);
        ci.is_forward_declaration =
            location.map_or(true, |cur| match cur.kind() {
                CXCursor_StructDecl |
                CXCursor_UnionDecl |
                CXCursor_ClassDecl => !cur.is_definition(),
                _ => false,
            });
        ci.template_args = match ty.template_args() {
            // In forward declarations and not specializations, etc, they are in
            // the ast, we'll meet them in CXCursor_TemplateTypeParameter
            None => vec![],
            Some(arg_types) => {
                let num_arg_types = arg_types.len();
                let mut specialization = true;

                let args = arg_types.filter(|t| t.kind() != CXType_Invalid)
                    .filter_map(|t| if t.spelling()
                        .starts_with("type-parameter") {
                        specialization = false;
                        None
                    } else {
                        Some(Item::from_ty_or_ref(t, None, None, ctx))
                    })
                    .collect::<Vec<_>>();

                if specialization && args.len() != num_arg_types {
                    ci.has_non_type_template_params = true;
                    warn!("warning: Template parameter is not a type");
                }

                if specialization { args } else { vec![] }
            }
        };

        ci.ref_template = cursor.specialized()
            .and_then(|c| Item::parse(c, None, ctx).ok());

        let mut maybe_anonymous_struct_field = None;
        cursor.visit(|cur| {
            if cur.kind() != CXCursor_FieldDecl {
                if let Some((ty, _, offset)) =
                    maybe_anonymous_struct_field.take() {
                    let field =
                        Field::new(None, ty, None, None, None, false, offset);
                    ci.fields.push(field);
                }
            }

            match cur.kind() {
                CXCursor_FieldDecl => {
                    if let Some((ty, clang_ty, offset)) =
                        maybe_anonymous_struct_field.take() {
                        let mut used = false;
                        cur.visit(|child| {
                            if child.cur_type() == clang_ty {
                                used = true;
                            }
                            CXChildVisit_Continue
                        });
                        if !used {
                            let field = Field::new(None,
                                                   ty,
                                                   None,
                                                   None,
                                                   None,
                                                   false,
                                                   offset);
                            ci.fields.push(field);
                        }
                    }

                    let bit_width = cur.bit_width();
                    let field_type = Item::from_ty_or_ref(cur.cur_type(),
                                                          Some(cur),
                                                          Some(potential_id),
                                                          ctx);

                    let comment = cur.raw_comment();
                    let annotations = Annotations::new(&cur);
                    let name = cur.spelling();
                    let is_mutable = cursor.is_mutable_field();
                    let offset = cur.offset_of_field().ok();

                    // Name can be empty if there are bitfields, for example,
                    // see tests/headers/struct_with_bitfields.h
                    assert!(!name.is_empty() || bit_width.is_some(),
                            "Empty field name?");

                    let name = if name.is_empty() { None } else { Some(name) };

                    let field = Field::new(name,
                                           field_type,
                                           comment,
                                           annotations,
                                           bit_width,
                                           is_mutable,
                                           offset);
                    ci.fields.push(field);

                    // No we look for things like attributes and stuff.
                    cur.visit(|cur| {
                        if cur.kind() == CXCursor_UnexposedAttr {
                            ci.found_unknown_attr = true;
                        }
                        CXChildVisit_Continue
                    });

                }
                CXCursor_UnexposedAttr => {
                    ci.found_unknown_attr = true;
                }
                CXCursor_EnumDecl |
                CXCursor_TypeAliasDecl |
                CXCursor_TypedefDecl |
                CXCursor_StructDecl |
                CXCursor_UnionDecl |
                CXCursor_ClassTemplate |
                CXCursor_ClassDecl => {
                    // We can find non-semantic children here, clang uses a
                    // StructDecl to note incomplete structs that hasn't been
                    // forward-declared before, see:
                    //
                    // https://github.com/servo/rust-bindgen/issues/482
                    if cur.semantic_parent() != cursor {
                        return CXChildVisit_Continue;
                    }

                    let inner = Item::parse(cur, Some(potential_id), ctx)
                        .expect("Inner ClassDecl");

                    ci.inner_types.push(inner);

                    // A declaration of an union or a struct without name could
                    // also be an unnamed field, unfortunately.
                    if cur.spelling().is_empty() &&
                       cur.kind() != CXCursor_EnumDecl {
                        let ty = cur.cur_type();
                        let offset = cur.offset_of_field().ok();
                        maybe_anonymous_struct_field =
                            Some((inner, ty, offset));
                    }
                }
                CXCursor_PackedAttr => {
                    ci.packed = true;
                }
                CXCursor_TemplateTypeParameter => {
                    // Yes! You can arrive here with an empty template parameter
                    // name! Awesome, isn't it?
                    //
                    // see tests/headers/empty_template_param_name.hpp
                    if cur.spelling().is_empty() {
                        return CXChildVisit_Continue;
                    }

                    let param =
                        Item::named_type(cur.spelling(), potential_id, ctx);
                    ci.template_args.push(param);
                }
                CXCursor_CXXBaseSpecifier => {
                    let is_virtual_base = cur.is_virtual_base();
                    ci.has_vtable |= is_virtual_base;

                    let kind = if is_virtual_base {
                        BaseKind::Virtual
                    } else {
                        BaseKind::Normal
                    };

                    let type_id = Item::from_ty_or_ref(cur.cur_type(),
                                                       Some(cur),
                                                       None,
                                                       ctx);
                    ci.base_members.push(Base {
                        ty: type_id,
                        kind: kind,
                    });
                }
                CXCursor_Constructor |
                CXCursor_Destructor |
                CXCursor_CXXMethod => {
                    let is_virtual = cur.method_is_virtual();
                    let is_static = cur.method_is_static();
                    debug_assert!(!(is_static && is_virtual), "How?");

                    ci.has_destructor |= cur.kind() == CXCursor_Destructor;
                    ci.has_vtable |= is_virtual;

                    // This used to not be here, but then I tried generating
                    // stylo bindings with this (without path filters), and
                    // cried a lot with a method in gfx/Point.h
                    // (ToUnknownPoint), that somehow was causing the same type
                    // to be inserted in the map two times.
                    //
                    // I couldn't make a reduced test case, but anyway...
                    // Methods of template functions not only use to be inlined,
                    // but also instantiated, and we wouldn't be able to call
                    // them, so just bail out.
                    if !ci.template_args.is_empty() {
                        return CXChildVisit_Continue;
                    }

                    // NB: This gets us an owned `Function`, not a
                    // `FunctionSig`.
                    let signature =
                        match Item::parse(cur, Some(potential_id), ctx) {
                            Ok(item) if ctx.resolve_item(item)
                                .kind()
                                .is_function() => item,
                            _ => return CXChildVisit_Continue,
                        };

                    match cur.kind() {
                        CXCursor_Constructor => {
                            ci.constructors.push(signature);
                        }
                        // TODO(emilio): Bind the destructor?
                        CXCursor_Destructor => {}
                        CXCursor_CXXMethod => {
                            let is_const = cur.method_is_const();
                            let method_kind = if is_static {
                                MethodKind::Static
                            } else if is_virtual {
                                MethodKind::Virtual
                            } else {
                                MethodKind::Normal
                            };

                            let method =
                                Method::new(method_kind, signature, is_const);

                            ci.methods.push(method);
                        }
                        _ => unreachable!("How can we see this here?"),
                    }
                }
                CXCursor_NonTypeTemplateParameter => {
                    ci.has_non_type_template_params = true;
                }
                CXCursor_VarDecl => {
                    let linkage = cur.linkage();
                    if linkage != CXLinkage_External &&
                       linkage != CXLinkage_UniqueExternal {
                        return CXChildVisit_Continue;
                    }

                    let visibility = cur.visibility();
                    if visibility != CXVisibility_Default {
                        return CXChildVisit_Continue;
                    }

                    if let Ok(item) = Item::parse(cur,
                                                  Some(potential_id),
                                                  ctx) {
                        ci.inner_vars.push(item);
                    }
                }
                // Intentionally not handled
                CXCursor_CXXAccessSpecifier |
                CXCursor_CXXFinalAttr |
                CXCursor_FunctionTemplate |
                CXCursor_ConversionFunction => {}
                _ => {
                    warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
                          cur.spelling(),
                          cur.kind(),
                          cursor.spelling(),
                          cur.location());
                }
            }
            CXChildVisit_Continue
        });

        if let Some((ty, _, offset)) = maybe_anonymous_struct_field {
            let field = Field::new(None, ty, None, None, None, false, offset);
            ci.fields.push(field);
        }

        Ok(ci)
    }

    fn kind_from_cursor(cursor: &clang::Cursor)
                        -> Result<CompKind, ParseError> {
        use clang_sys::*;
        Ok(match cursor.kind() {
            CXCursor_UnionDecl => CompKind::Union,
            CXCursor_ClassDecl |
            CXCursor_StructDecl => CompKind::Struct,
            CXCursor_CXXBaseSpecifier |
            CXCursor_ClassTemplatePartialSpecialization |
            CXCursor_ClassTemplate => {
                match cursor.template_kind() {
                    CXCursor_UnionDecl => CompKind::Union,
                    _ => CompKind::Struct,
                }
            }
            _ => {
                warn!("Unknown kind for comp type: {:?}", cursor);
                return Err(ParseError::Continue);
            }
        })
    }

    /// Do any of the types that participate in this type's "signature" use the
    /// named type `ty`?
    ///
    /// See also documentation for `ir::Item::signature_contains_named_type`.
    pub fn signature_contains_named_type(&self,
                                         ctx: &BindgenContext,
                                         ty: &Type)
                                         -> bool {
        // We don't generate these, so rather don't make the codegen step to
        // think we got it covered.
        if self.has_non_type_template_params() {
            return false;
        }
        self.template_args.iter().any(|arg| {
            ctx.resolve_type(*arg)
                .signature_contains_named_type(ctx, ty)
        })
    }

    /// Get the set of types that were declared within this compound type
    /// (e.g. nested class definitions).
    pub fn inner_types(&self) -> &[ItemId] {
        &self.inner_types
    }

    /// Get the set of static variables declared within this compound type.
    pub fn inner_vars(&self) -> &[ItemId] {
        &self.inner_vars
    }

    /// Have we found a field with an opaque type that could potentially mess up
    /// the layout of this compound type?
    pub fn found_unknown_attr(&self) -> bool {
        self.found_unknown_attr
    }

    /// Is this compound type packed?
    pub fn packed(&self) -> bool {
        self.packed
    }

    /// Returns whether this type needs an explicit vtable because it has
    /// virtual methods and none of its base classes has already a vtable.
    pub fn needs_explicit_vtable(&self, ctx: &BindgenContext) -> bool {
        self.has_vtable(ctx) &&
        !self.base_members.iter().any(|base| {
            // NB: Ideally, we could rely in all these types being `comp`, and
            // life would be beautiful.
            //
            // Unfortunately, given the way we implement --match-pat, and also
            // that you can inherit from templated types, we need to handle
            // other cases here too.
            ctx.resolve_type(base.ty)
                .canonical_type(ctx)
                .as_comp()
                .map_or(false, |ci| ci.has_vtable(ctx))
        })
    }

    /// Returns true if compound type has been forward declared
    pub fn is_forward_declaration(&self) -> bool {
        self.is_forward_declaration
    }
}

impl TemplateDeclaration for CompInfo {
    fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
        if self.template_args.is_empty() {
            None
        } else {
            Some(self.template_args.clone())
        }
    }
}

impl CanDeriveDebug for CompInfo {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        if self.has_non_type_template_params() {
            return layout.map_or(false, |l| l.opaque().can_derive_debug(ctx, ()));
        }

        // We can reach here recursively via template parameters of a member,
        // for example.
        if self.detect_derive_debug_cycle.get() {
            warn!("Derive debug cycle detected!");
            return true;
        }

        if self.kind == CompKind::Union {
            if ctx.options().unstable_rust {
                return false;
            }

            return layout.unwrap_or_else(Layout::zero)
                .opaque()
                .can_derive_debug(ctx, ());
        }

        self.detect_derive_debug_cycle.set(true);

        let can_derive_debug = {
            self.base_members
                .iter()
                .all(|base| base.ty.can_derive_debug(ctx, ())) &&
            self.template_args
                .iter()
                .all(|id| id.can_derive_debug(ctx, ())) &&
            self.fields
                .iter()
                .all(|f| f.can_derive_debug(ctx, ())) &&
            self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ()))
        };

        self.detect_derive_debug_cycle.set(false);

        can_derive_debug
    }
}

impl CanDeriveDefault for CompInfo {
    type Extra = Option<Layout>;

    fn can_derive_default(&self,
                          ctx: &BindgenContext,
                          layout: Option<Layout>)
                          -> bool {
        // We can reach here recursively via template parameters of a member,
        // for example.
        if self.detect_derive_default_cycle.get() {
            warn!("Derive default cycle detected!");
            return true;
        }

        if self.kind == CompKind::Union {
            if ctx.options().unstable_rust {
                return false;
            }

            return layout.unwrap_or_else(Layout::zero)
                .opaque()
                .can_derive_debug(ctx, ());
        }

        self.detect_derive_default_cycle.set(true);

        let can_derive_default = !self.has_vtable(ctx) &&
                                 !self.needs_explicit_vtable(ctx) &&
                                 self.base_members
            .iter()
            .all(|base| base.ty.can_derive_default(ctx, ())) &&
                                 self.template_args
            .iter()
            .all(|id| id.can_derive_default(ctx, ())) &&
                                 self.fields
            .iter()
            .all(|f| f.can_derive_default(ctx, ())) &&
                                 self.ref_template
            .map_or(true, |id| id.can_derive_default(ctx, ()));

        self.detect_derive_default_cycle.set(false);

        can_derive_default
    }
}

impl<'a> CanDeriveCopy<'a> for CompInfo {
    type Extra = (&'a Item, Option<Layout>);

    fn can_derive_copy(&self,
                       ctx: &BindgenContext,
                       (item, layout): (&Item, Option<Layout>))
                       -> bool {
        if self.has_non_type_template_params() {
            return layout.map_or(false, |l| l.opaque().can_derive_copy(ctx, ()));
        }

        // NOTE: Take into account that while unions in C and C++ are copied by
        // default, the may have an explicit destructor in C++, so we can't
        // defer this check just for the union case.
        if self.has_destructor(ctx) {
            return false;
        }

        if self.kind == CompKind::Union {
            if !ctx.options().unstable_rust {
                // NOTE: If there's no template parameters we can derive copy
                // unconditionally, since arrays are magical for rustc, and
                // __BindgenUnionField always implements copy.
                return true;
            }

            // https://github.com/rust-lang/rust/issues/36640
            if !self.template_args.is_empty() || self.ref_template.is_some() ||
               !item.applicable_template_args(ctx).is_empty() {
                return false;
            }
        }

        // With template args, use a safe subset of the types,
        // since copyability depends on the types itself.
        self.ref_template
            .as_ref()
            .map_or(true, |t| t.can_derive_copy(ctx, ())) &&
        self.base_members
            .iter()
            .all(|base| base.ty.can_derive_copy(ctx, ())) &&
        self.fields.iter().all(|field| field.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self,
                                ctx: &BindgenContext,
                                extra: (&Item, Option<Layout>))
                                -> bool {
        self.can_derive_copy(ctx, extra)
    }
}

impl Trace for CompInfo {
    type Extra = Item;

    fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
        where T: Tracer,
    {
        // TODO: We should properly distinguish template instantiations from
        // template declarations at the type level. Why are some template
        // instantiations represented here instead of as
        // TypeKind::TemplateInstantiation?
        if let Some(template) = self.specialized_template() {
            // This is an instantiation of a template declaration with concrete
            // template type arguments.
            tracer.visit(template);
            let args = item.applicable_template_args(context);
            for a in args {
                tracer.visit(a);
            }
        } else {
            let params = item.applicable_template_args(context);
            // This is a template declaration with abstract template type
            // parameters.
            for p in params {
                tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
            }
        }

        for base in self.base_members() {
            tracer.visit(base.ty);
        }

        for field in self.fields() {
            tracer.visit(field.ty());
        }

        for &ty in self.inner_types() {
            tracer.visit(ty);
        }

        for &var in self.inner_vars() {
            tracer.visit(var);
        }

        for method in self.methods() {
            tracer.visit(method.signature);
        }

        for &ctor in self.constructors() {
            tracer.visit(ctor);
        }
    }
}
