1 //! Metadata from source code coverage analysis and instrumentation.
3 use rustc_macros::HashStable;
4 use rustc_span::Symbol;
7 use std::fmt::{self, Debug, Formatter};
9 rustc_index::newtype_index! {
10 /// An ExpressionOperandId value is assigned directly from either a
11 /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
12 /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
13 /// constant value of `0`.
14 pub struct ExpressionOperandId {
16 DEBUG_FORMAT = "ExpressionOperandId({})",
21 impl ExpressionOperandId {
22 /// An expression operand for a "zero counter", as described in the following references:
24 /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
25 /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
26 /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
28 /// This operand can be used to count two or more separate code regions with a single counter,
29 /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
30 /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
31 /// the coverage map for the other code regions.
32 pub const ZERO: Self = Self::from_u32(0);
35 rustc_index::newtype_index! {
36 pub struct CounterValueReference {
38 DEBUG_FORMAT = "CounterValueReference({})",
43 impl CounterValueReference {
44 /// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
45 pub const START: Self = Self::from_u32(1);
47 /// Returns explicitly-requested zero-based version of the counter id, used
48 /// during codegen. LLVM expects zero-based indexes.
49 pub fn zero_based_index(self) -> u32 {
50 let one_based_index = self.as_u32();
51 debug_assert!(one_based_index > 0);
56 rustc_index::newtype_index! {
57 /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
59 /// Values descend from u32::MAX.
60 pub struct InjectedExpressionId {
62 DEBUG_FORMAT = "InjectedExpressionId({})",
67 rustc_index::newtype_index! {
68 /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
70 /// Values ascend from 0.
71 pub struct InjectedExpressionIndex {
73 DEBUG_FORMAT = "InjectedExpressionIndex({})",
78 rustc_index::newtype_index! {
79 /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
80 /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
81 /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
82 pub struct MappedExpressionIndex {
84 DEBUG_FORMAT = "MappedExpressionIndex({})",
89 impl From<CounterValueReference> for ExpressionOperandId {
91 fn from(v: CounterValueReference) -> ExpressionOperandId {
92 ExpressionOperandId::from(v.as_u32())
96 impl From<InjectedExpressionId> for ExpressionOperandId {
98 fn from(v: InjectedExpressionId) -> ExpressionOperandId {
99 ExpressionOperandId::from(v.as_u32())
103 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
104 pub enum CoverageKind {
106 function_source_hash: u64,
107 id: CounterValueReference,
110 id: InjectedExpressionId,
111 lhs: ExpressionOperandId,
113 rhs: ExpressionOperandId,
119 pub fn as_operand_id(&self) -> ExpressionOperandId {
122 Counter { id, .. } => ExpressionOperandId::from(id),
123 Expression { id, .. } => ExpressionOperandId::from(id),
124 Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
128 pub fn is_expression(&self) -> bool {
129 matches!(self, Self::Expression { .. })
133 impl Debug for CoverageKind {
134 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
137 Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
138 Expression { id, lhs, op, rhs } => write!(
140 "Expression({:?}) = {} {} {}",
143 if *op == Op::Add { "+" } else { "-" },
146 Unreachable => write!(fmt, "Unreachable"),
151 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
152 #[derive(TypeFoldable, TypeVisitable)]
153 pub struct CodeRegion {
154 pub file_name: Symbol,
161 impl Debug for CodeRegion {
162 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
166 self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
171 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
172 #[derive(TypeFoldable, TypeVisitable)]
179 pub fn is_add(&self) -> bool {
180 matches!(self, Self::Add)
183 pub fn is_subtract(&self) -> bool {
184 matches!(self, Self::Subtract)