/// \brief The source mapping regions for this function.
std::vector<SourceMappingRegion> SourceRegions;
+ /// \brief A set of regions which can be used as a filter.
+ ///
+ /// It is produced by emitExpansionRegions() and is used in
+ /// emitSourceRegions() to suppress producing code regions if
+ /// the same area is covered by expansion regions.
+ typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
+ SourceRegionFilter;
+
CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
const LangOptions &LangOpts)
: CVM(CVM), SM(SM), LangOpts(LangOpts) {}
/// \brief Generate the coverage counter mapping regions from collected
/// source regions.
- void emitSourceRegions() {
+ void emitSourceRegions(const SourceRegionFilter &Filter) {
for (const auto &Region : SourceRegions) {
assert(Region.hasEndLoc() && "incomplete region");
assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
"region spans multiple files");
+ // Don't add code regions for the area covered by expansion regions.
+ // This not only suppresses redundant regions, but sometimes prevents
+ // creating regions with wrong counters if, for example, a statement's
+ // body ends at the end of a nested macro.
+ if (Filter.count(std::make_pair(LocStart, LocEnd)))
+ continue;
+
// Find the spilling locations for the mapping region.
unsigned LineStart = SM.getSpellingLineNumber(LocStart);
unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);
}
/// \brief Generate expansion regions for each virtual file we've seen.
- void emitExpansionRegions() {
+ SourceRegionFilter emitExpansionRegions() {
+ SourceRegionFilter Filter;
for (const auto &FM : FileIDMapping) {
SourceLocation ExpandedLoc = FM.second.second;
SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
"region spans multiple files");
+ Filter.insert(std::make_pair(ParentLoc, LocEnd));
unsigned LineStart = SM.getSpellingLineNumber(ParentLoc);
unsigned ColumnStart = SM.getSpellingColumnNumber(ParentLoc);
*ParentFileID, *ExpandedFileID, LineStart, ColumnStart, LineEnd,
ColumnEnd));
}
+ return Filter;
}
};
void write(llvm::raw_ostream &OS) {
SmallVector<unsigned, 16> FileIDMapping;
gatherFileIDs(FileIDMapping);
- emitSourceRegions();
+ emitSourceRegions(SourceRegionFilter());
if (MappingRegions.empty())
return;
void write(llvm::raw_ostream &OS) {
llvm::SmallVector<unsigned, 8> VirtualFileMapping;
gatherFileIDs(VirtualFileMapping);
- emitSourceRegions();
- emitExpansionRegions();
+ SourceRegionFilter Filter = emitExpansionRegions();
+ emitSourceRegions(Filter);
gatherSkippedRegions();
if (MappingRegions.empty())
int main() M1
return 0;
}
-// CHECK-NEXT: File 1, 4:12 -> 4:14 = #0
// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0
// CHECK-NEXT: File 2, 3:12 -> 3:13 = #0
void func2() {
int x = 0;
M11
-// CHECK-NEXT: File 1, 6:13 -> 6:16 = #0
// CHECK-NEXT: Expansion,File 1, 6:13 -> 6:16 = #0
// CHECK-NEXT: File 2, 5:13 -> 5:14 = #0
void func3() M1
int x = 0;
M11
-// CHECK-NEXT: File 1, 4:12 -> 4:14 = #0
// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0
-// CHECK-NEXT: File 2, 6:13 -> 6:16 = #0
// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = #0
// CHECK-NEXT: File 3, 3:12 -> 3:13 = #0
// CHECK-NEXT: File 4, 5:13 -> 5:14 = #0
// CHECK-NEXT: File 0, [[@LINE+2]]:16 -> [[@LINE+2]]:20 = #0
// CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:17 -> [[@LINE+1]]:20 = #0
void func4() M1 M11
-// CHECK-NEXT: File 1, 4:12 -> 4:14 = #0
// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0
-// CHECK-NEXT: File 2, 6:13 -> 6:16 = #0
// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = #0
// CHECK-NEXT: File 3, 3:12 -> 3:13 = #0
// CHECK-NEXT: File 4, 5:13 -> 5:14 = #0
#define MACRO return; bar()
#define MACRO_2 bar()
#define MACRO_1 return; MACRO_2
+#define MACRO_3 MACRO_2
void bar() {}
i = 2;
}
// CHECK-NEXT: File 1, 5:17 -> 5:32 = #0
-// CHECK-NEXT: File 1, 5:25 -> 5:32 = 0
// CHECK-NEXT: Expansion,File 1, 5:25 -> 5:32 = 0
// CHECK-NEXT: File 2, 4:17 -> 4:22 = 0
// CHECK-NEXT: File 1, 4:17 -> 4:22 = #2
// CHECK-NOT: File 1
+// CHECK-NEXT: func5
+void func5() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+4]]:2 = #0
+ int i = 0;
+ if (i > 5) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = #0
+ MACRO_3; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:12 = #1
+}
+// CHECK-NEXT: Expansion,File 1, 6:17 -> 6:24 = #1
+// CHECK-NEXT: File 2, 4:17 -> 4:22 = #1
+
int main(int argc, const char *argv[]) {
func();
func2();