use analyssa::ir::exception::SsaExceptionHandler as AnalyssaSsaExceptionHandler;
use crate::{
analysis::ssa::target::CilTarget,
metadata::{
method::{ExceptionHandler, ExceptionHandlerFlags},
token::Token,
},
};
pub type SsaExceptionHandler<T = CilTarget> = AnalyssaSsaExceptionHandler<T>;
#[must_use]
pub fn from_exception_handler(handler: &ExceptionHandler) -> SsaExceptionHandler {
let class_token_or_filter = if handler.flags == ExceptionHandlerFlags::EXCEPTION {
handler
.handler
.as_ref()
.map_or(handler.filter_offset, |t| t.token.value())
} else {
handler.filter_offset
};
SsaExceptionHandler {
flags: handler.flags,
try_offset: handler.try_offset,
try_length: handler.try_length,
handler_offset: handler.handler_offset,
handler_length: handler.handler_length,
class_token_or_filter,
try_start_block: None,
try_end_block: None,
handler_start_block: None,
handler_end_block: None,
filter_start_block: None,
}
}
pub trait SsaExceptionHandlerCilExt {
fn class_token(&self) -> Option<Token>;
}
impl SsaExceptionHandlerCilExt for AnalyssaSsaExceptionHandler<CilTarget> {
fn class_token(&self) -> Option<Token> {
if self.flags == ExceptionHandlerFlags::EXCEPTION {
Some(Token::new(self.class_token_or_filter))
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use crate::metadata::method::ExceptionHandlerFlags;
use super::*;
type SsaExceptionHandler = super::SsaExceptionHandler<CilTarget>;
#[test]
fn test_remap_block_indices_basic() {
let mut handler = SsaExceptionHandler {
flags: ExceptionHandlerFlags::EXCEPTION,
try_offset: 0,
try_length: 10,
handler_offset: 10,
handler_length: 5,
class_token_or_filter: 0x01000001,
try_start_block: Some(0),
try_end_block: Some(2),
handler_start_block: Some(3),
handler_end_block: Some(4),
filter_start_block: None,
};
let block_remap = vec![Some(0), None, Some(1), Some(2), Some(3)];
handler.remap_block_indices(&block_remap);
assert_eq!(handler.try_start_block, Some(0)); assert_eq!(handler.try_end_block, Some(1)); assert_eq!(handler.handler_start_block, Some(2)); assert_eq!(handler.handler_end_block, Some(3)); }
#[test]
fn test_remap_block_indices_removed_block() {
let mut handler = SsaExceptionHandler {
flags: ExceptionHandlerFlags::EXCEPTION,
try_offset: 0,
try_length: 10,
handler_offset: 10,
handler_length: 5,
class_token_or_filter: 0x01000001,
try_start_block: Some(1), try_end_block: Some(2),
handler_start_block: Some(3),
handler_end_block: None,
filter_start_block: None,
};
let block_remap = vec![Some(0), None, Some(1), Some(2)];
handler.remap_block_indices(&block_remap);
assert_eq!(handler.try_start_block, None); assert_eq!(handler.try_end_block, Some(1)); assert_eq!(handler.handler_start_block, Some(2)); }
#[test]
fn test_remap_block_indices_filter_handler() {
let mut handler = SsaExceptionHandler {
flags: ExceptionHandlerFlags::FILTER,
try_offset: 0,
try_length: 10,
handler_offset: 15,
handler_length: 5,
class_token_or_filter: 10, try_start_block: Some(0),
try_end_block: Some(1),
handler_start_block: Some(3),
handler_end_block: Some(4),
filter_start_block: Some(2), };
let block_remap = vec![Some(0), Some(1), Some(2), Some(3), Some(4)];
handler.remap_block_indices(&block_remap);
assert_eq!(handler.try_start_block, Some(0));
assert_eq!(handler.filter_start_block, Some(2));
assert_eq!(handler.handler_start_block, Some(3));
}
#[test]
fn test_remap_end_block_finds_next_surviving() {
let mut handler = SsaExceptionHandler {
flags: ExceptionHandlerFlags::EXCEPTION,
try_offset: 0,
try_length: 10,
handler_offset: 10,
handler_length: 5,
class_token_or_filter: 0x01000001,
try_start_block: Some(0),
try_end_block: Some(2), handler_start_block: Some(3),
handler_end_block: Some(5), filter_start_block: None,
};
let block_remap = vec![Some(0), None, None, Some(1), None, None, Some(3)];
handler.remap_block_indices(&block_remap);
assert_eq!(handler.try_start_block, Some(0));
assert_eq!(handler.try_end_block, Some(1)); assert_eq!(handler.handler_start_block, Some(1));
assert_eq!(handler.handler_end_block, Some(3)); }
#[test]
fn test_remap_end_block_none_when_no_surviving() {
let mut handler = SsaExceptionHandler {
flags: ExceptionHandlerFlags::EXCEPTION,
try_offset: 0,
try_length: 10,
handler_offset: 10,
handler_length: 5,
class_token_or_filter: 0x01000001,
try_start_block: Some(0),
try_end_block: Some(1),
handler_start_block: Some(2),
handler_end_block: Some(3), filter_start_block: None,
};
let block_remap = vec![Some(0), Some(1), Some(2), None];
handler.remap_block_indices(&block_remap);
assert_eq!(handler.handler_end_block, None); }
}