Issue 208237
Summary [llvm-cov] Wrong `show` output if a macro defined in a system header defines an inline function
Labels new issue
Assignees
Reporter kanje
    ### Problem Statement

Given this project structure
```
CMakeLists.txt
include
└── mymacro.hh
main.cc
main.hh
test.cc
```

when

1. `include` is a system include path specified with `-isystem`
2. `mymacro.hh` defines `MY_MACRO()` as `inline void func_from_macro() {}`
3. `MY_MACRO()` is used in `main.hh`
4. `main.hh` contains another inlined function after using `MY_MACRO()`
5. `func_from_macro()` is not used in tests

then `llvm-cov show` marks `MY_MACRO()` as not covered (which is correct) **and** also marks a region afterwards as not covered as well, including empty lines, comments and function declarations (even if their definitions are covered).

### Reproduction

1. Take the code (attached, or see the [listing](#code-listing) below).
2. Make a `build` directory.
    ```bash
    mkdir build && cd build
    ```
3. Build the project with Clang.
    ```bash
    CXX=clang++ cmake .. && cmake --build .
    ```
4. Run the tests.
    ```bash
    find . -name "*.profraw" -delete && ctest
    ```
5. Generate the coverage report.
    ```bash
    llvm-profdata merge -o merged.profdata default.profraw
    llvm-cov show -format=text -instr-profile="" CMakeFiles/main.dir/main.cc.o -object=CMakeFiles/ut-main.dir/test.cc.o .. .
    ```

The output will look like this:
```
    1|       |#pragma once
    2|       |
    3|       |#include <mymacro.hh>
    4|       |
    5|      0|MY_MACRO()
    6|      0|// inline int bar() { return 42; }
    7|      0|
    8|      0|// Comment section
    9|      0|// Comment section
   10|      0|// Comment section
   11|      0|// Comment section
   12|      0|// Comment section
   13|      0|// Comment section
   14|      0|// Comment section
   15|      0|// Comment section
   16|      0|
   17|      0|int doSomething();
   18|      0|
   19|      0|class ExampleClass {
   20|      0|public:
   21|      0|    ExampleClass();
   22|      0|};
   23|      0|
   24|      0|inline int foo() { return 42; }
   25|       |
   26|       |// Comment section
```

### Expected Output

Only `MY_MACRO()` is marked as not covered.

### Other Observations

1. Uncommenting `bar()` right after `MY_MACRO()` stops the propagation of the not covered region.
2. Defining `MY_MACRO()` locally or using `-I` instead of `-isystem` fixes the issue.
3. Commenting out `foo()` at the end of `main.hh` fixes the issue.
4. Covering `func_from_macro()` fixing the issue.

### Code Listing

#### CMakeLists.txt
```
cmake_minimum_required(VERSION 3.28)
project(CoverageTest VERSION 1.0 LANGUAGES CXX)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping" CACHE STRING "" FORCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping" CACHE STRING "" FORCE)
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS_DEBUG}" CACHE STRING "" FORCE)

find_package(GTest REQUIRED)
enable_testing()

add_library(main STATIC main.cc)
target_include_directories(main SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

add_executable(ut-main test.cc)
target_link_libraries(ut-main PRIVATE main GTest::gtest GTest::gtest_main)
add_test(NAME ut-main COMMAND ut-main)
```

#### include/mymacro.hh
```cpp
#pragma once

#define MY_MACRO() inline void func_from_macro() {}
```

#### main.hh
```cpp
#pragma once

#include <mymacro.hh>

MY_MACRO()
// inline int bar() { return 42; }

// Comment section
// Comment section
// Comment section
// Comment section
// Comment section
// Comment section
// Comment section
// Comment section

int doSomething();

class ExampleClass {
public:
    ExampleClass();
};

inline int foo() { return 42; }

// Comment section
```

#### main.cc
```cpp
#include "main.hh"

int doSomething()
{
    ExampleClass c;
    return 42;
}

ExampleClass::ExampleClass()
{
    // Constructor implementation
}
```

#### test.cc
```cpp
#include <gtest/gtest.h>
#include "main.hh"

TEST(Test, Test) {
    doSomething();
}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to