Struct Method

pub struct Method {
Show 24 fields pub rid: u32, pub token: Token, pub meta_offset: usize, pub name: String, pub impl_code_type: MethodImplCodeType, pub impl_management: MethodImplManagement, pub impl_options: MethodImplOptions, pub flags_access: MethodAccessFlags, pub flags_vtable: MethodVtableFlags, pub flags_modifiers: MethodModifiers, pub flags_pinvoke: AtomicU32, pub params: ParamList, pub varargs: Arc<Vec<VarArg>>, pub generic_params: GenericParamList, pub generic_args: MethodSpecList, pub signature: SignatureMethod, pub rva: Option<u32>, pub body: OnceLock<MethodBody>, pub local_vars: Arc<Vec<LocalVariable>>, pub overrides: OnceLock<MethodRef>, pub interface_impls: MethodRefList, pub security: OnceLock<Security>, pub blocks: OnceLock<Vec<BasicBlock>>, pub custom_attributes: CustomAttributeValueList,
}
Expand description

Represents all the information about a CIL method.

The Method struct contains all metadata, code, and analysis results for a single .NET method. It includes method attributes, parameters, generic arguments, IL code, exception handlers, and analysis results.

Fields§

§rid: u32

The row this method has in the MetadataTable

§token: Token

The token of this method

§meta_offset: usize

The offset in the MetadataTable

§name: String

This methods name

§impl_code_type: MethodImplCodeType

MethodImplAttributes, §II.23.1.10

§impl_management: MethodImplManagement

MethodImplAttributes, §II.23.1.10

§impl_options: MethodImplOptions

MethodImplAttributes, §II.23.1.10

§flags_access: MethodAccessFlags

MethodAttributes, §II.23.1.10

§flags_vtable: MethodVtableFlags

MethodAttributes, §II.23.1.10

§flags_modifiers: MethodModifiers

MethodAttributes, §II.23.1.10

§flags_pinvoke: AtomicU32

PInvokeAttributes, §II.23.1.8

§params: ParamList

The parameters (from Param table, enhanced with information from the SignatureMethod) sequence 0, is the return value (if there is a count 0).

§varargs: Arc<Vec<VarArg>>

The vararg parameters of this method

§generic_params: GenericParamList

All generic parameters this type has (type information, not the instantiated version)

§generic_args: MethodSpecList

MethodSpec instances that provide generic instantiations for this method

§signature: SignatureMethod

The signature of this method

§rva: Option<u32>

The RVA of this method

§body: OnceLock<MethodBody>

The MethodBody

§local_vars: Arc<Vec<LocalVariable>>

The local variables

§overrides: OnceLock<MethodRef>

Overridden method if this is an override (from MethodImpl table where MethodBody points to this method)

§interface_impls: MethodRefList

Implemented interface methods (from MethodImpl table entries for this type)

§security: OnceLock<Security>

The .NET CIL Security Information (if present)

§blocks: OnceLock<Vec<BasicBlock>>

The basic blocks of this method, lazily initialized

§custom_attributes: CustomAttributeValueList

Custom attributes attached to this method

Implementations§

§

impl Method

pub fn instructions(&self) -> InstructionIterator<'_>

Returns an iterator over all instructions in this method.

Instructions are yielded in execution order across all basic blocks, providing a linear view of the method’s IL code. This method handles uninitialized state gracefully by returning an empty iterator if blocks haven’t been decoded yet.

The iterator implements efficient traversal without copying instruction data, making it suitable for analysis of large methods. Each instruction maintains its original metadata including RVA, operands, and flow control information.

§Thread Safety

This method is thread-safe and can be called concurrently. If the method hasn’t been disassembled yet, all threads will receive an empty iterator.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter().take(3) {
    let method = entry.value();
    println!("Method: {} ({} instructions)",
             method.name, method.instruction_count());

    for (i, instruction) in method.instructions().enumerate() {
        println!("  [{}] {} {:?}", i, instruction.mnemonic, instruction.operand);
        if i >= 10 { break; } // Limit output for readability
    }
}

pub fn blocks(&self) -> Box<dyn Iterator<Item = (usize, &BasicBlock)> + '_>

Returns an iterator over all basic blocks containing the instructions.

This method provides access to the control flow structure of the method by yielding each basic block along with its sequential index. Basic blocks represent straight-line sequences of instructions with a single entry point and single exit point.

The iterator yields tuples of (block_index, &BasicBlock) where block_index is the zero-based position in the blocks vector. Returns an empty iterator if the method hasn’t been disassembled yet.

§Thread Safety

This method is thread-safe and handles the OnceLock access pattern internally. Multiple threads can safely iterate over blocks simultaneously.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter().take(3) {
    let method = entry.value();
    println!("Method: {} has {} basic blocks",
             method.name, method.block_count());
     
    for (block_index, block) in method.blocks() {
        println!("  Block {}: RVA 0x{:X}, {} instructions, {} exceptions",
                block_index, block.rva, block.instructions.len(), block.exceptions.len());
         
        // Show control flow information
        if !block.instructions.is_empty() {
            let last_instr = &block.instructions[block.instructions.len() - 1];
            println!("    Ends with: {} (flow: {:?})",
                    last_instr.mnemonic, last_instr.flow_type);
        }
    }
}
§Control Flow Analysis

Each basic block contains:

  • Sequential instructions with no internal jumps
  • Exception handler associations
  • RVA and offset information for debugging
  • Flow control termination (branch, return, throw, etc.)

pub fn block_count(&self) -> usize

Returns the number of basic blocks in this method.

This provides an efficient way to get the block count without iterating through all blocks. Returns 0 if the method hasn’t been disassembled yet or contains no executable code.

§Thread Safety

This method is thread-safe and handles the OnceLock access pattern internally.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter().take(10) {
    let method = entry.value();
    let block_count = method.block_count();
    let instr_count = method.instruction_count();
     
    println!("Method: {} - {} blocks, {} instructions (avg {:.1} instr/block)",
             method.name, block_count, instr_count,
             if block_count > 0 { instr_count as f64 / block_count as f64 } else { 0.0 });
}

pub fn instruction_count(&self) -> usize

Returns the total number of instructions across all basic blocks.

This method efficiently calculates the total instruction count by summing the length of instruction vectors in each basic block. This is more efficient than calling method.instructions().count() as it avoids creating and consuming the iterator.

Returns 0 if the method hasn’t been disassembled yet or contains no executable code.

§Thread Safety

This method is thread-safe and handles the OnceLock access pattern internally.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let mut total_instructions = 0;
let mut method_count = 0;

for entry in assembly.methods().iter() {
    let method = entry.value();
    let count = method.instruction_count();
    total_instructions += count;
    method_count += 1;
     
    if count > 100 {
        println!("Large method: {} with {} instructions", method.name, count);
    }
}

println!("Assembly has {} methods with {} total instructions",
         method_count, total_instructions);

pub fn is_code_il(&self) -> bool

Returns true if the method has IL code.

This checks the MethodImplCodeType::IL flag in the method’s implementation attributes to determine if the method contains Common Intermediate Language (CIL) instructions that can be disassembled and analyzed.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter().take(10) {
    let method = entry.value();
    if method.is_code_il() {
        println!("Method '{}' contains IL code", method.name);
    }
}

pub fn is_code_native(&self) -> bool

Returns true if the method has native code (P/Invoke).

This checks the MethodImplCodeType::NATIVE flag to determine if the method is implemented in native code rather than IL. This is typical for P/Invoke methods that call into unmanaged libraries.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let native_methods: Vec<_> = assembly.methods().iter()
    .filter(|entry| entry.value().is_code_native())
    .map(|entry| entry.value().name.clone())
    .collect();

println!("Found {} native methods", native_methods.len());

pub fn is_code_opt_il(&self) -> bool

Returns true if the method has optimized IL code.

This checks the MethodImplCodeType::OPTIL flag to determine if the method contains optimized Common Intermediate Language that may have been transformed by the runtime or tools for better performance.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter() {
    let method = entry.value();
    if method.is_code_opt_il() {
        println!("Method '{}' has optimized IL code", method.name);
    }
}

pub fn is_code_runtime(&self) -> bool

Returns true if the method is implemented in the runtime.

This checks the MethodImplCodeType::RUNTIME flag to determine if the method is implemented directly by the .NET runtime rather than containing user code. This is common for intrinsic methods and runtime-provided functionality.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let runtime_methods: Vec<_> = assembly.methods().iter()
    .filter(|entry| entry.value().is_code_runtime())
    .map(|entry| entry.value().name.clone())
    .collect();

println!("Found {} runtime-implemented methods", runtime_methods.len());

pub fn is_code_unmanaged(&self) -> bool

Returns true if the method is unmanaged.

This checks the MethodImplManagement::UNMANAGED flag to determine if the method runs outside the managed execution environment, typically for P/Invoke methods or COM interop scenarios.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter() {
    let method = entry.value();
    if method.is_code_unmanaged() {
        println!("Unmanaged method: {}", method.name);
    }
}

pub fn is_forward_ref(&self) -> bool

Returns true if the method is a forward reference (used in merge scenarios).

This checks the MethodImplOptions::FORWARD_REF flag to determine if the method is declared but not yet defined, which can occur during incremental compilation or when working with incomplete assemblies.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let forward_refs: Vec<_> = assembly.methods().iter()
    .filter(|entry| entry.value().is_forward_ref())
    .map(|entry| entry.value().name.clone())
    .collect();

if !forward_refs.is_empty() {
    println!("Found {} forward reference methods", forward_refs.len());
}

pub fn is_synchronized(&self) -> bool

Returns true if the method is synchronized.

This checks the MethodImplOptions::SYNCHRONIZED flag to determine if the method automatically acquires a lock before execution, providing thread-safe access to the method body. This is equivalent to marking a method with the synchronized keyword in some languages.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter() {
    let method = entry.value();
    if method.is_synchronized() {
        println!("Synchronized method: {}", method.name);
    }
}

pub fn is_pinvoke(&self) -> bool

Returns true if the method preserves signature for P/Invoke.

This checks the MethodImplOptions::PRESERVE_SIG flag to determine if the method signature should be preserved exactly as declared when calling into unmanaged code, rather than applying standard .NET marshalling transformations.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter() {
    let method = entry.value();
    if method.is_pinvoke() {
        println!("P/Invoke method with preserved signature: {}", method.name);
    }
}

pub fn is_internal_call(&self) -> bool

Returns true if the method is an internal call.

This checks the MethodImplOptions::INTERNAL_CALL flag to determine if the method is implemented internally by the runtime with special handling for parameter type checking and validation.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let internal_methods: Vec<_> = assembly.methods().iter()
    .filter(|entry| entry.value().is_internal_call())
    .map(|entry| entry.value().name.clone())
    .collect();

println!("Found {} internal call methods", internal_methods.len());

pub fn is_forarded_pinvoke(&self) -> bool

Returns true if the method implementation is forwarded through P/Invoke.

This checks the MethodImplOptions::MAX_METHOD_IMPL_VAL flag to determine if the method implementation is forwarded to an external library through the Platform Invoke (P/Invoke) mechanism.

§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for entry in assembly.methods().iter() {
    let method = entry.value();
    if method.is_forarded_pinvoke() {
        println!("Forwarded P/Invoke method: {}", method.name);
    }
}

pub fn is_constructor(&self) -> bool

Returns true if the method is a constructor (.ctor or .cctor).

pub fn parse( &self, file: &File, blobs: &Blob<'_>, sigs: &MetadataTable<'_, StandAloneSigRaw>, types: &Arc<TypeRegistry>, shared_visited: Arc<VisitedMap>, ) -> Result<()>

Parse provided data, and extract additional information from the binary. e.g. Disassembly, method body, local variables, exception handlers, etc.

§Arguments
  • file - The input file
  • blobs - The processed Blobs
  • sigs - The table of signatures
  • types - The type registry
§Errors

Returns an error if parsing fails or if referenced types/signatures cannot be resolved.

Auto Trait Implementations§

§

impl !Freeze for Method

§

impl RefUnwindSafe for Method

§

impl Send for Method

§

impl Sync for Method

§

impl Unpin for Method

§

impl UnwindSafe for Method

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> 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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> 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<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> Same for T

Source§

type Output = T

Should always be Self
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.