int-zjt f4cf610159
[Coverage] Add gap region between binary operator '&& and ||' and RHS (#149085)
## Issue Summary
We identified an inaccuracy in line coverage reporting when short-circuit evaluation occurs in multi-line conditional expressions.

Specifically:
1. Un-executed conditions following line breaks may be incorrectly marked as covered
(e.g., conditionB in a non-executed && chain shows coverage)
```
    1|       |#include <iostream>
    2|       |
    3|      1|int main() {
    4|      1|    bool conditionA = false;
    5|      1|    bool conditionB = true;
    6|      1|    if (conditionA &&
    7|      1|        conditionB) {
    8|      0|        std::cout << "IF-THEN" << std::endl;
    9|      0|    }
   10|      1|    return 0;
   11|      1|}
```
2. Inconsistent coverage reporting across un-executed conditions
*(adjacent un-executed conditions may show 1 vs 0 line coverage)*
```
    1|       |#include <iostream>
    2|       |
    3|      1|int main() {
    4|      1|    bool conditionA = false;
    5|      1|    bool conditionB = true;
    6|      1|    bool conditionC = true;
    7|      1|    if (conditionA &&
    8|      1|        (conditionB ||
    9|      0|        conditionC)) {
   10|      0|        std::cout << "IF-THEN" << std::endl;
   11|      0|    }
   12|      1|    return 0;
   13|      1|}
```

This is resolved by inserting a GapRegion when mapping logical operators to isolate coverage contexts around short-circuit evaluation.
2025-08-08 12:50:52 -05:00

32 lines
2.9 KiB
C++

// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name logical.cpp %s | FileCheck %s
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name logical.cpp %s | FileCheck %s -check-prefix=MCDC
int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+27]]:2 = #0
bool bt = true;
bool bf = false; // MCDC: Decision,File 0, [[@LINE+1]]:12 -> [[@LINE+1]]:20 = M:3, C:2
bool a = bt && bf; // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE]]:14 = #0
// CHECK-NEXT: Branch,File 0, [[@LINE-1]]:12 -> [[@LINE-1]]:14 = #1, (#0 - #1)
// CHECK-NEXT: Gap,File 0, [[@LINE-2]]:14 -> [[@LINE-2]]:18 = #1
// CHECK-NEXT: File 0, [[@LINE-3]]:18 -> [[@LINE-3]]:20 = #1
// CHECK-NEXT: Branch,File 0, [[@LINE-4]]:18 -> [[@LINE-4]]:20 = #2, (#1 - #2)
// MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+2]]:9 = M:6, C:2
a = bt && // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
bf; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = #3, (#0 - #3)
// CHECK-NEXT: Gap,File 0, [[@LINE-2]]:9 -> [[@LINE-1]]:7 = #3
// CHECK-NEXT: File 0, [[@LINE-2]]:7 -> [[@LINE-2]]:9 = #3
// CHECK-NEXT: Branch,File 0, [[@LINE-3]]:7 -> [[@LINE-3]]:9 = #4, (#3 - #4)
// MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:15 = M:9, C:2
a = bf || bt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
// CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = (#0 - #5), #5
// CHECK-NEXT: Gap,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:13 = #5
// CHECK-NEXT: File 0, [[@LINE-3]]:13 -> [[@LINE-3]]:15 = #5
// CHECK-NEXT: Branch,File 0, [[@LINE-4]]:13 -> [[@LINE-4]]:15 = (#5 - #6), #6
// MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+2]]:9 = M:12, C:2
a = bf || // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
bt; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = (#0 - #7), #7
// CHECK-NEXT: Gap,File 0, [[@LINE-2]]:9 -> [[@LINE-1]]:7 = #7
// CHECK-NEXT: File 0, [[@LINE-2]]:7 -> [[@LINE-2]]:9 = #7
// CHECK-NEXT: Branch,File 0, [[@LINE-3]]:7 -> [[@LINE-3]]:9 = (#7 - #8), #8
return 0;
}