1 //! Metadata from source code coverage analysis and instrumentation.
3 use rustc_macros::HashStable;
4 use rustc_span::Symbol;
6 use std::fmt::{self, Debug, Formatter};
8 rustc_index::newtype_index! {
9 /// An ExpressionOperandId value is assigned directly from either a
10 /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
11 /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
12 /// constant value of `0`.
15 #[debug_format = "ExpressionOperandId({})"]
16 pub struct ExpressionOperandId {
20 impl ExpressionOperandId {
21 /// An expression operand for a "zero counter", as described in the following references:
23 /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
24 /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
25 /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
27 /// This operand can be used to count two or more separate code regions with a single counter,
28 /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
29 /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
30 /// the coverage map for the other code regions.
31 pub const ZERO: Self = Self::from_u32(0);
34 rustc_index::newtype_index! {
37 #[debug_format = "CounterValueReference({})"]
38 pub struct CounterValueReference {}
41 impl CounterValueReference {
42 /// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
43 pub const START: Self = Self::from_u32(1);
45 /// Returns explicitly-requested zero-based version of the counter id, used
46 /// during codegen. LLVM expects zero-based indexes.
47 pub fn zero_based_index(self) -> u32 {
48 let one_based_index = self.as_u32();
49 debug_assert!(one_based_index > 0);
54 rustc_index::newtype_index! {
55 /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
57 /// Values descend from u32::MAX.
60 #[debug_format = "InjectedExpressionId({})"]
61 pub struct InjectedExpressionId {}
64 rustc_index::newtype_index! {
65 /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
67 /// Values ascend from 0.
70 #[debug_format = "InjectedExpressionIndex({})"]
71 pub struct InjectedExpressionIndex {}
74 rustc_index::newtype_index! {
75 /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
76 /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
77 /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
80 #[debug_format = "MappedExpressionIndex({})"]
81 pub struct MappedExpressionIndex {}
84 impl From<CounterValueReference> for ExpressionOperandId {
86 fn from(v: CounterValueReference) -> ExpressionOperandId {
87 ExpressionOperandId::from(v.as_u32())
91 impl From<InjectedExpressionId> for ExpressionOperandId {
93 fn from(v: InjectedExpressionId) -> ExpressionOperandId {
94 ExpressionOperandId::from(v.as_u32())
98 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
99 pub enum CoverageKind {
101 function_source_hash: u64,
102 id: CounterValueReference,
105 id: InjectedExpressionId,
106 lhs: ExpressionOperandId,
108 rhs: ExpressionOperandId,
114 pub fn as_operand_id(&self) -> ExpressionOperandId {
117 Counter { id, .. } => ExpressionOperandId::from(id),
118 Expression { id, .. } => ExpressionOperandId::from(id),
119 Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
123 pub fn is_expression(&self) -> bool {
124 matches!(self, Self::Expression { .. })
128 impl Debug for CoverageKind {
129 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
132 Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
133 Expression { id, lhs, op, rhs } => write!(
135 "Expression({:?}) = {} {} {}",
138 if *op == Op::Add { "+" } else { "-" },
141 Unreachable => write!(fmt, "Unreachable"),
146 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
147 #[derive(TypeFoldable, TypeVisitable)]
148 pub struct CodeRegion {
149 pub file_name: Symbol,
156 impl Debug for CodeRegion {
157 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
161 self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
166 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
167 #[derive(TypeFoldable, TypeVisitable)]
174 pub fn is_add(&self) -> bool {
175 matches!(self, Self::Add)
178 pub fn is_subtract(&self) -> bool {
179 matches!(self, Self::Subtract)