In the current gcov implementation, all lines within a basic block are attributed to the source file of the block's containing function. This is inaccurate when a block contains lines from other files (e.g., via #include "foo.inc"). Commit [406e81b](406e81b79d) attempted to address this by filtering lines based on debug info types, but this approach has two limitations: * **Over-filtering**: Some valid lines belonging to the function are incorrectly excluded. * **Under-counting**: Lines not belonging to the function are filtered out and omitted from coverage statistics. **GCC Reference Behavior** GCC's gcov implementation handles this case correctly.This change aligns the LLVM behavior with GCC. **Proposed Solution** 1. **GCNO Generation**: * **Current**: Each block stores a single GCOVLines record (filename + lines). * **New**: Dynamically create new GCOVLines records whenever consecutive lines in a block originate from different source files. Group subsequent lines from the same file under one record. 2. **GCNO Parsing**: * **Current**: Lines are directly attributed to the function's source file. * **New**: Introduce a GCOVLocation type to track filename/line mappings within blocks. Statistics will reflect the actual source file for each line.
40 lines
1.3 KiB
C++
40 lines
1.3 KiB
C++
// RUN: rm -rf %t && split-file %s %t && cd %t
|
|
// RUN: %clangxx --coverage main.cpp -o t
|
|
// RUN: %run ./t
|
|
// RUN: llvm-cov gcov -t t-main. | FileCheck %s
|
|
|
|
//--- main.cpp
|
|
#include "a.h"
|
|
#include <stdio.h>
|
|
|
|
// CHECK: Runs:1
|
|
/// __cxx_global_var_init contains a block from a.h. Don't attribute its lines to main.cpp.
|
|
// CHECK-NOT: {{^ +[0-9]+:}}
|
|
|
|
inline auto *const inl_var_main = // CHECK: 1: [[#]]:inline auto
|
|
new A; // CHECK-NEXT: 1: [[#]]:
|
|
void foo(int x) { // CHECK-NEXT: 1: [[#]]:
|
|
if (x) { // CHECK-NEXT: 1: [[#]]:
|
|
#include "a.inc"
|
|
} // CHECK: 1: [[#]]:
|
|
} // CHECK-NEXT: 1: [[#]]:
|
|
// CHECK-NOT: {{^ +[0-9]+:}}
|
|
|
|
int main(int argc, char *argv[]) { // CHECK: 1: [[#]]:int main
|
|
foo(1); // CHECK-NEXT: 1: [[#]]:
|
|
} // CHECK-NEXT: 1: [[#]]:
|
|
// CHECK-NOT: {{^ +[0-9]+:}}
|
|
|
|
// CHECK: Source:a.h
|
|
// CHECK: 1: 1:struct A
|
|
// CHECK-NOT: {{^ +[0-9]+:}}
|
|
|
|
//--- a.h
|
|
/// Apple targets doesn't enable -mconstructor-aliases by default and the count may be 4.
|
|
struct A { A() { } }; // CHECK: {{[24]}}: [[#]]:struct A
|
|
inline auto *const inl_var_a = // CHECK-NEXT: 1: [[#]]:
|
|
new A; // CHECK-NEXT: 1: [[#]]:
|
|
|
|
//--- a.inc
|
|
puts(""); // CHECK: 1: [[#]]:puts
|