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: u32The row this method has in the MetadataTable
token: TokenThe token of this method
meta_offset: usizeThe offset in the MetadataTable
name: StringThis methods name
impl_code_type: MethodImplCodeTypeMethodImplAttributes, §II.23.1.10
impl_management: MethodImplManagementMethodImplAttributes, §II.23.1.10
impl_options: MethodImplOptionsMethodImplAttributes, §II.23.1.10
flags_access: MethodAccessFlagsMethodAttributes, §II.23.1.10
flags_vtable: MethodVtableFlagsMethodAttributes, §II.23.1.10
flags_modifiers: MethodModifiersMethodAttributes, §II.23.1.10
flags_pinvoke: AtomicU32PInvokeAttributes, §II.23.1.8
params: ParamListThe 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: GenericParamListAll generic parameters this type has (type information, not the instantiated version)
generic_args: MethodSpecListMethodSpec instances that provide generic instantiations for this method
signature: SignatureMethodThe 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: MethodRefListImplemented 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: CustomAttributeValueListCustom attributes attached to this method
Implementations§
§impl Method
impl Method
pub fn instructions(&self) -> InstructionIterator<'_> ⓘ
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)> + '_>
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
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
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
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
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
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
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
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
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
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
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
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
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
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<()>
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 fileblobs- The processed Blobssigs- The table of signaturestypes- 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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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