Bug Summary

File:build/source/clang/lib/CodeGen/CoverageMappingGen.cpp
Warning:line 279, column 26
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name CoverageMappingGen.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm -resource-dir /usr/lib/llvm-17/lib/clang/17 -I tools/clang/lib/CodeGen -I /build/source/clang/lib/CodeGen -I /build/source/clang/include -I tools/clang/include -I include -I /build/source/llvm/include -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm=build-llvm -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm=build-llvm -fcoverage-prefix-map=/build/source/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm -fdebug-prefix-map=/build/source/build-llvm=build-llvm -fdebug-prefix-map=/build/source/= -fdebug-prefix-map=/build/source/build-llvm=build-llvm -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/clang/lib/CodeGen/CoverageMappingGen.cpp
1//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Instrumentation-based code coverage mapping generator
10//
11//===----------------------------------------------------------------------===//
12
13#include "CoverageMappingGen.h"
14#include "CodeGenFunction.h"
15#include "clang/AST/StmtVisitor.h"
16#include "clang/Basic/Diagnostic.h"
17#include "clang/Basic/FileManager.h"
18#include "clang/Frontend/FrontendDiagnostic.h"
19#include "clang/Lex/Lexer.h"
20#include "llvm/ADT/SmallSet.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ProfileData/Coverage/CoverageMapping.h"
23#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
24#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
25#include "llvm/ProfileData/InstrProfReader.h"
26#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/Path.h"
28#include <optional>
29
30// This selects the coverage mapping format defined when `InstrProfData.inc`
31// is textually included.
32#define COVMAP_V3
33
34static llvm::cl::opt<bool> EmptyLineCommentCoverage(
35 "emptyline-comment-coverage",
36 llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
37 "disable it on test)"),
38 llvm::cl::init(true), llvm::cl::Hidden);
39
40static llvm::cl::opt<bool> SystemHeadersCoverage(
41 "system-headers-coverage",
42 llvm::cl::desc("Enable collecting coverage from system headers"),
43 llvm::cl::init(false), llvm::cl::Hidden);
44
45using namespace clang;
46using namespace CodeGen;
47using namespace llvm::coverage;
48
49CoverageSourceInfo *
50CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
51 CoverageSourceInfo *CoverageInfo =
52 new CoverageSourceInfo(PP.getSourceManager());
53 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
54 if (EmptyLineCommentCoverage) {
55 PP.addCommentHandler(CoverageInfo);
56 PP.setEmptylineHandler(CoverageInfo);
57 PP.setPreprocessToken(true);
58 PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
59 // Update previous token location.
60 CoverageInfo->PrevTokLoc = Tok.getLocation();
61 if (Tok.getKind() != clang::tok::eod)
62 CoverageInfo->updateNextTokLoc(Tok.getLocation());
63 });
64 }
65 return CoverageInfo;
66}
67
68void CoverageSourceInfo::AddSkippedRange(SourceRange Range,
69 SkippedRange::Kind RangeKind) {
70 if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
71 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
72 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
73 Range.getBegin()))
74 SkippedRanges.back().Range.setEnd(Range.getEnd());
75 else
76 SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
77}
78
79void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
80 AddSkippedRange(Range, SkippedRange::PPIfElse);
81}
82
83void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
84 AddSkippedRange(Range, SkippedRange::EmptyLine);
85}
86
87bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
88 AddSkippedRange(Range, SkippedRange::Comment);
89 return false;
90}
91
92void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
93 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
94 SkippedRanges.back().NextTokLoc = Loc;
95}
96
97namespace {
98
99/// A region of source code that can be mapped to a counter.
100class SourceMappingRegion {
101 /// Primary Counter that is also used for Branch Regions for "True" branches.
102 Counter Count;
103
104 /// Secondary Counter used for Branch Regions for "False" branches.
105 std::optional<Counter> FalseCount;
106
107 /// The region's starting location.
108 std::optional<SourceLocation> LocStart;
109
110 /// The region's ending location.
111 std::optional<SourceLocation> LocEnd;
112
113 /// Whether this region is a gap region. The count from a gap region is set
114 /// as the line execution count if there are no other regions on the line.
115 bool GapRegion;
116
117public:
118 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
119 std::optional<SourceLocation> LocEnd,
120 bool GapRegion = false)
121 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
122 }
123
124 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
125 std::optional<SourceLocation> LocStart,
126 std::optional<SourceLocation> LocEnd,
127 bool GapRegion = false)
128 : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
129 LocEnd(LocEnd), GapRegion(GapRegion) {}
130
131 const Counter &getCounter() const { return Count; }
132
133 const Counter &getFalseCounter() const {
134 assert(FalseCount && "Region has no alternate counter")(static_cast <bool> (FalseCount && "Region has no alternate counter"
) ? void (0) : __assert_fail ("FalseCount && \"Region has no alternate counter\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 134, __extension__
__PRETTY_FUNCTION__))
;
135 return *FalseCount;
136 }
137
138 void setCounter(Counter C) { Count = C; }
139
140 bool hasStartLoc() const { return LocStart.has_value(); }
141
142 void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
143
144 SourceLocation getBeginLoc() const {
145 assert(LocStart && "Region has no start location")(static_cast <bool> (LocStart && "Region has no start location"
) ? void (0) : __assert_fail ("LocStart && \"Region has no start location\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 145, __extension__
__PRETTY_FUNCTION__))
;
146 return *LocStart;
147 }
148
149 bool hasEndLoc() const { return LocEnd.has_value(); }
150
151 void setEndLoc(SourceLocation Loc) {
152 assert(Loc.isValid() && "Setting an invalid end location")(static_cast <bool> (Loc.isValid() && "Setting an invalid end location"
) ? void (0) : __assert_fail ("Loc.isValid() && \"Setting an invalid end location\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 152, __extension__
__PRETTY_FUNCTION__))
;
153 LocEnd = Loc;
154 }
155
156 SourceLocation getEndLoc() const {
157 assert(LocEnd && "Region has no end location")(static_cast <bool> (LocEnd && "Region has no end location"
) ? void (0) : __assert_fail ("LocEnd && \"Region has no end location\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 157, __extension__
__PRETTY_FUNCTION__))
;
158 return *LocEnd;
159 }
160
161 bool isGap() const { return GapRegion; }
162
163 void setGap(bool Gap) { GapRegion = Gap; }
164
165 bool isBranch() const { return FalseCount.has_value(); }
166};
167
168/// Spelling locations for the start and end of a source region.
169struct SpellingRegion {
170 /// The line where the region starts.
171 unsigned LineStart;
172
173 /// The column where the region starts.
174 unsigned ColumnStart;
175
176 /// The line where the region ends.
177 unsigned LineEnd;
178
179 /// The column where the region ends.
180 unsigned ColumnEnd;
181
182 SpellingRegion(SourceManager &SM, SourceLocation LocStart,
183 SourceLocation LocEnd) {
184 LineStart = SM.getSpellingLineNumber(LocStart);
185 ColumnStart = SM.getSpellingColumnNumber(LocStart);
186 LineEnd = SM.getSpellingLineNumber(LocEnd);
187 ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
188 }
189
190 SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
191 : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
192
193 /// Check if the start and end locations appear in source order, i.e
194 /// top->bottom, left->right.
195 bool isInSourceOrder() const {
196 return (LineStart < LineEnd) ||
197 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
198 }
199};
200
201/// Provides the common functionality for the different
202/// coverage mapping region builders.
203class CoverageMappingBuilder {
204public:
205 CoverageMappingModuleGen &CVM;
206 SourceManager &SM;
207 const LangOptions &LangOpts;
208
209private:
210 /// Map of clang's FileIDs to IDs used for coverage mapping.
211 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
212 FileIDMapping;
213
214public:
215 /// The coverage mapping regions for this function
216 llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
217 /// The source mapping regions for this function.
218 std::vector<SourceMappingRegion> SourceRegions;
219
220 /// A set of regions which can be used as a filter.
221 ///
222 /// It is produced by emitExpansionRegions() and is used in
223 /// emitSourceRegions() to suppress producing code regions if
224 /// the same area is covered by expansion regions.
225 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
226 SourceRegionFilter;
227
228 CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
229 const LangOptions &LangOpts)
230 : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
231
232 /// Return the precise end location for the given token.
233 SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
234 // We avoid getLocForEndOfToken here, because it doesn't do what we want for
235 // macro locations, which we just treat as expanded files.
236 unsigned TokLen =
237 Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
238 return Loc.getLocWithOffset(TokLen);
239 }
240
241 /// Return the start location of an included file or expanded macro.
242 SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
243 if (Loc.isMacroID())
244 return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
245 return SM.getLocForStartOfFile(SM.getFileID(Loc));
246 }
247
248 /// Return the end location of an included file or expanded macro.
249 SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
250 if (Loc.isMacroID())
251 return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
252 SM.getFileOffset(Loc));
253 return SM.getLocForEndOfFile(SM.getFileID(Loc));
254 }
255
256 /// Find out where the current file is included or macro is expanded.
257 SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
258 return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
259 : SM.getIncludeLoc(SM.getFileID(Loc));
260 }
261
262 /// Return true if \c Loc is a location in a built-in macro.
263 bool isInBuiltin(SourceLocation Loc) {
264 return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
265 }
266
267 /// Check whether \c Loc is included or expanded from \c Parent.
268 bool isNestedIn(SourceLocation Loc, FileID Parent) {
269 do {
270 Loc = getIncludeOrExpansionLoc(Loc);
271 if (Loc.isInvalid())
272 return false;
273 } while (!SM.isInFileID(Loc, Parent));
274 return true;
275 }
276
277 /// Get the start of \c S ignoring macro arguments and builtin macros.
278 SourceLocation getStart(const Stmt *S) {
279 SourceLocation Loc = S->getBeginLoc();
14
Called C++ object pointer is null
280 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
281 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
282 return Loc;
283 }
284
285 /// Get the end of \c S ignoring macro arguments and builtin macros.
286 SourceLocation getEnd(const Stmt *S) {
287 SourceLocation Loc = S->getEndLoc();
288 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
289 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
290 return getPreciseTokenLocEnd(Loc);
291 }
292
293 /// Find the set of files we have regions for and assign IDs
294 ///
295 /// Fills \c Mapping with the virtual file mapping needed to write out
296 /// coverage and collects the necessary file information to emit source and
297 /// expansion regions.
298 void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
299 FileIDMapping.clear();
300
301 llvm::SmallSet<FileID, 8> Visited;
302 SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
303 for (const auto &Region : SourceRegions) {
304 SourceLocation Loc = Region.getBeginLoc();
305 FileID File = SM.getFileID(Loc);
306 if (!Visited.insert(File).second)
307 continue;
308
309 // Do not map FileID's associated with system headers unless collecting
310 // coverage from system headers is explicitly enabled.
311 if (!SystemHeadersCoverage && SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
312 continue;
313
314 unsigned Depth = 0;
315 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
316 Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
317 ++Depth;
318 FileLocs.push_back(std::make_pair(Loc, Depth));
319 }
320 llvm::stable_sort(FileLocs, llvm::less_second());
321
322 for (const auto &FL : FileLocs) {
323 SourceLocation Loc = FL.first;
324 FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
325 auto Entry = SM.getFileEntryForID(SpellingFile);
326 if (!Entry)
327 continue;
328
329 FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
330 Mapping.push_back(CVM.getFileID(Entry));
331 }
332 }
333
334 /// Get the coverage mapping file ID for \c Loc.
335 ///
336 /// If such file id doesn't exist, return std::nullopt.
337 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
338 auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
339 if (Mapping != FileIDMapping.end())
340 return Mapping->second.first;
341 return std::nullopt;
342 }
343
344 /// This shrinks the skipped range if it spans a line that contains a
345 /// non-comment token. If shrinking the skipped range would make it empty,
346 /// this returns std::nullopt.
347 /// Note this function can potentially be expensive because
348 /// getSpellingLineNumber uses getLineNumber, which is expensive.
349 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
350 SourceLocation LocStart,
351 SourceLocation LocEnd,
352 SourceLocation PrevTokLoc,
353 SourceLocation NextTokLoc) {
354 SpellingRegion SR{SM, LocStart, LocEnd};
355 SR.ColumnStart = 1;
356 if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
357 SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
358 SR.LineStart++;
359 if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
360 SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
361 SR.LineEnd--;
362 SR.ColumnEnd++;
363 }
364 if (SR.isInSourceOrder())
365 return SR;
366 return std::nullopt;
367 }
368
369 /// Gather all the regions that were skipped by the preprocessor
370 /// using the constructs like #if or comments.
371 void gatherSkippedRegions() {
372 /// An array of the minimum lineStarts and the maximum lineEnds
373 /// for mapping regions from the appropriate source files.
374 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
375 FileLineRanges.resize(
376 FileIDMapping.size(),
377 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
378 for (const auto &R : MappingRegions) {
379 FileLineRanges[R.FileID].first =
380 std::min(FileLineRanges[R.FileID].first, R.LineStart);
381 FileLineRanges[R.FileID].second =
382 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
383 }
384
385 auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
386 for (auto &I : SkippedRanges) {
387 SourceRange Range = I.Range;
388 auto LocStart = Range.getBegin();
389 auto LocEnd = Range.getEnd();
390 assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&(static_cast <bool> (SM.isWrittenInSameFile(LocStart, LocEnd
) && "region spans multiple files") ? void (0) : __assert_fail
("SM.isWrittenInSameFile(LocStart, LocEnd) && \"region spans multiple files\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 391, __extension__
__PRETTY_FUNCTION__))
391 "region spans multiple files")(static_cast <bool> (SM.isWrittenInSameFile(LocStart, LocEnd
) && "region spans multiple files") ? void (0) : __assert_fail
("SM.isWrittenInSameFile(LocStart, LocEnd) && \"region spans multiple files\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 391, __extension__
__PRETTY_FUNCTION__))
;
392
393 auto CovFileID = getCoverageFileID(LocStart);
394 if (!CovFileID)
395 continue;
396 std::optional<SpellingRegion> SR;
397 if (I.isComment())
398 SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
399 I.NextTokLoc);
400 else if (I.isPPIfElse() || I.isEmptyLine())
401 SR = {SM, LocStart, LocEnd};
402
403 if (!SR)
404 continue;
405 auto Region = CounterMappingRegion::makeSkipped(
406 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
407 SR->ColumnEnd);
408 // Make sure that we only collect the regions that are inside
409 // the source code of this function.
410 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
411 Region.LineEnd <= FileLineRanges[*CovFileID].second)
412 MappingRegions.push_back(Region);
413 }
414 }
415
416 /// Generate the coverage counter mapping regions from collected
417 /// source regions.
418 void emitSourceRegions(const SourceRegionFilter &Filter) {
419 for (const auto &Region : SourceRegions) {
420 assert(Region.hasEndLoc() && "incomplete region")(static_cast <bool> (Region.hasEndLoc() && "incomplete region"
) ? void (0) : __assert_fail ("Region.hasEndLoc() && \"incomplete region\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 420, __extension__
__PRETTY_FUNCTION__))
;
421
422 SourceLocation LocStart = Region.getBeginLoc();
423 assert(SM.getFileID(LocStart).isValid() && "region in invalid file")(static_cast <bool> (SM.getFileID(LocStart).isValid() &&
"region in invalid file") ? void (0) : __assert_fail ("SM.getFileID(LocStart).isValid() && \"region in invalid file\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 423, __extension__
__PRETTY_FUNCTION__))
;
424
425 // Ignore regions from system headers unless collecting coverage from
426 // system headers is explicitly enabled.
427 if (!SystemHeadersCoverage &&
428 SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
429 continue;
430
431 auto CovFileID = getCoverageFileID(LocStart);
432 // Ignore regions that don't have a file, such as builtin macros.
433 if (!CovFileID)
434 continue;
435
436 SourceLocation LocEnd = Region.getEndLoc();
437 assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&(static_cast <bool> (SM.isWrittenInSameFile(LocStart, LocEnd
) && "region spans multiple files") ? void (0) : __assert_fail
("SM.isWrittenInSameFile(LocStart, LocEnd) && \"region spans multiple files\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 438, __extension__
__PRETTY_FUNCTION__))
438 "region spans multiple files")(static_cast <bool> (SM.isWrittenInSameFile(LocStart, LocEnd
) && "region spans multiple files") ? void (0) : __assert_fail
("SM.isWrittenInSameFile(LocStart, LocEnd) && \"region spans multiple files\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 438, __extension__
__PRETTY_FUNCTION__))
;
439
440 // Don't add code regions for the area covered by expansion regions.
441 // This not only suppresses redundant regions, but sometimes prevents
442 // creating regions with wrong counters if, for example, a statement's
443 // body ends at the end of a nested macro.
444 if (Filter.count(std::make_pair(LocStart, LocEnd)))
445 continue;
446
447 // Find the spelling locations for the mapping region.
448 SpellingRegion SR{SM, LocStart, LocEnd};
449 assert(SR.isInSourceOrder() && "region start and end out of order")(static_cast <bool> (SR.isInSourceOrder() && "region start and end out of order"
) ? void (0) : __assert_fail ("SR.isInSourceOrder() && \"region start and end out of order\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 449, __extension__
__PRETTY_FUNCTION__))
;
450
451 if (Region.isGap()) {
452 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
453 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
454 SR.LineEnd, SR.ColumnEnd));
455 } else if (Region.isBranch()) {
456 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
457 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
458 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
459 } else {
460 MappingRegions.push_back(CounterMappingRegion::makeRegion(
461 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
462 SR.LineEnd, SR.ColumnEnd));
463 }
464 }
465 }
466
467 /// Generate expansion regions for each virtual file we've seen.
468 SourceRegionFilter emitExpansionRegions() {
469 SourceRegionFilter Filter;
470 for (const auto &FM : FileIDMapping) {
471 SourceLocation ExpandedLoc = FM.second.second;
472 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
473 if (ParentLoc.isInvalid())
474 continue;
475
476 auto ParentFileID = getCoverageFileID(ParentLoc);
477 if (!ParentFileID)
478 continue;
479 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
480 assert(ExpandedFileID && "expansion in uncovered file")(static_cast <bool> (ExpandedFileID && "expansion in uncovered file"
) ? void (0) : __assert_fail ("ExpandedFileID && \"expansion in uncovered file\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 480, __extension__
__PRETTY_FUNCTION__))
;
481
482 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
483 assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&(static_cast <bool> (SM.isWrittenInSameFile(ParentLoc, LocEnd
) && "region spans multiple files") ? void (0) : __assert_fail
("SM.isWrittenInSameFile(ParentLoc, LocEnd) && \"region spans multiple files\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 484, __extension__
__PRETTY_FUNCTION__))
484 "region spans multiple files")(static_cast <bool> (SM.isWrittenInSameFile(ParentLoc, LocEnd
) && "region spans multiple files") ? void (0) : __assert_fail
("SM.isWrittenInSameFile(ParentLoc, LocEnd) && \"region spans multiple files\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 484, __extension__
__PRETTY_FUNCTION__))
;
485 Filter.insert(std::make_pair(ParentLoc, LocEnd));
486
487 SpellingRegion SR{SM, ParentLoc, LocEnd};
488 assert(SR.isInSourceOrder() && "region start and end out of order")(static_cast <bool> (SR.isInSourceOrder() && "region start and end out of order"
) ? void (0) : __assert_fail ("SR.isInSourceOrder() && \"region start and end out of order\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 488, __extension__
__PRETTY_FUNCTION__))
;
489 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
490 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
491 SR.LineEnd, SR.ColumnEnd));
492 }
493 return Filter;
494 }
495};
496
497/// Creates unreachable coverage regions for the functions that
498/// are not emitted.
499struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
500 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
501 const LangOptions &LangOpts)
502 : CoverageMappingBuilder(CVM, SM, LangOpts) {}
503
504 void VisitDecl(const Decl *D) {
505 if (!D->hasBody())
506 return;
507 auto Body = D->getBody();
508 SourceLocation Start = getStart(Body);
509 SourceLocation End = getEnd(Body);
510 if (!SM.isWrittenInSameFile(Start, End)) {
511 // Walk up to find the common ancestor.
512 // Correct the locations accordingly.
513 FileID StartFileID = SM.getFileID(Start);
514 FileID EndFileID = SM.getFileID(End);
515 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
516 Start = getIncludeOrExpansionLoc(Start);
517 assert(Start.isValid() &&(static_cast <bool> (Start.isValid() && "Declaration start location not nested within a known region"
) ? void (0) : __assert_fail ("Start.isValid() && \"Declaration start location not nested within a known region\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 518, __extension__
__PRETTY_FUNCTION__))
518 "Declaration start location not nested within a known region")(static_cast <bool> (Start.isValid() && "Declaration start location not nested within a known region"
) ? void (0) : __assert_fail ("Start.isValid() && \"Declaration start location not nested within a known region\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 518, __extension__
__PRETTY_FUNCTION__))
;
519 StartFileID = SM.getFileID(Start);
520 }
521 while (StartFileID != EndFileID) {
522 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
523 assert(End.isValid() &&(static_cast <bool> (End.isValid() && "Declaration end location not nested within a known region"
) ? void (0) : __assert_fail ("End.isValid() && \"Declaration end location not nested within a known region\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 524, __extension__
__PRETTY_FUNCTION__))
524 "Declaration end location not nested within a known region")(static_cast <bool> (End.isValid() && "Declaration end location not nested within a known region"
) ? void (0) : __assert_fail ("End.isValid() && \"Declaration end location not nested within a known region\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 524, __extension__
__PRETTY_FUNCTION__))
;
525 EndFileID = SM.getFileID(End);
526 }
527 }
528 SourceRegions.emplace_back(Counter(), Start, End);
529 }
530
531 /// Write the mapping data to the output stream
532 void write(llvm::raw_ostream &OS) {
533 SmallVector<unsigned, 16> FileIDMapping;
534 gatherFileIDs(FileIDMapping);
535 emitSourceRegions(SourceRegionFilter());
536
537 if (MappingRegions.empty())
538 return;
539
540 CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions);
541 Writer.write(OS);
542 }
543};
544
545/// A StmtVisitor that creates coverage mapping regions which map
546/// from the source code locations to the PGO counters.
547struct CounterCoverageMappingBuilder
548 : public CoverageMappingBuilder,
549 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
550 /// The map of statements to count values.
551 llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
552
553 /// A stack of currently live regions.
554 std::vector<SourceMappingRegion> RegionStack;
555
556 CounterExpressionBuilder Builder;
557
558 /// A location in the most recently visited file or macro.
559 ///
560 /// This is used to adjust the active source regions appropriately when
561 /// expressions cross file or macro boundaries.
562 SourceLocation MostRecentLocation;
563
564 /// Whether the visitor at a terminate statement.
565 bool HasTerminateStmt = false;
566
567 /// Gap region counter after terminate statement.
568 Counter GapRegionCounter;
569
570 /// Return a counter for the subtraction of \c RHS from \c LHS
571 Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) {
572 return Builder.subtract(LHS, RHS, Simplify);
573 }
574
575 /// Return a counter for the sum of \c LHS and \c RHS.
576 Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
577 return Builder.add(LHS, RHS, Simplify);
578 }
579
580 Counter addCounters(Counter C1, Counter C2, Counter C3,
581 bool Simplify = true) {
582 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
583 }
584
585 /// Return the region counter for the given statement.
586 ///
587 /// This should only be called on statements that have a dedicated counter.
588 Counter getRegionCounter(const Stmt *S) {
589 return Counter::getCounter(CounterMap[S]);
590 }
591
592 /// Push a region onto the stack.
593 ///
594 /// Returns the index on the stack where the region was pushed. This can be
595 /// used with popRegions to exit a "scope", ending the region that was pushed.
596 size_t pushRegion(Counter Count,
597 std::optional<SourceLocation> StartLoc = std::nullopt,
598 std::optional<SourceLocation> EndLoc = std::nullopt,
599 std::optional<Counter> FalseCount = std::nullopt) {
600
601 if (StartLoc && !FalseCount) {
602 MostRecentLocation = *StartLoc;
603 }
604
605 // If either of these locations is invalid, something elsewhere in the
606 // compiler has broken.
607 assert((!StartLoc || StartLoc->isValid()) && "Start location is not valid")(static_cast <bool> ((!StartLoc || StartLoc->isValid
()) && "Start location is not valid") ? void (0) : __assert_fail
("(!StartLoc || StartLoc->isValid()) && \"Start location is not valid\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 607, __extension__
__PRETTY_FUNCTION__))
;
608 assert((!EndLoc || EndLoc->isValid()) && "End location is not valid")(static_cast <bool> ((!EndLoc || EndLoc->isValid()) &&
"End location is not valid") ? void (0) : __assert_fail ("(!EndLoc || EndLoc->isValid()) && \"End location is not valid\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 608, __extension__
__PRETTY_FUNCTION__))
;
609
610 // However, we can still recover without crashing.
611 // If either location is invalid, set it to std::nullopt to avoid
612 // letting users of RegionStack think that region has a valid start/end
613 // location.
614 if (StartLoc && StartLoc->isInvalid())
615 StartLoc = std::nullopt;
616 if (EndLoc && EndLoc->isInvalid())
617 EndLoc = std::nullopt;
618 RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
619
620 return RegionStack.size() - 1;
621 }
622
623 size_t locationDepth(SourceLocation Loc) {
624 size_t Depth = 0;
625 while (Loc.isValid()) {
626 Loc = getIncludeOrExpansionLoc(Loc);
627 Depth++;
628 }
629 return Depth;
630 }
631
632 /// Pop regions from the stack into the function's list of regions.
633 ///
634 /// Adds all regions from \c ParentIndex to the top of the stack to the
635 /// function's \c SourceRegions.
636 void popRegions(size_t ParentIndex) {
637 assert(RegionStack.size() >= ParentIndex && "parent not in stack")(static_cast <bool> (RegionStack.size() >= ParentIndex
&& "parent not in stack") ? void (0) : __assert_fail
("RegionStack.size() >= ParentIndex && \"parent not in stack\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 637, __extension__
__PRETTY_FUNCTION__))
;
638 while (RegionStack.size() > ParentIndex) {
639 SourceMappingRegion &Region = RegionStack.back();
640 if (Region.hasStartLoc() &&
641 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
642 SourceLocation StartLoc = Region.getBeginLoc();
643 SourceLocation EndLoc = Region.hasEndLoc()
644 ? Region.getEndLoc()
645 : RegionStack[ParentIndex].getEndLoc();
646 bool isBranch = Region.isBranch();
647 size_t StartDepth = locationDepth(StartLoc);
648 size_t EndDepth = locationDepth(EndLoc);
649 while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
650 bool UnnestStart = StartDepth >= EndDepth;
651 bool UnnestEnd = EndDepth >= StartDepth;
652 if (UnnestEnd) {
653 // The region ends in a nested file or macro expansion. If the
654 // region is not a branch region, create a separate region for each
655 // expansion, and for all regions, update the EndLoc. Branch
656 // regions should not be split in order to keep a straightforward
657 // correspondance between the region and its associated branch
658 // condition, even if the condition spans multiple depths.
659 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
660 assert(SM.isWrittenInSameFile(NestedLoc, EndLoc))(static_cast <bool> (SM.isWrittenInSameFile(NestedLoc, EndLoc
)) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(NestedLoc, EndLoc)"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 660, __extension__
__PRETTY_FUNCTION__))
;
661
662 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
663 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
664 EndLoc);
665
666 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
667 if (EndLoc.isInvalid())
668 llvm::report_fatal_error(
669 "File exit not handled before popRegions");
670 EndDepth--;
671 }
672 if (UnnestStart) {
673 // The region ends in a nested file or macro expansion. If the
674 // region is not a branch region, create a separate region for each
675 // expansion, and for all regions, update the StartLoc. Branch
676 // regions should not be split in order to keep a straightforward
677 // correspondance between the region and its associated branch
678 // condition, even if the condition spans multiple depths.
679 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
680 assert(SM.isWrittenInSameFile(StartLoc, NestedLoc))(static_cast <bool> (SM.isWrittenInSameFile(StartLoc, NestedLoc
)) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(StartLoc, NestedLoc)"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 680, __extension__
__PRETTY_FUNCTION__))
;
681
682 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
683 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
684 NestedLoc);
685
686 StartLoc = getIncludeOrExpansionLoc(StartLoc);
687 if (StartLoc.isInvalid())
688 llvm::report_fatal_error(
689 "File exit not handled before popRegions");
690 StartDepth--;
691 }
692 }
693 Region.setStartLoc(StartLoc);
694 Region.setEndLoc(EndLoc);
695
696 if (!isBranch) {
697 MostRecentLocation = EndLoc;
698 // If this region happens to span an entire expansion, we need to
699 // make sure we don't overlap the parent region with it.
700 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
701 EndLoc == getEndOfFileOrMacro(EndLoc))
702 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
703 }
704
705 assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc))(static_cast <bool> (SM.isWrittenInSameFile(Region.getBeginLoc
(), EndLoc)) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc)"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 705, __extension__
__PRETTY_FUNCTION__))
;
706 assert(SpellingRegion(SM, Region).isInSourceOrder())(static_cast <bool> (SpellingRegion(SM, Region).isInSourceOrder
()) ? void (0) : __assert_fail ("SpellingRegion(SM, Region).isInSourceOrder()"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 706, __extension__
__PRETTY_FUNCTION__))
;
707 SourceRegions.push_back(Region);
708 }
709 RegionStack.pop_back();
710 }
711 }
712
713 /// Return the currently active region.
714 SourceMappingRegion &getRegion() {
715 assert(!RegionStack.empty() && "statement has no region")(static_cast <bool> (!RegionStack.empty() && "statement has no region"
) ? void (0) : __assert_fail ("!RegionStack.empty() && \"statement has no region\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 715, __extension__
__PRETTY_FUNCTION__))
;
716 return RegionStack.back();
717 }
718
719 /// Propagate counts through the children of \p S if \p VisitChildren is true.
720 /// Otherwise, only emit a count for \p S itself.
721 Counter propagateCounts(Counter TopCount, const Stmt *S,
722 bool VisitChildren = true) {
723 SourceLocation StartLoc = getStart(S);
12
Passing null pointer value via 1st parameter 'S'
13
Calling 'CoverageMappingBuilder::getStart'
724 SourceLocation EndLoc = getEnd(S);
725 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
726 if (VisitChildren)
727 Visit(S);
728 Counter ExitCount = getRegion().getCounter();
729 popRegions(Index);
730
731 // The statement may be spanned by an expansion. Make sure we handle a file
732 // exit out of this expansion before moving to the next statement.
733 if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
734 MostRecentLocation = EndLoc;
735
736 return ExitCount;
737 }
738
739 /// Determine whether the given condition can be constant folded.
740 bool ConditionFoldsToBool(const Expr *Cond) {
741 Expr::EvalResult Result;
742 return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
743 }
744
745 /// Create a Branch Region around an instrumentable condition for coverage
746 /// and add it to the function's SourceRegions. A branch region tracks a
747 /// "True" counter and a "False" counter for boolean expressions that
748 /// result in the generation of a branch.
749 void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
750 // Check for NULL conditions.
751 if (!C)
752 return;
753
754 // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
755 // region onto RegionStack but immediately pop it (which adds it to the
756 // function's SourceRegions) because it doesn't apply to any other source
757 // code other than the Condition.
758 if (CodeGenFunction::isInstrumentedCondition(C)) {
759 // If a condition can fold to true or false, the corresponding branch
760 // will be removed. Create a region with both counters hard-coded to
761 // zero. This allows us to visualize them in a special way.
762 // Alternatively, we can prevent any optimization done via
763 // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
764 // CodeGenFunction.c always returns false, but that is very heavy-handed.
765 if (ConditionFoldsToBool(C))
766 popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
767 Counter::getZero()));
768 else
769 // Otherwise, create a region with the True counter and False counter.
770 popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
771 }
772 }
773
774 /// Create a Branch Region around a SwitchCase for code coverage
775 /// and add it to the function's SourceRegions.
776 void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
777 Counter FalseCnt) {
778 // Push region onto RegionStack but immediately pop it (which adds it to
779 // the function's SourceRegions) because it doesn't apply to any other
780 // source other than the SwitchCase.
781 popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
782 }
783
784 /// Check whether a region with bounds \c StartLoc and \c EndLoc
785 /// is already added to \c SourceRegions.
786 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
787 bool isBranch = false) {
788 return llvm::any_of(
789 llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) {
790 return Region.getBeginLoc() == StartLoc &&
791 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
792 });
793 }
794
795 /// Adjust the most recently visited location to \c EndLoc.
796 ///
797 /// This should be used after visiting any statements in non-source order.
798 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
799 MostRecentLocation = EndLoc;
800 // The code region for a whole macro is created in handleFileExit() when
801 // it detects exiting of the virtual file of that macro. If we visited
802 // statements in non-source order, we might already have such a region
803 // added, for example, if a body of a loop is divided among multiple
804 // macros. Avoid adding duplicate regions in such case.
805 if (getRegion().hasEndLoc() &&
806 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
807 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
808 MostRecentLocation, getRegion().isBranch()))
809 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
810 }
811
812 /// Adjust regions and state when \c NewLoc exits a file.
813 ///
814 /// If moving from our most recently tracked location to \c NewLoc exits any
815 /// files, this adjusts our current region stack and creates the file regions
816 /// for the exited file.
817 void handleFileExit(SourceLocation NewLoc) {
818 if (NewLoc.isInvalid() ||
819 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
820 return;
821
822 // If NewLoc is not in a file that contains MostRecentLocation, walk up to
823 // find the common ancestor.
824 SourceLocation LCA = NewLoc;
825 FileID ParentFile = SM.getFileID(LCA);
826 while (!isNestedIn(MostRecentLocation, ParentFile)) {
827 LCA = getIncludeOrExpansionLoc(LCA);
828 if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
829 // Since there isn't a common ancestor, no file was exited. We just need
830 // to adjust our location to the new file.
831 MostRecentLocation = NewLoc;
832 return;
833 }
834 ParentFile = SM.getFileID(LCA);
835 }
836
837 llvm::SmallSet<SourceLocation, 8> StartLocs;
838 std::optional<Counter> ParentCounter;
839 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
840 if (!I.hasStartLoc())
841 continue;
842 SourceLocation Loc = I.getBeginLoc();
843 if (!isNestedIn(Loc, ParentFile)) {
844 ParentCounter = I.getCounter();
845 break;
846 }
847
848 while (!SM.isInFileID(Loc, ParentFile)) {
849 // The most nested region for each start location is the one with the
850 // correct count. We avoid creating redundant regions by stopping once
851 // we've seen this region.
852 if (StartLocs.insert(Loc).second) {
853 if (I.isBranch())
854 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
855 getEndOfFileOrMacro(Loc), I.isBranch());
856 else
857 SourceRegions.emplace_back(I.getCounter(), Loc,
858 getEndOfFileOrMacro(Loc));
859 }
860 Loc = getIncludeOrExpansionLoc(Loc);
861 }
862 I.setStartLoc(getPreciseTokenLocEnd(Loc));
863 }
864
865 if (ParentCounter) {
866 // If the file is contained completely by another region and doesn't
867 // immediately start its own region, the whole file gets a region
868 // corresponding to the parent.
869 SourceLocation Loc = MostRecentLocation;
870 while (isNestedIn(Loc, ParentFile)) {
871 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
872 if (StartLocs.insert(FileStart).second) {
873 SourceRegions.emplace_back(*ParentCounter, FileStart,
874 getEndOfFileOrMacro(Loc));
875 assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder())(static_cast <bool> (SpellingRegion(SM, SourceRegions.back
()).isInSourceOrder()) ? void (0) : __assert_fail ("SpellingRegion(SM, SourceRegions.back()).isInSourceOrder()"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 875, __extension__
__PRETTY_FUNCTION__))
;
876 }
877 Loc = getIncludeOrExpansionLoc(Loc);
878 }
879 }
880
881 MostRecentLocation = NewLoc;
882 }
883
884 /// Ensure that \c S is included in the current region.
885 void extendRegion(const Stmt *S) {
886 SourceMappingRegion &Region = getRegion();
887 SourceLocation StartLoc = getStart(S);
888
889 handleFileExit(StartLoc);
890 if (!Region.hasStartLoc())
891 Region.setStartLoc(StartLoc);
892 }
893
894 /// Mark \c S as a terminator, starting a zero region.
895 void terminateRegion(const Stmt *S) {
896 extendRegion(S);
897 SourceMappingRegion &Region = getRegion();
898 SourceLocation EndLoc = getEnd(S);
899 if (!Region.hasEndLoc())
900 Region.setEndLoc(EndLoc);
901 pushRegion(Counter::getZero());
902 HasTerminateStmt = true;
903 }
904
905 /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
906 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
907 SourceLocation BeforeLoc) {
908 // If AfterLoc is in function-like macro, use the right parenthesis
909 // location.
910 if (AfterLoc.isMacroID()) {
911 FileID FID = SM.getFileID(AfterLoc);
912 const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
913 if (EI->isFunctionMacroExpansion())
914 AfterLoc = EI->getExpansionLocEnd();
915 }
916
917 size_t StartDepth = locationDepth(AfterLoc);
918 size_t EndDepth = locationDepth(BeforeLoc);
919 while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
920 bool UnnestStart = StartDepth >= EndDepth;
921 bool UnnestEnd = EndDepth >= StartDepth;
922 if (UnnestEnd) {
923 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),(static_cast <bool> (SM.isWrittenInSameFile(getStartOfFileOrMacro
(BeforeLoc), BeforeLoc)) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), BeforeLoc)"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 924, __extension__
__PRETTY_FUNCTION__))
924 BeforeLoc))(static_cast <bool> (SM.isWrittenInSameFile(getStartOfFileOrMacro
(BeforeLoc), BeforeLoc)) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), BeforeLoc)"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 924, __extension__
__PRETTY_FUNCTION__))
;
925
926 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
927 assert(BeforeLoc.isValid())(static_cast <bool> (BeforeLoc.isValid()) ? void (0) : __assert_fail
("BeforeLoc.isValid()", "clang/lib/CodeGen/CoverageMappingGen.cpp"
, 927, __extension__ __PRETTY_FUNCTION__))
;
928 EndDepth--;
929 }
930 if (UnnestStart) {
931 assert(SM.isWrittenInSameFile(AfterLoc,(static_cast <bool> (SM.isWrittenInSameFile(AfterLoc, getEndOfFileOrMacro
(AfterLoc))) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(AfterLoc, getEndOfFileOrMacro(AfterLoc))"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 932, __extension__
__PRETTY_FUNCTION__))
932 getEndOfFileOrMacro(AfterLoc)))(static_cast <bool> (SM.isWrittenInSameFile(AfterLoc, getEndOfFileOrMacro
(AfterLoc))) ? void (0) : __assert_fail ("SM.isWrittenInSameFile(AfterLoc, getEndOfFileOrMacro(AfterLoc))"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 932, __extension__
__PRETTY_FUNCTION__))
;
933
934 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
935 assert(AfterLoc.isValid())(static_cast <bool> (AfterLoc.isValid()) ? void (0) : __assert_fail
("AfterLoc.isValid()", "clang/lib/CodeGen/CoverageMappingGen.cpp"
, 935, __extension__ __PRETTY_FUNCTION__))
;
936 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
937 assert(AfterLoc.isValid())(static_cast <bool> (AfterLoc.isValid()) ? void (0) : __assert_fail
("AfterLoc.isValid()", "clang/lib/CodeGen/CoverageMappingGen.cpp"
, 937, __extension__ __PRETTY_FUNCTION__))
;
938 StartDepth--;
939 }
940 }
941 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
942 // If the start and end locations of the gap are both within the same macro
943 // file, the range may not be in source order.
944 if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
945 return std::nullopt;
946 if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
947 !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
948 return std::nullopt;
949 return {{AfterLoc, BeforeLoc}};
950 }
951
952 /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
953 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
954 Counter Count) {
955 if (StartLoc == EndLoc)
956 return;
957 assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder())(static_cast <bool> (SpellingRegion(SM, StartLoc, EndLoc
).isInSourceOrder()) ? void (0) : __assert_fail ("SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder()"
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 957, __extension__
__PRETTY_FUNCTION__))
;
958 handleFileExit(StartLoc);
959 size_t Index = pushRegion(Count, StartLoc, EndLoc);
960 getRegion().setGap(true);
961 handleFileExit(EndLoc);
962 popRegions(Index);
963 }
964
965 /// Keep counts of breaks and continues inside loops.
966 struct BreakContinue {
967 Counter BreakCount;
968 Counter ContinueCount;
969 };
970 SmallVector<BreakContinue, 8> BreakContinueStack;
971
972 CounterCoverageMappingBuilder(
973 CoverageMappingModuleGen &CVM,
974 llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
975 const LangOptions &LangOpts)
976 : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
977
978 /// Write the mapping data to the output stream
979 void write(llvm::raw_ostream &OS) {
980 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
981 gatherFileIDs(VirtualFileMapping);
982 SourceRegionFilter Filter = emitExpansionRegions();
983 emitSourceRegions(Filter);
984 gatherSkippedRegions();
985
986 if (MappingRegions.empty())
987 return;
988
989 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
990 MappingRegions);
991 Writer.write(OS);
992 }
993
994 void VisitStmt(const Stmt *S) {
995 if (S->getBeginLoc().isValid())
996 extendRegion(S);
997 const Stmt *LastStmt = nullptr;
998 bool SaveTerminateStmt = HasTerminateStmt;
999 HasTerminateStmt = false;
1000 GapRegionCounter = Counter::getZero();
1001 for (const Stmt *Child : S->children())
1002 if (Child) {
1003 // If last statement contains terminate statements, add a gap area
1004 // between the two statements. Skipping attributed statements, because
1005 // they don't have valid start location.
1006 if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
1007 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1008 if (Gap)
1009 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1010 GapRegionCounter);
1011 SaveTerminateStmt = true;
1012 HasTerminateStmt = false;
1013 }
1014 this->Visit(Child);
1015 LastStmt = Child;
1016 }
1017 if (SaveTerminateStmt)
1018 HasTerminateStmt = true;
1019 handleFileExit(getEnd(S));
1020 }
1021
1022 void VisitDecl(const Decl *D) {
1023 Stmt *Body = D->getBody();
4
'Body' initialized here
1024
1025 // Do not propagate region counts into system headers unless collecting
1026 // coverage from system headers is explicitly enabled.
1027 if (!SystemHeadersCoverage && Body &&
5
Assuming the condition is true
6
Assuming pointer value is null
7
Assuming 'Body' is null
1028 SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
1029 return;
1030
1031 // Do not visit the artificial children nodes of defaulted methods. The
1032 // lexer may not be able to report back precise token end locations for
1033 // these children nodes (llvm.org/PR39822), and moreover users will not be
1034 // able to see coverage for them.
1035 bool Defaulted = false;
1036 if (auto *Method
8.1
'Method' is null
= dyn_cast<CXXMethodDecl>(D))
8
Assuming 'D' is not a 'CastReturnType'
9
Taking false branch
1037 Defaulted = Method->isDefaulted();
1038
1039 propagateCounts(getRegionCounter(Body), Body,
10
Passing null pointer value via 2nd parameter 'S'
11
Calling 'CounterCoverageMappingBuilder::propagateCounts'
1040 /*VisitChildren=*/!Defaulted);
1041 assert(RegionStack.empty() && "Regions entered but never exited")(static_cast <bool> (RegionStack.empty() && "Regions entered but never exited"
) ? void (0) : __assert_fail ("RegionStack.empty() && \"Regions entered but never exited\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 1041, __extension__
__PRETTY_FUNCTION__))
;
1042 }
1043
1044 void VisitReturnStmt(const ReturnStmt *S) {
1045 extendRegion(S);
1046 if (S->getRetValue())
1047 Visit(S->getRetValue());
1048 terminateRegion(S);
1049 }
1050
1051 void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
1052 extendRegion(S);
1053 Visit(S->getBody());
1054 }
1055
1056 void VisitCoreturnStmt(const CoreturnStmt *S) {
1057 extendRegion(S);
1058 if (S->getOperand())
1059 Visit(S->getOperand());
1060 terminateRegion(S);
1061 }
1062
1063 void VisitCXXThrowExpr(const CXXThrowExpr *E) {
1064 extendRegion(E);
1065 if (E->getSubExpr())
1066 Visit(E->getSubExpr());
1067 terminateRegion(E);
1068 }
1069
1070 void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
1071
1072 void VisitLabelStmt(const LabelStmt *S) {
1073 Counter LabelCount = getRegionCounter(S);
1074 SourceLocation Start = getStart(S);
1075 // We can't extendRegion here or we risk overlapping with our new region.
1076 handleFileExit(Start);
1077 pushRegion(LabelCount, Start);
1078 Visit(S->getSubStmt());
1079 }
1080
1081 void VisitBreakStmt(const BreakStmt *S) {
1082 assert(!BreakContinueStack.empty() && "break not in a loop or switch!")(static_cast <bool> (!BreakContinueStack.empty() &&
"break not in a loop or switch!") ? void (0) : __assert_fail
("!BreakContinueStack.empty() && \"break not in a loop or switch!\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 1082, __extension__
__PRETTY_FUNCTION__))
;
1083 BreakContinueStack.back().BreakCount = addCounters(
1084 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1085 // FIXME: a break in a switch should terminate regions for all preceding
1086 // case statements, not just the most recent one.
1087 terminateRegion(S);
1088 }
1089
1090 void VisitContinueStmt(const ContinueStmt *S) {
1091 assert(!BreakContinueStack.empty() && "continue stmt not in a loop!")(static_cast <bool> (!BreakContinueStack.empty() &&
"continue stmt not in a loop!") ? void (0) : __assert_fail (
"!BreakContinueStack.empty() && \"continue stmt not in a loop!\""
, "clang/lib/CodeGen/CoverageMappingGen.cpp", 1091, __extension__
__PRETTY_FUNCTION__))
;
1092 BreakContinueStack.back().ContinueCount = addCounters(
1093 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1094 terminateRegion(S);
1095 }
1096
1097 void VisitCallExpr(const CallExpr *E) {
1098 VisitStmt(E);
1099
1100 // Terminate the region when we hit a noreturn function.
1101 // (This is helpful dealing with switch statements.)
1102 QualType CalleeType = E->getCallee()->getType();
1103 if (getFunctionExtInfo(*CalleeType).getNoReturn())
1104 terminateRegion(E);
1105 }
1106
1107 void VisitWhileStmt(const WhileStmt *S) {
1108 extendRegion(S);
1109
1110 Counter ParentCount = getRegion().getCounter();
1111 Counter BodyCount = getRegionCounter(S);
1112
1113 // Handle the body first so that we can get the backedge count.
1114 BreakContinueStack.push_back(BreakContinue());
1115 extendRegion(S->getBody());
1116 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1117 BreakContinue BC = BreakContinueStack.pop_back_val();
1118
1119 bool BodyHasTerminateStmt = HasTerminateStmt;
1120 HasTerminateStmt = false;
1121
1122 // Go back to handle the condition.
1123 Counter CondCount =
1124 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1125 propagateCounts(CondCount, S->getCond());
1126 adjustForOutOfOrderTraversal(getEnd(S));
1127
1128 // The body count applies to the area immediately after the increment.
1129 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1130 if (Gap)
1131 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1132
1133 Counter OutCount =
1134 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1135 if (OutCount != ParentCount) {
1136 pushRegion(OutCount);
1137 GapRegionCounter = OutCount;
1138 if (BodyHasTerminateStmt)
1139 HasTerminateStmt = true;
1140 }
1141
1142 // Create Branch Region around condition.
1143 createBranchRegion(S->getCond(), BodyCount,
1144 subtractCounters(CondCount, BodyCount));
1145 }
1146
1147 void VisitDoStmt(const DoStmt *S) {
1148 extendRegion(S);
1149
1150 Counter ParentCount = getRegion().getCounter();
1151 Counter BodyCount = getRegionCounter(S);
1152
1153 BreakContinueStack.push_back(BreakContinue());
1154 extendRegion(S->getBody());
1155 Counter BackedgeCount =
1156 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1157 BreakContinue BC = BreakContinueStack.pop_back_val();
1158
1159 bool BodyHasTerminateStmt = HasTerminateStmt;
1160 HasTerminateStmt = false;
1161
1162 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1163 propagateCounts(CondCount, S->getCond());
1164
1165 Counter OutCount =
1166 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1167 if (OutCount != ParentCount) {
1168 pushRegion(OutCount);
1169 GapRegionCounter = OutCount;
1170 }
1171
1172 // Create Branch Region around condition.
1173 createBranchRegion(S->getCond(), BodyCount,
1174 subtractCounters(CondCount, BodyCount));
1175
1176 if (BodyHasTerminateStmt)
1177 HasTerminateStmt = true;
1178 }
1179
1180 void VisitForStmt(const ForStmt *S) {
1181 extendRegion(S);
1182 if (S->getInit())
1183 Visit(S->getInit());
1184
1185 Counter ParentCount = getRegion().getCounter();
1186 Counter BodyCount = getRegionCounter(S);
1187
1188 // The loop increment may contain a break or continue.
1189 if (S->getInc())
1190 BreakContinueStack.emplace_back();
1191
1192 // Handle the body first so that we can get the backedge count.
1193 BreakContinueStack.emplace_back();
1194 extendRegion(S->getBody());
1195 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1196 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1197
1198 bool BodyHasTerminateStmt = HasTerminateStmt;
1199 HasTerminateStmt = false;
1200
1201 // The increment is essentially part of the body but it needs to include
1202 // the count for all the continue statements.
1203 BreakContinue IncrementBC;
1204 if (const Stmt *Inc = S->getInc()) {
1205 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1206 IncrementBC = BreakContinueStack.pop_back_val();
1207 }
1208
1209 // Go back to handle the condition.
1210 Counter CondCount = addCounters(
1211 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1212 IncrementBC.ContinueCount);
1213 if (const Expr *Cond = S->getCond()) {
1214 propagateCounts(CondCount, Cond);
1215 adjustForOutOfOrderTraversal(getEnd(S));
1216 }
1217
1218 // The body count applies to the area immediately after the increment.
1219 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1220 if (Gap)
1221 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1222
1223 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1224 subtractCounters(CondCount, BodyCount));
1225 if (OutCount != ParentCount) {
1226 pushRegion(OutCount);
1227 GapRegionCounter = OutCount;
1228 if (BodyHasTerminateStmt)
1229 HasTerminateStmt = true;
1230 }
1231
1232 // Create Branch Region around condition.
1233 createBranchRegion(S->getCond(), BodyCount,
1234 subtractCounters(CondCount, BodyCount));
1235 }
1236
1237 void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
1238 extendRegion(S);
1239 if (S->getInit())
1240 Visit(S->getInit());
1241 Visit(S->getLoopVarStmt());
1242 Visit(S->getRangeStmt());
1243
1244 Counter ParentCount = getRegion().getCounter();
1245 Counter BodyCount = getRegionCounter(S);
1246
1247 BreakContinueStack.push_back(BreakContinue());
1248 extendRegion(S->getBody());
1249 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1250 BreakContinue BC = BreakContinueStack.pop_back_val();
1251
1252 bool BodyHasTerminateStmt = HasTerminateStmt;
1253 HasTerminateStmt = false;
1254
1255 // The body count applies to the area immediately after the range.
1256 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1257 if (Gap)
1258 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1259
1260 Counter LoopCount =
1261 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1262 Counter OutCount =
1263 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1264 if (OutCount != ParentCount) {
1265 pushRegion(OutCount);
1266 GapRegionCounter = OutCount;
1267 if (BodyHasTerminateStmt)
1268 HasTerminateStmt = true;
1269 }
1270
1271 // Create Branch Region around condition.
1272 createBranchRegion(S->getCond(), BodyCount,
1273 subtractCounters(LoopCount, BodyCount));
1274 }
1275
1276 void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
1277 extendRegion(S);
1278 Visit(S->getElement());
1279
1280 Counter ParentCount = getRegion().getCounter();
1281 Counter BodyCount = getRegionCounter(S);
1282
1283 BreakContinueStack.push_back(BreakContinue());
1284 extendRegion(S->getBody());
1285 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1286 BreakContinue BC = BreakContinueStack.pop_back_val();
1287
1288 // The body count applies to the area immediately after the collection.
1289 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1290 if (Gap)
1291 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1292
1293 Counter LoopCount =
1294 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1295 Counter OutCount =
1296 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1297 if (OutCount != ParentCount) {
1298 pushRegion(OutCount);
1299 GapRegionCounter = OutCount;
1300 }
1301 }
1302
1303 void VisitSwitchStmt(const SwitchStmt *S) {
1304 extendRegion(S);
1305 if (S->getInit())
1306 Visit(S->getInit());
1307 Visit(S->getCond());
1308
1309 BreakContinueStack.push_back(BreakContinue());
1310
1311 const Stmt *Body = S->getBody();
1312 extendRegion(Body);
1313 if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1314 if (!CS->body_empty()) {
1315 // Make a region for the body of the switch. If the body starts with
1316 // a case, that case will reuse this region; otherwise, this covers
1317 // the unreachable code at the beginning of the switch body.
1318 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1319 getRegion().setGap(true);
1320 Visit(Body);
1321
1322 // Set the end for the body of the switch, if it isn't already set.
1323 for (size_t i = RegionStack.size(); i != Index; --i) {
1324 if (!RegionStack[i - 1].hasEndLoc())
1325 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1326 }
1327
1328 popRegions(Index);
1329 }
1330 } else
1331 propagateCounts(Counter::getZero(), Body);
1332 BreakContinue BC = BreakContinueStack.pop_back_val();
1333
1334 if (!BreakContinueStack.empty())
1335 BreakContinueStack.back().ContinueCount = addCounters(
1336 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1337
1338 Counter ParentCount = getRegion().getCounter();
1339 Counter ExitCount = getRegionCounter(S);
1340 SourceLocation ExitLoc = getEnd(S);
1341 pushRegion(ExitCount);
1342 GapRegionCounter = ExitCount;
1343
1344 // Ensure that handleFileExit recognizes when the end location is located
1345 // in a different file.
1346 MostRecentLocation = getStart(S);
1347 handleFileExit(ExitLoc);
1348
1349 // Create a Branch Region around each Case. Subtract the case's
1350 // counter from the Parent counter to track the "False" branch count.
1351 Counter CaseCountSum;
1352 bool HasDefaultCase = false;
1353 const SwitchCase *Case = S->getSwitchCaseList();
1354 for (; Case; Case = Case->getNextSwitchCase()) {
1355 HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1356 CaseCountSum =
1357 addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false);
1358 createSwitchCaseRegion(
1359 Case, getRegionCounter(Case),
1360 subtractCounters(ParentCount, getRegionCounter(Case)));
1361 }
1362 // Simplify is skipped while building the counters above: it can get really
1363 // slow on top of switches with thousands of cases. Instead, trigger
1364 // simplification by adding zero to the last counter.
1365 CaseCountSum = addCounters(CaseCountSum, Counter::getZero());
1366
1367 // If no explicit default case exists, create a branch region to represent
1368 // the hidden branch, which will be added later by the CodeGen. This region
1369 // will be associated with the switch statement's condition.
1370 if (!HasDefaultCase) {
1371 Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1372 Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1373 createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1374 }
1375 }
1376
1377 void VisitSwitchCase(const SwitchCase *S) {
1378 extendRegion(S);
1379
1380 SourceMappingRegion &Parent = getRegion();
1381
1382 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1383 // Reuse the existing region if it starts at our label. This is typical of
1384 // the first case in a switch.
1385 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1386 Parent.setCounter(Count);
1387 else
1388 pushRegion(Count, getStart(S));
1389
1390 GapRegionCounter = Count;
1391
1392 if (const auto *CS = dyn_cast<CaseStmt>(S)) {
1393 Visit(CS->getLHS());
1394 if (const Expr *RHS = CS->getRHS())
1395 Visit(RHS);
1396 }
1397 Visit(S->getSubStmt());
1398 }
1399
1400 void VisitIfStmt(const IfStmt *S) {
1401 extendRegion(S);
1402 if (S->getInit())
1403 Visit(S->getInit());
1404
1405 // Extend into the condition before we propagate through it below - this is
1406 // needed to handle macros that generate the "if" but not the condition.
1407 if (!S->isConsteval())
1408 extendRegion(S->getCond());
1409
1410 Counter ParentCount = getRegion().getCounter();
1411 Counter ThenCount = getRegionCounter(S);
1412
1413 if (!S->isConsteval()) {
1414 // Emitting a counter for the condition makes it easier to interpret the
1415 // counter for the body when looking at the coverage.
1416 propagateCounts(ParentCount, S->getCond());
1417
1418 // The 'then' count applies to the area immediately after the condition.
1419 std::optional<SourceRange> Gap =
1420 findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
1421 if (Gap)
1422 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
1423 }
1424
1425 extendRegion(S->getThen());
1426 Counter OutCount = propagateCounts(ThenCount, S->getThen());
1427
1428 Counter ElseCount = subtractCounters(ParentCount, ThenCount);
1429 if (const Stmt *Else = S->getElse()) {
1430 bool ThenHasTerminateStmt = HasTerminateStmt;
1431 HasTerminateStmt = false;
1432 // The 'else' count applies to the area immediately after the 'then'.
1433 std::optional<SourceRange> Gap =
1434 findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
1435 if (Gap)
1436 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
1437 extendRegion(Else);
1438 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1439
1440 if (ThenHasTerminateStmt)
1441 HasTerminateStmt = true;
1442 } else
1443 OutCount = addCounters(OutCount, ElseCount);
1444
1445 if (OutCount != ParentCount) {
1446 pushRegion(OutCount);
1447 GapRegionCounter = OutCount;
1448 }
1449
1450 if (!S->isConsteval()) {
1451 // Create Branch Region around condition.
1452 createBranchRegion(S->getCond(), ThenCount,
1453 subtractCounters(ParentCount, ThenCount));
1454 }
1455 }
1456
1457 void VisitCXXTryStmt(const CXXTryStmt *S) {
1458 extendRegion(S);
1459 // Handle macros that generate the "try" but not the rest.
1460 extendRegion(S->getTryBlock());
1461
1462 Counter ParentCount = getRegion().getCounter();
1463 propagateCounts(ParentCount, S->getTryBlock());
1464
1465 for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
1466 Visit(S->getHandler(I));
1467
1468 Counter ExitCount = getRegionCounter(S);
1469 pushRegion(ExitCount);
1470 }
1471
1472 void VisitCXXCatchStmt(const CXXCatchStmt *S) {
1473 propagateCounts(getRegionCounter(S), S->getHandlerBlock());
1474 }
1475
1476 void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
1477 extendRegion(E);
1478
1479 Counter ParentCount = getRegion().getCounter();
1480 Counter TrueCount = getRegionCounter(E);
1481
1482 propagateCounts(ParentCount, E->getCond());
1483 Counter OutCount;
1484
1485 if (!isa<BinaryConditionalOperator>(E)) {
1486 // The 'then' count applies to the area immediately after the condition.
1487 auto Gap =
1488 findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
1489 if (Gap)
1490 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
1491
1492 extendRegion(E->getTrueExpr());
1493 OutCount = propagateCounts(TrueCount, E->getTrueExpr());
1494 }
1495
1496 extendRegion(E->getFalseExpr());
1497 OutCount = addCounters(
1498 OutCount, propagateCounts(subtractCounters(ParentCount, TrueCount),
1499 E->getFalseExpr()));
1500
1501 if (OutCount != ParentCount) {
1502 pushRegion(OutCount);
1503 GapRegionCounter = OutCount;
1504 }
1505
1506 // Create Branch Region around condition.
1507 createBranchRegion(E->getCond(), TrueCount,
1508 subtractCounters(ParentCount, TrueCount));
1509 }
1510
1511 void VisitBinLAnd(const BinaryOperator *E) {
1512 extendRegion(E->getLHS());
1513 propagateCounts(getRegion().getCounter(), E->getLHS());
1514 handleFileExit(getEnd(E->getLHS()));
1515
1516 // Counter tracks the right hand side of a logical and operator.
1517 extendRegion(E->getRHS());
1518 propagateCounts(getRegionCounter(E), E->getRHS());
1519
1520 // Extract the RHS's Execution Counter.
1521 Counter RHSExecCnt = getRegionCounter(E);
1522
1523 // Extract the RHS's "True" Instance Counter.
1524 Counter RHSTrueCnt = getRegionCounter(E->getRHS());
1525
1526 // Extract the Parent Region Counter.
1527 Counter ParentCnt = getRegion().getCounter();
1528
1529 // Create Branch Region around LHS condition.
1530 createBranchRegion(E->getLHS(), RHSExecCnt,
1531 subtractCounters(ParentCnt, RHSExecCnt));
1532
1533 // Create Branch Region around RHS condition.
1534 createBranchRegion(E->getRHS(), RHSTrueCnt,
1535 subtractCounters(RHSExecCnt, RHSTrueCnt));
1536 }
1537
1538 // Determine whether the right side of OR operation need to be visited.
1539 bool shouldVisitRHS(const Expr *LHS) {
1540 bool LHSIsTrue = false;
1541 bool LHSIsConst = false;
1542 if (!LHS->isValueDependent())
1543 LHSIsConst = LHS->EvaluateAsBooleanCondition(
1544 LHSIsTrue, CVM.getCodeGenModule().getContext());
1545 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
1546 }
1547
1548 void VisitBinLOr(const BinaryOperator *E) {
1549 extendRegion(E->getLHS());
1550 Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS());
1551 handleFileExit(getEnd(E->getLHS()));
1552
1553 // Counter tracks the right hand side of a logical or operator.
1554 extendRegion(E->getRHS());
1555 propagateCounts(getRegionCounter(E), E->getRHS());
1556
1557 // Extract the RHS's Execution Counter.
1558 Counter RHSExecCnt = getRegionCounter(E);
1559
1560 // Extract the RHS's "False" Instance Counter.
1561 Counter RHSFalseCnt = getRegionCounter(E->getRHS());
1562
1563 if (!shouldVisitRHS(E->getLHS())) {
1564 GapRegionCounter = OutCount;
1565 }
1566
1567 // Extract the Parent Region Counter.
1568 Counter ParentCnt = getRegion().getCounter();
1569
1570 // Create Branch Region around LHS condition.
1571 createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1572 RHSExecCnt);
1573
1574 // Create Branch Region around RHS condition.
1575 createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1576 RHSFalseCnt);
1577 }
1578
1579 void VisitLambdaExpr(const LambdaExpr *LE) {
1580 // Lambdas are treated as their own functions for now, so we shouldn't
1581 // propagate counts into them.
1582 }
1583
1584 void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) {
1585 // Just visit syntatic expression as this is what users actually write.
1586 VisitStmt(POE->getSyntacticForm());
1587 }
1588
1589 void VisitOpaqueValueExpr(const OpaqueValueExpr* OVE) {
1590 Visit(OVE->getSourceExpr());
1591 }
1592};
1593
1594} // end anonymous namespace
1595
1596static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
1597 ArrayRef<CounterExpression> Expressions,
1598 ArrayRef<CounterMappingRegion> Regions) {
1599 OS << FunctionName << ":\n";
1600 CounterMappingContext Ctx(Expressions);
1601 for (const auto &R : Regions) {
1602 OS.indent(2);
1603 switch (R.Kind) {
1604 case CounterMappingRegion::CodeRegion:
1605 break;
1606 case CounterMappingRegion::ExpansionRegion:
1607 OS << "Expansion,";
1608 break;
1609 case CounterMappingRegion::SkippedRegion:
1610 OS << "Skipped,";
1611 break;
1612 case CounterMappingRegion::GapRegion:
1613 OS << "Gap,";
1614 break;
1615 case CounterMappingRegion::BranchRegion:
1616 OS << "Branch,";
1617 break;
1618 }
1619
1620 OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
1621 << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
1622 Ctx.dump(R.Count, OS);
1623
1624 if (R.Kind == CounterMappingRegion::BranchRegion) {
1625 OS << ", ";
1626 Ctx.dump(R.FalseCount, OS);
1627 }
1628
1629 if (R.Kind == CounterMappingRegion::ExpansionRegion)
1630 OS << " (Expanded file = " << R.ExpandedFileID << ")";
1631 OS << "\n";
1632 }
1633}
1634
1635CoverageMappingModuleGen::CoverageMappingModuleGen(
1636 CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
1637 : CGM(CGM), SourceInfo(SourceInfo) {}
1638
1639std::string CoverageMappingModuleGen::getCurrentDirname() {
1640 if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty())
1641 return CGM.getCodeGenOpts().CoverageCompilationDir;
1642
1643 SmallString<256> CWD;
1644 llvm::sys::fs::current_path(CWD);
1645 return CWD.str().str();
1646}
1647
1648std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
1649 llvm::SmallString<256> Path(Filename);
1650 llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1651
1652 /// Traverse coverage prefix map in reverse order because prefix replacements
1653 /// are applied in reverse order starting from the last one when multiple
1654 /// prefix replacement options are provided.
1655 for (const auto &[From, To] :
1656 llvm::reverse(CGM.getCodeGenOpts().CoveragePrefixMap)) {
1657 if (llvm::sys::path::replace_path_prefix(Path, From, To))
1658 break;
1659 }
1660 return Path.str().str();
1661}
1662
1663static std::string getInstrProfSection(const CodeGenModule &CGM,
1664 llvm::InstrProfSectKind SK) {
1665 return llvm::getInstrProfSectionName(
1666 SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
1667}
1668
1669void CoverageMappingModuleGen::emitFunctionMappingRecord(
1670 const FunctionInfo &Info, uint64_t FilenamesRef) {
1671 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1672
1673 // Assign a name to the function record. This is used to merge duplicates.
1674 std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
1675
1676 // A dummy description for a function included-but-not-used in a TU can be
1677 // replaced by full description provided by a different TU. The two kinds of
1678 // descriptions play distinct roles: therefore, assign them different names
1679 // to prevent `linkonce_odr` merging.
1680 if (Info.IsUsed)
1681 FuncRecordName += "u";
1682
1683 // Create the function record type.
1684 const uint64_t NameHash = Info.NameHash;
1685 const uint64_t FuncHash = Info.FuncHash;
1686 const std::string &CoverageMapping = Info.CoverageMapping;
1687#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
1688 llvm::Type *FunctionRecordTypes[] = {
1689#include "llvm/ProfileData/InstrProfData.inc"
1690 };
1691 auto *FunctionRecordTy =
1692 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
1693 /*isPacked=*/true);
1694
1695 // Create the function record constant.
1696#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
1697 llvm::Constant *FunctionRecordVals[] = {
1698 #include "llvm/ProfileData/InstrProfData.inc"
1699 };
1700 auto *FuncRecordConstant =
1701 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
1702
1703 // Create the function record global.
1704 auto *FuncRecord = new llvm::GlobalVariable(
1705 CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
1706 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
1707 FuncRecordName);
1708 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
1709 FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
1710 FuncRecord->setAlignment(llvm::Align(8));
1711 if (CGM.supportsCOMDAT())
1712 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
1713
1714 // Make sure the data doesn't get deleted.
1715 CGM.addUsedGlobal(FuncRecord);
1716}
1717
1718void CoverageMappingModuleGen::addFunctionMappingRecord(
1719 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1720 const std::string &CoverageMapping, bool IsUsed) {
1721 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1722 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
1723 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
1724
1725 if (!IsUsed)
1726 FunctionNames.push_back(
1727 llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
1728
1729 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
1730 // Dump the coverage mapping data for this function by decoding the
1731 // encoded data. This allows us to dump the mapping regions which were
1732 // also processed by the CoverageMappingWriter which performs
1733 // additional minimization operations such as reducing the number of
1734 // expressions.
1735 llvm::SmallVector<std::string, 16> FilenameStrs;
1736 std::vector<StringRef> Filenames;
1737 std::vector<CounterExpression> Expressions;
1738 std::vector<CounterMappingRegion> Regions;
1739 FilenameStrs.resize(FileEntries.size() + 1);
1740 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1741 for (const auto &Entry : FileEntries) {
1742 auto I = Entry.second;
1743 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1744 }
1745 ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs);
1746 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
1747 Expressions, Regions);
1748 if (Reader.read())
1749 return;
1750 dump(llvm::outs(), NameValue, Expressions, Regions);
1751 }
1752}
1753
1754void CoverageMappingModuleGen::emit() {
1755 if (FunctionRecords.empty())
1756 return;
1757 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1758 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
1759
1760 // Create the filenames and merge them with coverage mappings
1761 llvm::SmallVector<std::string, 16> FilenameStrs;
1762 FilenameStrs.resize(FileEntries.size() + 1);
1763 // The first filename is the current working directory.
1764 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1765 for (const auto &Entry : FileEntries) {
1766 auto I = Entry.second;
1767 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1768 }
1769
1770 std::string Filenames;
1771 {
1772 llvm::raw_string_ostream OS(Filenames);
1773 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
1774 }
1775 auto *FilenamesVal =
1776 llvm::ConstantDataArray::getString(Ctx, Filenames, false);
1777 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
1778
1779 // Emit the function records.
1780 for (const FunctionInfo &Info : FunctionRecords)
1781 emitFunctionMappingRecord(Info, FilenamesRef);
1782
1783 const unsigned NRecords = 0;
1784 const size_t FilenamesSize = Filenames.size();
1785 const unsigned CoverageMappingSize = 0;
1786 llvm::Type *CovDataHeaderTypes[] = {
1787#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
1788#include "llvm/ProfileData/InstrProfData.inc"
1789 };
1790 auto CovDataHeaderTy =
1791 llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));
1792 llvm::Constant *CovDataHeaderVals[] = {
1793#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
1794#include "llvm/ProfileData/InstrProfData.inc"
1795 };
1796 auto CovDataHeaderVal =
1797 llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals));
1798
1799 // Create the coverage data record
1800 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
1801 auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes));
1802 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
1803 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals));
1804 auto CovData = new llvm::GlobalVariable(
1805 CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
1806 CovDataVal, llvm::getCoverageMappingVarName());
1807
1808 CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
1809 CovData->setAlignment(llvm::Align(8));
1810
1811 // Make sure the data doesn't get deleted.
1812 CGM.addUsedGlobal(CovData);
1813 // Create the deferred function records array
1814 if (!FunctionNames.empty()) {
1815 auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
1816 FunctionNames.size());
1817 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
1818 // This variable will *NOT* be emitted to the object file. It is used
1819 // to pass the list of names referenced to codegen.
1820 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
1821 llvm::GlobalValue::InternalLinkage, NamesArrVal,
1822 llvm::getCoverageUnusedNamesVarName());
1823 }
1824}
1825
1826unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
1827 auto It = FileEntries.find(File);
1828 if (It != FileEntries.end())
1829 return It->second;
1830 unsigned FileID = FileEntries.size() + 1;
1831 FileEntries.insert(std::make_pair(File, FileID));
1832 return FileID;
1833}
1834
1835void CoverageMappingGen::emitCounterMapping(const Decl *D,
1836 llvm::raw_ostream &OS) {
1837 assert(CounterMap)(static_cast <bool> (CounterMap) ? void (0) : __assert_fail
("CounterMap", "clang/lib/CodeGen/CoverageMappingGen.cpp", 1837
, __extension__ __PRETTY_FUNCTION__))
;
1
Assuming field 'CounterMap' is non-null
2
'?' condition is true
1838 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
1839 Walker.VisitDecl(D);
3
Calling 'CounterCoverageMappingBuilder::VisitDecl'
1840 Walker.write(OS);
1841}
1842
1843void CoverageMappingGen::emitEmptyMapping(const Decl *D,
1844 llvm::raw_ostream &OS) {
1845 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
1846 Walker.VisitDecl(D);
1847 Walker.write(OS);
1848}