Skip to content

[Coverage][Expansion] handle nested macros in scratch space #89869

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 24, 2024
45 changes: 40 additions & 5 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
@@ -294,10 +294,36 @@ class CoverageMappingBuilder {
return SM.getLocForEndOfFile(SM.getFileID(Loc));
}

/// Find out where the current file is included or macro is expanded.
SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
: SM.getIncludeLoc(SM.getFileID(Loc));
/// Find out where a macro is expanded. If the immediate result is a
/// <scratch space>, keep looking until the result isn't. Return a pair of
/// \c SourceLocation. The first object is always the begin sloc of found
/// result. The second should be checked by the caller: if it has value, it's
/// the end sloc of the found result. Otherwise the while loop didn't get
/// executed, which means the location wasn't changed and the caller has to
/// learn the end sloc from somewhere else.
std::pair<SourceLocation, std::optional<SourceLocation>>
getNonScratchExpansionLoc(SourceLocation Loc) {
std::optional<SourceLocation> EndLoc = std::nullopt;
while (Loc.isMacroID() &&
SM.isWrittenInScratchSpace(SM.getSpellingLoc(Loc))) {
auto ExpansionRange = SM.getImmediateExpansionRange(Loc);
Loc = ExpansionRange.getBegin();
EndLoc = ExpansionRange.getEnd();
}
return std::make_pair(Loc, EndLoc);
}

/// Find out where the current file is included or macro is expanded. If
/// \c AcceptScratch is set to false, keep looking for expansions until the
/// found sloc is not a <scratch space>.
SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc,
bool AcceptScratch = true) {
if (!Loc.isMacroID())
return SM.getIncludeLoc(SM.getFileID(Loc));
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
if (AcceptScratch)
return Loc;
return getNonScratchExpansionLoc(Loc).first;
}

/// Return true if \c Loc is a location in a built-in macro.
@@ -344,6 +370,15 @@ class CoverageMappingBuilder {
for (auto &Region : SourceRegions) {
SourceLocation Loc = Region.getBeginLoc();

// Replace Region with its definition if it is in <scratch space>.
auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc);
auto EndLoc = NonScratchExpansionLoc.second;
if (EndLoc.has_value()) {
Loc = NonScratchExpansionLoc.first;
Region.setStartLoc(Loc);
Region.setEndLoc(EndLoc.value());
}

// Replace Loc with FileLoc if it is expanded with system headers.
if (!SystemHeadersCoverage && SM.isInSystemMacro(Loc)) {
auto BeginLoc = SM.getSpellingLoc(Loc);
@@ -538,7 +573,7 @@ class CoverageMappingBuilder {
SourceRegionFilter Filter;
for (const auto &FM : FileIDMapping) {
SourceLocation ExpandedLoc = FM.second.second;
SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc, false);
if (ParentLoc.isInvalid())
continue;

2 changes: 1 addition & 1 deletion clang/test/CoverageMapping/builtinmacro.c
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

// CHECK: filename
const char *filename (const char *name) { // CHECK-NEXT: File 0, [[@LINE]]:41 -> [[@LINE+3]]:2 = #0
static const char this_file[] = __FILE__;
static const char this_file[] = __FILE__; // CHECK-NEXT: File 0, [[@LINE]]:35 -> [[@LINE]]:35 = #0
return this_file;
}

8 changes: 5 additions & 3 deletions clang/test/CoverageMapping/macros.c
Original file line number Diff line number Diff line change
@@ -80,12 +80,14 @@ void func7(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+6]]:2 = #0
int kk,ll; // CHECK-NEXT: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:8 = #0
if (k) // CHECK-NEXT: Branch,File 0, [[@LINE]]:7 -> [[@LINE]]:8 = #1
m(k); // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:9 -> [[@LINE]]:5 = #1
else // CHECK-NEXT: Expansion,File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:6 = #0
else // CHECK-NEXT: Expansion,File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:6 = #1
l = m(l); // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:7 -> [[@LINE]]:5 = (#0 - #1)
} // CHECK-NEXT: File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:10 = (#0 - #1)
// CHECK-NEXT: Expansion,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:10 = (#0 - #1)
// CHECK-NEXT: File 1, [[@LINE-9]]:14 -> [[@LINE-9]]:18 = #0
// CHECK-NEXT: File 2, [[@LINE-10]]:14 -> [[@LINE-10]]:15 = (#0 - #1)
// CHECK-NEXT: File 1, [[@LINE-9]]:14 -> [[@LINE-9]]:17 = #1
// CHECK-NEXT: File 1, [[@LINE-10]]:14 -> [[@LINE-10]]:18 = #0
// CHECK-NEXT: File 2, [[@LINE-11]]:14 -> [[@LINE-11]]:17 = (#0 - #1)
// CHECK-NEXT: File 2, [[@LINE-12]]:14 -> [[@LINE-12]]:15 = (#0 - #1)

int main(int argc, const char *argv[]) {
func();
52 changes: 45 additions & 7 deletions clang/test/CoverageMapping/mcdc-scratch-space.c
Original file line number Diff line number Diff line change
@@ -1,27 +1,65 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c99 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s
// XFAIL: *
// REQUIRES: asserts
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c99 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s | FileCheck %s

// CHECK: builtin_macro0:
int builtin_macro0(int a) {
return (__LINE__
&& a);
// CHECK: Decision,File 0, [[@LINE+1]]:11 -> [[@LINE+2]]:15 = M:0, C:2
return (__LINE__ // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:11 = 0, 0 [1,2,0]
&& a); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:15 = #2, (#1 - #2) [2,0,0]
}

// CHECK: builtin_macro1:
int builtin_macro1(int a) {
return (a
|| __LINE__);
// CHECK: Decision,File 0, [[@LINE+1]]:11 -> [[@LINE+2]]:22 = M:0, C:2
return (a // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = (#0 - #1), #1 [1,0,2]
|| __LINE__); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:14 = 0, 0 [2,0,0]
}

#define PRE(x) pre_##x

// CHECK: pre0:
int pre0(int pre_a, int b_post) {
// CHECK: Decision,File 0, [[@LINE+2]]:11 -> [[@LINE+3]]:20 = M:0, C:2
// CHECK: Expansion,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:14 = #0 (Expanded file = 1)
return (PRE(a)
&& b_post);
// CHECK: Branch,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:20 = #2, (#1 - #2) [2,0,0]
// CHECK: Branch,File 1, [[@LINE-9]]:16 -> [[@LINE-9]]:22 = #1, (#0 - #1) [1,2,0]
}

#define pre_foo pre_a

// CHECK: pre1:
int pre1(int pre_a, int b_post) {
// CHECK: Decision,File 0, [[@LINE+3]]:11 -> [[@LINE+4]]:20 = M:0, C:2
// CHECK: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:14 = #0 (Expanded file = 1)
// CHECK: Branch,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:20 = #2, (#1 - #2) [2,0,0]
return (PRE(foo)
&& b_post);
// CHECK: Expansion,File 1, 17:16 -> 17:20 = #0 (Expanded file = 2)
// CHECK: Branch,File 2, 29:17 -> 29:22 = #1, (#0 - #1) [1,2,0]
}

#define POST(x) x##_post

// CHECK: post0:
int post0(int pre_a, int b_post) {
// CHECK: Decision,File 0, [[@LINE+2]]:11 -> [[@LINE+3]]:18 = M:0, C:2
// CHECK: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:16 = (#0 - #1), #1 [1,0,2]
return (pre_a
|| POST(b));
// CHECK: Expansion,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:18 = #1 (Expanded file = 1)
// CHECK: Branch,File 1, [[@LINE-9]]:17 -> [[@LINE-9]]:20 = (#1 - #2), #2 [2,0,0]
}

#define bar_post b_post

// CHECK: post1:
int post1(int pre_a, int b_post) {
// CHECK: Decision,File 0, [[@LINE+3]]:11 -> [[@LINE+4]]:18 = M:0, C:2
// CHECK: Branch,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:16 = (#0 - #1), #1 [1,0,2]
// CHECK: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:18 = 0 (Expanded file = 1)
return (pre_a
|| POST(bar));
// CHECK: Expansion,File 1, 42:17 -> 42:18 = #1 (Expanded file = 2)
// CHECK: Branch,File 2, 54:18 -> 54:24 = (#1 - #2), #2 [2,0,0]
}