@@ -45,10 +45,14 @@ class SourceMappingRegion {
45
45
// / \brief The region's ending location.
46
46
Optional<SourceLocation> LocEnd;
47
47
48
+ // / Whether this region should be emitted after its parent is emitted.
49
+ bool DeferRegion;
50
+
48
51
public:
49
52
SourceMappingRegion (Counter Count, Optional<SourceLocation> LocStart,
50
- Optional<SourceLocation> LocEnd)
51
- : Count(Count), LocStart(LocStart), LocEnd(LocEnd) {}
53
+ Optional<SourceLocation> LocEnd, bool DeferRegion = false )
54
+ : Count(Count), LocStart(LocStart), LocEnd(LocEnd),
55
+ DeferRegion (DeferRegion) {}
52
56
53
57
const Counter &getCounter () const { return Count; }
54
58
@@ -71,6 +75,10 @@ class SourceMappingRegion {
71
75
assert (LocEnd && " Region has no end location" );
72
76
return *LocEnd;
73
77
}
78
+
79
+ bool isDeferred () const { return DeferRegion; }
80
+
81
+ void setDeferred (bool Deferred) { DeferRegion = Deferred; }
74
82
};
75
83
76
84
// / Spelling locations for the start and end of a source region.
@@ -409,6 +417,10 @@ struct CounterCoverageMappingBuilder
409
417
// / \brief A stack of currently live regions.
410
418
std::vector<SourceMappingRegion> RegionStack;
411
419
420
+ // / The currently deferred region: its end location and count can be set once
421
+ // / its parent has been popped from the region stack.
422
+ Optional<SourceMappingRegion> DeferredRegion;
423
+
412
424
CounterExpressionBuilder Builder;
413
425
414
426
// / \brief A location in the most recently visited file or macro.
@@ -444,19 +456,60 @@ struct CounterCoverageMappingBuilder
444
456
// / used with popRegions to exit a "scope", ending the region that was pushed.
445
457
size_t pushRegion (Counter Count, Optional<SourceLocation> StartLoc = None,
446
458
Optional<SourceLocation> EndLoc = None) {
447
- if (StartLoc)
459
+ if (StartLoc) {
448
460
MostRecentLocation = *StartLoc;
461
+ completeDeferred (Count, MostRecentLocation);
462
+ }
449
463
RegionStack.emplace_back (Count, StartLoc, EndLoc);
450
464
451
465
return RegionStack.size () - 1 ;
452
466
}
453
467
468
+ // / Complete any pending deferred region by setting its end location and
469
+ // / count, and then pushing it onto the region stack.
470
+ size_t completeDeferred (Counter Count, SourceLocation DeferredEndLoc) {
471
+ size_t Index = RegionStack.size ();
472
+ if (!DeferredRegion)
473
+ return Index;
474
+
475
+ // Consume the pending region.
476
+ SourceMappingRegion DR = DeferredRegion.getValue ();
477
+ DeferredRegion = None;
478
+
479
+ // If the region ends in an expansion, find the expansion site.
480
+ if (SM.getFileID (DeferredEndLoc) != SM.getMainFileID ()) {
481
+ FileID StartFile = SM.getFileID (DR.getStartLoc ());
482
+ if (isNestedIn (DeferredEndLoc, StartFile)) {
483
+ do {
484
+ DeferredEndLoc = getIncludeOrExpansionLoc (DeferredEndLoc);
485
+ } while (StartFile != SM.getFileID (DeferredEndLoc));
486
+ }
487
+ }
488
+
489
+ // The parent of this deferred region ends where the containing decl ends,
490
+ // so the region isn't useful.
491
+ if (DR.getStartLoc () == DeferredEndLoc)
492
+ return Index;
493
+
494
+ // If we're visiting statements in non-source order (e.g switch cases or
495
+ // a loop condition) we can't construct a sensible deferred region.
496
+ if (!SpellingRegion (SM, DR.getStartLoc (), DeferredEndLoc).isInSourceOrder ())
497
+ return Index;
498
+
499
+ DR.setCounter (Count);
500
+ DR.setEndLoc (DeferredEndLoc);
501
+ handleFileExit (DeferredEndLoc);
502
+ RegionStack.push_back (DR);
503
+ return Index;
504
+ }
505
+
454
506
// / \brief Pop regions from the stack into the function's list of regions.
455
507
// /
456
508
// / Adds all regions from \c ParentIndex to the top of the stack to the
457
509
// / function's \c SourceRegions.
458
510
void popRegions (size_t ParentIndex) {
459
511
assert (RegionStack.size () >= ParentIndex && " parent not in stack" );
512
+ bool ParentOfDeferredRegion = false ;
460
513
while (RegionStack.size () > ParentIndex) {
461
514
SourceMappingRegion &Region = RegionStack.back ();
462
515
if (Region.hasStartLoc ()) {
@@ -488,9 +541,26 @@ struct CounterCoverageMappingBuilder
488
541
489
542
assert (SM.isWrittenInSameFile (Region.getStartLoc (), EndLoc));
490
543
SourceRegions.push_back (Region);
544
+
545
+ if (ParentOfDeferredRegion) {
546
+ ParentOfDeferredRegion = false ;
547
+
548
+ // If there's an existing deferred region, keep the old one, because
549
+ // it means there are two consecutive returns (or a similar pattern).
550
+ if (!DeferredRegion.hasValue () &&
551
+ // File IDs aren't gathered within macro expansions, so it isn't
552
+ // useful to try and create a deferred region inside of one.
553
+ (SM.getFileID (EndLoc) == SM.getMainFileID ()))
554
+ DeferredRegion =
555
+ SourceMappingRegion (Counter::getZero (), EndLoc, None);
556
+ }
557
+ } else if (Region.isDeferred ()) {
558
+ assert (!ParentOfDeferredRegion && " Consecutive deferred regions" );
559
+ ParentOfDeferredRegion = true ;
491
560
}
492
561
RegionStack.pop_back ();
493
562
}
563
+ assert (!ParentOfDeferredRegion && " Deferred region with no parent" );
494
564
}
495
565
496
566
// / \brief Return the currently active region.
@@ -617,6 +687,8 @@ struct CounterCoverageMappingBuilder
617
687
handleFileExit (StartLoc);
618
688
if (!Region.hasStartLoc ())
619
689
Region.setStartLoc (StartLoc);
690
+
691
+ completeDeferred (Region.getCounter (), StartLoc);
620
692
}
621
693
622
694
// / \brief Mark \c S as a terminator, starting a zero region.
@@ -626,6 +698,7 @@ struct CounterCoverageMappingBuilder
626
698
if (!Region.hasEndLoc ())
627
699
Region.setEndLoc (getEnd (S));
628
700
pushRegion (Counter::getZero ());
701
+ getRegion ().setDeferred (true );
629
702
}
630
703
631
704
// / \brief Keep counts of breaks and continues inside loops.
@@ -639,13 +712,15 @@ struct CounterCoverageMappingBuilder
639
712
CoverageMappingModuleGen &CVM,
640
713
llvm::DenseMap<const Stmt *, unsigned > &CounterMap, SourceManager &SM,
641
714
const LangOptions &LangOpts)
642
- : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
715
+ : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
716
+ DeferredRegion (None) {}
643
717
644
718
// / \brief Write the mapping data to the output stream
645
719
void write (llvm::raw_ostream &OS) {
646
720
llvm::SmallVector<unsigned , 8 > VirtualFileMapping;
647
721
gatherFileIDs (VirtualFileMapping);
648
722
SourceRegionFilter Filter = emitExpansionRegions ();
723
+ assert (!DeferredRegion && " Deferred region never completed" );
649
724
emitSourceRegions (Filter);
650
725
gatherSkippedRegions ();
651
726
@@ -667,13 +742,19 @@ struct CounterCoverageMappingBuilder
667
742
}
668
743
669
744
void VisitDecl (const Decl *D) {
745
+ assert (!DeferredRegion && " Deferred region never completed" );
746
+
670
747
Stmt *Body = D->getBody ();
671
748
672
749
// Do not propagate region counts into system headers.
673
750
if (Body && SM.isInSystemHeader (SM.getSpellingLoc (getStart (Body))))
674
751
return ;
675
752
676
- propagateCounts (getRegionCounter (Body), Body);
753
+ Counter ExitCount = propagateCounts (getRegionCounter (Body), Body);
754
+ assert (RegionStack.empty () && " Regions entered but never exited" );
755
+
756
+ // Complete any deferred regions introduced by the last statement in a decl.
757
+ popRegions (completeDeferred (ExitCount, getEnd (Body)));
677
758
}
678
759
679
760
void VisitReturnStmt (const ReturnStmt *S) {
0 commit comments