Skip to main content

CilType

Struct CilType 

pub struct CilType {
Show 20 fields pub token: Token, pub namespace: String, pub name: String, pub flags: TypeAttributes, pub fields: FieldList, pub methods: MethodRefList, pub properties: PropertyList, pub events: EventList, pub interfaces: InterfaceEntryList, pub overwrites: Arc<Vec<CilTypeReference>>, pub nested_types: CilTypeRefList, pub generic_params: GenericParamList, pub generic_args: MethodSpecList, pub custom_attributes: CustomAttributeValueList, pub packing_size: OnceLock<u16>, pub class_size: OnceLock<u32>, pub spec: OnceLock<CilFlavor>, pub modifiers: Arc<Vec<CilModifier>>, pub security: OnceLock<Security>, pub enclosing_type: OnceLock<CilTypeRef>, /* private fields */
}
Expand description

Represents a unified type definition combining information from TypeDef, TypeRef, and TypeSpec tables.

CilType provides a complete representation of a .NET type, merging metadata from multiple tables into a single coherent structure. This eliminates the need to navigate between different metadata tables during type analysis and provides a more convenient API.

The token field indicates the source table:

  • TypeDef tokens for types defined in the current assembly
  • TypeRef tokens for types referenced from other assemblies
  • TypeSpec tokens for generic instantiations and complex type signatures
  • Artificial tokens for runtime primitive types

§Thread Safety

CilType is designed for concurrent access with interior mutability using OnceLock for lazily computed fields. Most fields are immutable after construction, while computed properties like flavor and base are thread-safely cached.

§Examples

Basic type information access is available through the type registry. Complex iteration patterns may require understanding the current iterator implementation.

Fields§

§token: Token

Metadata token identifying this type (TypeDef, TypeRef, TypeSpec, or artificial)

§namespace: String

Type namespace (empty for global types and some special cases like <Module>)

§name: String

Type name (class name, interface name, etc.)

§flags: TypeAttributes

Type attributes flags (ECMA-335 §II.23.1.15).

§fields: FieldList

All fields defined in this type

§methods: MethodRefList

All methods defined in this type (constructors, instance methods, static methods)

§properties: PropertyList

All properties defined in this type

§events: EventList

All events defined in this type

§interfaces: InterfaceEntryList

All interfaces this type implements (from InterfaceImpl table)

§overwrites: Arc<Vec<CilTypeReference>>

All method overwrites this type implements (explicit interface implementations)

§nested_types: CilTypeRefList

Nested types contained within this type (inner classes, delegates, etc.)

§generic_params: GenericParamList

Generic parameters for this type definition (e.g., T, U in Class<T, U>)

§generic_args: MethodSpecList

Generic arguments for instantiated generic types (actual types substituted for parameters)

§custom_attributes: CustomAttributeValueList

Custom attributes applied to this type (annotations, decorators)

§packing_size: OnceLock<u16>

Field layout packing size - alignment of fields in memory (from ClassLayout table)

§class_size: OnceLock<u32>

Total size of the class in bytes (from ClassLayout table)

§spec: OnceLock<CilFlavor>

TypeSpec specifiers providing additional type information for complex types

§modifiers: Arc<Vec<CilModifier>>

Type modifiers from TypeSpec (required/optional modifiers, pinned types, etc.)

§security: OnceLock<Security>

Security declarations and permissions associated with this type

§enclosing_type: OnceLock<CilTypeRef>

Enclosing type for nested types - used for reverse lookup to build hierarchical names

Implementations§

§

impl CilType

pub fn new( token: Token, namespace: String, name: String, external: Option<CilTypeReference>, base: Option<CilTypeRef>, flags: TypeAttributes, fields: FieldList, methods: MethodRefList, flavor: Option<CilFlavor>, ) -> Self

Create a new instance of a CilType.

Creates a new type representation with the provided metadata. Some fields like properties, events, interfaces, etc. are initialized as empty collections and can be populated later during metadata loading.

§Arguments
  • token - The metadata token for this type
  • namespace - The namespace of the type (can be empty for global types)
  • name - The name of the type
  • external - External type reference if this is an imported type
  • base - Base type reference if this type inherits from another (optional)
  • flags - Type attributes flags from TypeAttributes
  • fields - Fields belonging to this type
  • methods - Methods belonging to this type
  • flavor - Optional explicit flavor. If None, flavor will be computed lazily
§Thread Safety

The returned CilType is safe for concurrent access. Lazily computed fields like flavor and base use OnceLock for thread-safe initialization.

§Examples
use dotscope::metadata::{
    tables::TypeAttributes,
    typesystem::{CilType, CilFlavor},
    token::Token,
};
use std::sync::Arc;

let cil_type = CilType::new(
    Token::new(0x02000001), // TypeDef token
    "MyNamespace".to_string(),
    "MyClass".to_string(),
    None, // Not an external type
    None, // No base type specified yet
    TypeAttributes::new(0x00100001), // TypeAttributes flags
    Arc::new(boxcar::Vec::new()), // Empty fields list
    Arc::new(boxcar::Vec::new()), // Empty methods list
    Some(CilFlavor::Class), // Explicit class flavor
);

pub fn set_base(&self, base_type: &CilTypeRef) -> Result<()>

Set the base type of this type for inheritance relationships.

This method allows setting the base type after the CilType has been created, which is useful during metadata loading when type references may not be fully resolved at construction time.

§Arguments
  • base_type - The base type this type inherits from
§Returns
  • Ok(()) if the base type was set successfully
  • Err(base_type) if a base type was already set for this type
§Errors

This function will return an error if a base type was already set for this type. The error contains the base type that was attempted to be set.

§Thread Safety

This method is thread-safe and can be called concurrently. Only the first call will succeed in setting the base type.

§Examples
use dotscope::metadata::typesystem::{CilType, CilTypeRef};
use std::sync::{Arc, Weak};

let base_ref = CilTypeRef::new(&base_type);
match cil_type.set_base(base_ref) {
    Ok(()) => println!("Base type set successfully"),
    Err(_) => println!("Base type was already set"),
}

pub fn base(&self) -> Option<CilTypeRc>

Access the base type of this type, if it exists.

Returns the base type that this type inherits from, if one has been set. For classes, this is typically another class or System.Object. For value types, this is usually System.ValueType or System.Enum.

§Returns
  • Some(CilTypeRc) - The base type if one is set and the reference is still valid
  • None - If no base type is set or the reference has been dropped
§Thread Safety

This method is thread-safe and can be called concurrently.

§Examples
if let Some(base) = cil_type.base() {
    println!("Base type: {}.{}", base.namespace, base.name);
} else {
    println!("No base type (likely System.Object or interface)");
}

pub fn set_enclosing_type(&self, enclosing_type: &CilTypeRef) -> Result<()>

Set the enclosing type for nested types.

This method allows setting the enclosing type for nested types, establishing the bidirectional relationship between nested and enclosing types. This is used to build proper hierarchical names with “/” separators like the .NET runtime.

§Arguments
  • enclosing_type - The enclosing type that contains this nested type
§Returns
  • Ok(()) if the enclosing type was set successfully or an equivalent type was already set
  • Err(_) if a different enclosing type was already set for this type
§Errors

Returns an error if an enclosing type was already set with a different value.

§Thread Safety

This method is thread-safe and can be called concurrently. Only the first call will succeed in setting the enclosing type; subsequent calls with the same or equivalent enclosing type will succeed, while calls with a different enclosing type will return an error.

pub fn enclosing_type(&self) -> Option<CilTypeRc>

Access the enclosing type for nested types, if it exists.

Returns the enclosing type that contains this nested type, if one has been set. This is used to traverse up the type hierarchy for building hierarchical names.

§Returns
  • Some(CilTypeRc) - The enclosing type if one is set and the reference is still valid
  • None - If this is not a nested type or the reference has been dropped
§Thread Safety

This method is thread-safe and can be called concurrently.

pub fn set_external(&self, external_ref: &CilTypeReference) -> Result<()>

Sets the external type reference for this type.

This method sets the external reference that indicates where this type is defined (e.g., which assembly, module, or file). This is primarily used for TypeRef entries that reference types defined outside the current assembly.

§Arguments
  • external_ref - The external type reference indicating where this type is defined
§Returns
  • Ok(()) - External reference set successfully
  • Err(_) - External reference was already set or other error occurred
§Errors

Returns an error if the external reference was already set.

§Thread Safety

This method is thread-safe and can be called concurrently. Only the first call will succeed in setting the external reference.

pub fn external(&self) -> Option<&CilTypeReference>

Gets the external type reference for this type, if it exists.

Returns the external reference that indicates where this type is defined, or None if this is a type defined in the current assembly or if no external reference has been set.

§Returns

Returns the external reference if it has been set, or None if it’s still pending resolution.

pub fn flavor(&self) -> &CilFlavor

Get the computed type flavor - determined lazily from context.

The flavor represents the fundamental nature of the type (class, interface, value type, etc.) and is computed from type attributes, inheritance relationships, and naming patterns. The result is cached for performance.

§Returns

A reference to the computed CilFlavor for this type

§Thread Safety

This method is thread-safe. The flavor is computed once and cached using OnceLock for subsequent calls.

§Examples
use dotscope::metadata::typesystem::{CilType, CilFlavor};

match cil_type.flavor() {
    CilFlavor::Class => println!("Reference type class"),
    CilFlavor::ValueType => println!("Value type (struct/enum)"),
    CilFlavor::Interface => println!("Interface definition"),
    _ => println!("Other type flavor"),
}

pub fn is_public(&self) -> bool

Returns true if this type is publicly visible.

A type is considered public if it has Public visibility (for top-level types) or NestedPublic visibility (for nested types).

§Examples
if cil_type.is_public() {
    println!("Type {} is publicly accessible", cil_type.name);
}

pub fn is_internal(&self) -> bool

Returns true if this type has internal/assembly-only visibility.

Returns true for:

  • Top-level types with NotPublic visibility (internal to assembly)
  • Nested types with NestedAssembly visibility

pub fn is_interface(&self) -> bool

Returns true if this type is an interface.

Checks if the type’s flavor is CilFlavor::Interface.

pub fn is_class(&self) -> bool

Returns true if this type is a class.

Checks if the type’s flavor is CilFlavor::Class.

pub fn is_value_type(&self) -> bool

Returns true if this type is a value type (struct, enum, or primitive value type).

pub fn is_sealed(&self) -> bool

Returns true if this type is sealed (cannot be inherited from).

pub fn is_abstract(&self) -> bool

Returns true if this type is abstract (cannot be instantiated directly).

pub fn is_enum(&self) -> bool

Returns true if this type is an enum (inherits from System.Enum).

pub fn is_delegate(&self) -> bool

Returns true if this type is a delegate (inherits from System.Delegate or System.MulticastDelegate).

pub fn query_methods(&self) -> MethodQuery<'_>

Returns a composable query over methods defined in this type.

This handles the weak-ref upgrade boilerplate automatically, replacing the common pattern:

for (_, method_ref) in type_info.methods.iter() {
    if let Some(method) = method_ref.upgrade() { ... }
}

pub fn query_fields(&self) -> FieldQuery<'_>

Returns a composable query over fields defined in this type.

This provides a fluent API mirroring query_methods():

let static_fields = type_info.query_fields().static_fields().find_all();
let value_field = type_info.query_fields().instance_fields().name("value__").find_first();

pub fn cctor(&self) -> Option<Token>

Returns the .cctor (class constructor / type initializer) token, if present.

pub fn ctor(&self) -> Option<Token>

Returns the first .ctor (instance constructor) token, if present.

pub fn is_module_type(&self) -> bool

Returns true if this is the global <Module> type.

pub fn methods(&self) -> impl Iterator<Item = MethodRc> + '_

Returns an iterator over all methods defined in this type.

Automatically upgrades weak references, skipping any that have been dropped.

pub fn fields(&self) -> impl Iterator<Item = &FieldRc> + '_

Returns an iterator over all fields defined in this type.

Returns references to the field entries in the field list.

pub fn is_nested_internal(&self) -> bool

Returns true if this is a nested type with private or internal visibility.

This includes:

  • NestedPrivate - Only accessible within the declaring type
  • NestedAssembly - Only accessible within the same assembly
  • NestedFamANDAssem - Only accessible to derived types within the same assembly

Useful for detecting obfuscation infrastructure types that are intentionally hidden.

pub fn has_public_methods(&self) -> bool

Returns true if any method in this type has public access.

Iterates through all methods declared by this type and checks if any have Public accessibility.

pub fn has_public_fields(&self) -> bool

Returns true if any field in this type has public access.

Iterates through all fields declared by this type and checks if any have Public accessibility (flag value 0x06).

pub fn find_method(&self, name: &str) -> Option<MethodRc>

Finds the first method with the given name declared by this type.

Searches through the type’s method list, upgrading weak references and comparing names. Returns None if no method matches or if all matching weak references have been dropped.

pub fn find_methods(&self, name: &str) -> Vec<MethodRc>

Finds all methods with the given name declared by this type.

Returns all matching methods, useful for finding overloaded methods.

pub fn fullname(&self) -> String

Returns the full name (Namespace.Name) of the type.

Combines the namespace and name to create a fully qualified type name, which is useful for type lookup and identification. For nested types, uses “/” separators as per .NET runtime convention.

§Returns

A string containing the full name in the format:

  • "Namespace.Name" for top-level types
  • "Namespace.Outer/Inner" for nested types
§Caching

The result is cached after first computation for performance.

pub fn is_typeref(&self) -> bool

Checks if this type was created from a TypeRef table entry.

Returns true if this type’s token indicates it originated from a TypeRef table, meaning it references a type defined in an external assembly. This is essential for TypeRef to TypeDef resolution during multi-assembly loading.

§Returns
  • true - If the type’s token has table ID 0x01 (TypeRef)
  • false - If the type came from TypeDef (0x02), TypeSpec (0x1B), or other sources
§Examples
use dotscope::metadata::typesystem::CilType;
use dotscope::metadata::token::Token;

if type_def.is_typeref() {
    println!("Type {} needs TypeRef resolution", type_def.fullname());
}

pub fn is_compatible_with(&self, target: &CilType) -> bool

Check if this type is compatible with (assignable to) another type

This implements .NET type compatibility rules including:

  • Exact type matching
  • Inheritance compatibility
  • Interface implementation
  • Primitive type widening
  • Reference type to System.Object
§Arguments
  • target - The target type to check compatibility against
§Returns

true if this type can be assigned to the target type

pub fn accepts_constant(&self, constant: &CilPrimitive) -> bool

Check if a constant value is compatible with this type

§Arguments
  • constant - The constant primitive value to check
§Returns

true if the constant can be assigned to this type

pub fn is_structurally_equivalent(&self, other: &CilType) -> bool

Performs deep structural comparison with another type for deduplication purposes

This method compares all structural aspects of types to determine true equivalence, including generic arguments, base types, and source information. This is the authoritative method for determining if two types are semantically identical.

§Arguments
  • other - The other type to compare with
§Returns

true if the types are structurally equivalent and can be deduplicated

pub fn external_sources_equivalent(&self, other: &CilType) -> bool

Compare external source references for equivalence.

Determines if two types originate from the same assembly by comparing their external source references (AssemblyRef, ModuleRef, File, etc.).

§Returns
  • true if types are from the same assembly or indeterminate (conservative)
  • false if types are definitively from different assemblies
§Examples

Types from the same assembly will return true, while types from different assemblies (different AssemblyRef) will return false.

pub fn is_array_of(&self, base_fullname: &str) -> bool

Check if this type has an array relationship with the given base type.

Returns true if this type is an array type (ends with “[]”) and the base type matches the array’s element type. This handles nested types correctly by checking both direct name matches and nested type patterns.

§Arguments
  • base_fullname - The full name of the potential base type to check against. Must be a non-empty, valid type name.
§Returns
  • true - If this type is an array of the specified base type
  • false - If this is not an array type, the base name is empty, or there’s no match
§Examples
  • MyClass[] is an array of MyClass
  • AdjustmentRule[] is an array of TimeZoneInfo/AdjustmentRule

pub fn is_pointer_to(&self, base_fullname: &str) -> bool

Check if this type has a pointer relationship with the given base type.

Returns true if this type is a pointer type (ends with “*”) and the base type matches the pointer’s target type. This handles nested types correctly by checking both direct name matches and nested type patterns.

§Arguments
  • base_fullname - The full name of the potential target type to check against. Must be a non-empty, valid type name.
§Returns
  • true - If this type is a pointer to the specified base type
  • false - If this is not a pointer type, the base name is empty, or there’s no match
§Examples
  • EventData* is a pointer to EventData
  • MyStruct* is a pointer to OuterClass/MyStruct

pub fn is_generic_of(&self, base_fullname: &str) -> bool

Check if this type represents a generic relationship with the base type.

Returns true if either type has generic parameters (contains ‘`’) and they share a common base name, indicating a generic instantiation relationship.

§Arguments
  • base_fullname - The full name of the potential generic base type to check against. Must be a non-empty, valid type name.
§Returns
  • true - If the types share a generic relationship
  • false - If there’s no generic relationship, or the base name is empty
§Examples
  • List<int> has a generic relationship with List<T>
  • Dictionary<string, int> has a generic relationship with Dictionary<K, V>

Trait Implementations§

§

impl Display for CilType

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AsAny for T
where T: Any,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Source§

fn type_name(&self) -> &'static str

Gets the type name of self
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: AsAny + ?Sized,

Source§

fn is<T>(&self) -> bool
where T: AsAny,

Returns true if the boxed type is the same as T. Read more
Source§

fn downcast_ref<T>(&self) -> Option<&T>
where T: AsAny,

Forward to the method defined on the type Any.
Source§

fn downcast_mut<T>(&mut self) -> Option<&mut T>
where T: AsAny,

Forward to the method defined on the type Any.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, A> IntoAst<A> for T
where T: Into<A>, A: Ast,

Source§

fn into_ast(self, _a: &A) -> A

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToCompactString for T
where T: Display,

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more