//! Metadata from source code coverage analysis and instrumentation. use rustc_macros::HashStable; use rustc_span::Symbol; use std::fmt::{self, Debug, Formatter}; rustc_index::newtype_index! { #[derive(HashStable)] #[max = 0xFFFF_FFFF] #[debug_format = "CounterValueReference({})"] pub struct CounterValueReference {} } impl CounterValueReference { /// Counters start at 1 for historical reasons. pub const START: Self = Self::from_u32(1); /// Returns explicitly-requested zero-based version of the counter id, used /// during codegen. LLVM expects zero-based indexes. pub fn zero_based_index(self) -> u32 { let one_based_index = self.as_u32(); debug_assert!(one_based_index > 0); one_based_index - 1 } } rustc_index::newtype_index! { /// Values descend from u32::MAX. #[derive(HashStable)] #[max = 0xFFFF_FFFF] #[debug_format = "InjectedExpressionId({})"] pub struct InjectedExpressionId {} } rustc_index::newtype_index! { /// Values ascend from 0. #[derive(HashStable)] #[max = 0xFFFF_FFFF] #[debug_format = "InjectedExpressionIndex({})"] pub struct InjectedExpressionIndex {} } rustc_index::newtype_index! { /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their /// array position in the LLVM coverage map "Expressions" array, which is assembled during the /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s. #[derive(HashStable)] #[max = 0xFFFF_FFFF] #[debug_format = "MappedExpressionIndex({})"] pub struct MappedExpressionIndex {} } /// Operand of a coverage-counter expression. /// /// Operands can be a constant zero value, an actual coverage counter, or another /// expression. Counter/expression operands are referred to by ID. #[derive(Copy, Clone, PartialEq, Eq)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum Operand { Zero, Counter(CounterValueReference), Expression(InjectedExpressionId), } impl Debug for Operand { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Zero => write!(f, "Zero"), Self::Counter(id) => f.debug_tuple("Counter").field(&id.as_u32()).finish(), Self::Expression(id) => f.debug_tuple("Expression").field(&id.as_u32()).finish(), } } } #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum CoverageKind { Counter { function_source_hash: u64, /// ID of this counter within its enclosing function. /// Expressions in the same function can refer to it as an operand. id: CounterValueReference, }, Expression { /// ID of this coverage-counter expression within its enclosing function. /// Other expressions in the same function can refer to it as an operand. id: InjectedExpressionId, lhs: Operand, op: Op, rhs: Operand, }, Unreachable, } impl CoverageKind { pub fn as_operand(&self) -> Operand { use CoverageKind::*; match *self { Counter { id, .. } => Operand::Counter(id), Expression { id, .. } => Operand::Expression(id), Unreachable => bug!("Unreachable coverage cannot be part of an expression"), } } pub fn is_expression(&self) -> bool { matches!(self, Self::Expression { .. }) } } impl Debug for CoverageKind { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use CoverageKind::*; match self { Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), Expression { id, lhs, op, rhs } => write!( fmt, "Expression({:?}) = {:?} {} {:?}", id.index(), lhs, match op { Op::Add => "+", Op::Subtract => "-", }, rhs, ), Unreachable => write!(fmt, "Unreachable"), } } } #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)] #[derive(TypeFoldable, TypeVisitable)] pub struct CodeRegion { pub file_name: Symbol, pub start_line: u32, pub start_col: u32, pub end_line: u32, pub end_col: u32, } impl Debug for CodeRegion { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { write!( fmt, "{}:{}:{} - {}:{}", self.file_name, self.start_line, self.start_col, self.end_line, self.end_col ) } } #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub enum Op { Subtract, Add, } impl Op { pub fn is_add(&self) -> bool { matches!(self, Self::Add) } pub fn is_subtract(&self) -> bool { matches!(self, Self::Subtract) } }