@@ -433,6 +433,23 @@ class CounterExpr {
433
433
434
434
// / A region of source code that can be mapped to a counter.
435
435
class SourceMappingRegion {
436
+ public:
437
+ enum class Kind {
438
+ // / A region that is associated with an ASTNode, and defines a scope under
439
+ // / which the region is active.
440
+ Node,
441
+
442
+ // / A node region that is only present for scoping of child regions, and
443
+ // / doesn't need to be included in the resulting set of regions.
444
+ ScopingOnly,
445
+
446
+ // / A region that refines the counter of a node region. This doesn't have
447
+ // / an ASTNode of its own.
448
+ Refined,
449
+ };
450
+
451
+ private:
452
+ Kind RegionKind;
436
453
ASTNode Node;
437
454
438
455
// / The counter for an incomplete region. Note we do not store counters
@@ -445,21 +462,54 @@ class SourceMappingRegion {
445
462
// / The region's ending location.
446
463
llvm::Optional<SourceLoc> EndLoc;
447
464
448
- public:
449
- SourceMappingRegion (ASTNode Node, llvm::Optional<CounterExpr> Counter,
450
- llvm::Optional<SourceLoc> StartLoc,
451
- llvm::Optional<SourceLoc> EndLoc)
452
- : Node(Node), Counter(std::move(Counter)), StartLoc(StartLoc),
453
- EndLoc (EndLoc) {
465
+ SourceMappingRegion (Kind RegionKind, llvm::Optional<CounterExpr> Counter,
466
+ llvm::Optional<SourceLoc> StartLoc)
467
+ : RegionKind(RegionKind), Counter(Counter), StartLoc(StartLoc) {
454
468
assert ((!StartLoc || StartLoc->isValid ()) &&
455
469
" Expected start location to be valid" );
456
- assert ((!EndLoc || EndLoc->isValid ()) &&
457
- " Expected end location to be valid" );
470
+ }
471
+
472
+ SourceMappingRegion (Kind RegionKind, ASTNode Node, SourceRange Range,
473
+ const SourceManager &SM)
474
+ : RegionKind(RegionKind), Node(Node) {
475
+ assert (Range.isValid ());
476
+ StartLoc = Range.Start ;
477
+ EndLoc = Lexer::getLocForEndOfToken (SM, Range.End );
478
+ }
479
+
480
+ public:
481
+ // / Create a regular source region for an ASTNode.
482
+ static SourceMappingRegion forNode (ASTNode Node, const SourceManager &SM,
483
+ SourceRange Range = SourceRange()) {
484
+ if (Range.isInvalid ())
485
+ Range = Node.getSourceRange ();
486
+
487
+ // Note we don't store counters for nodes, as we need to be able to fix them
488
+ // up later.
489
+ return SourceMappingRegion (Kind::Node, Node, Range, SM);
490
+ }
491
+
492
+ // / Create a source region for an ASTNode that is only present for scoping of
493
+ // / child regions, and doesn't need to be included in the resulting set of
494
+ // / regions.
495
+ static SourceMappingRegion scopingOnly (ASTNode Node,
496
+ const SourceManager &SM) {
497
+ return SourceMappingRegion (Kind::ScopingOnly, Node, Node.getSourceRange (),
498
+ SM);
499
+ }
500
+
501
+ // / Create a refined region for a given counter.
502
+ static SourceMappingRegion refined (CounterExpr Counter,
503
+ llvm::Optional<SourceLoc> StartLoc) {
504
+ return SourceMappingRegion (Kind::Refined, Counter, StartLoc);
458
505
}
459
506
460
507
SourceMappingRegion (SourceMappingRegion &&Region) = default ;
461
508
SourceMappingRegion &operator =(SourceMappingRegion &&RHS) = default ;
462
509
510
+ // / Whether this region is for scoping only.
511
+ bool isForScopingOnly () const { return RegionKind == Kind::ScopingOnly; }
512
+
463
513
ASTNode getNode () const { return Node; }
464
514
465
515
CounterExpr getCounter (const llvm::DenseMap<ProfileCounterRef, CounterExpr>
@@ -867,6 +917,13 @@ struct CoverageMapping : public ASTWalker {
867
917
// / Returns the delta of the count on entering \c Node and exiting, or null if
868
918
// / there was no change.
869
919
llvm::Optional<CounterExpr> setExitCount (ASTNode Node) {
920
+ // A `try?` absorbs child error branches, so we can assume the exit count is
921
+ // the same as the entry count in that case.
922
+ // NOTE: This assumes there is no other kind of control flow that can happen
923
+ // in a nested expression, which is true today, but may not always be.
924
+ if (Node.isExpr (ExprKind::OptionalTry))
925
+ return llvm::None;
926
+
870
927
ExitCounter = getCurrentCounter ();
871
928
if (hasCounter (Node) && getRegion ().getNode () != Node)
872
929
return CounterExpr::Sub (getCounter (Node), *ExitCounter, CounterBuilder);
@@ -914,20 +971,14 @@ struct CoverageMapping : public ASTWalker {
914
971
replaceCount (Count, getEndLoc (Scope));
915
972
}
916
973
917
- // / Push a region covering \c Node onto the stack.
918
- void pushRegion (ASTNode Node, SourceRange Range = SourceRange()) {
919
- if (Range.isInvalid ())
920
- Range = Node.getSourceRange ();
921
-
922
- // Note we don't store counters for nodes, as we need to be able to fix
923
- // them up later.
924
- RegionStack.emplace_back (Node, /* Counter*/ llvm::None, Range.Start ,
925
- Lexer::getLocForEndOfToken (SM, Range.End ));
974
+ // / Push a region onto the stack.
975
+ void pushRegion (SourceMappingRegion Region) {
926
976
LLVM_DEBUG ({
927
977
llvm::dbgs () << " Pushed region: " ;
928
- RegionStack. back () .print (llvm::dbgs (), SM);
978
+ Region .print (llvm::dbgs (), SM);
929
979
llvm::dbgs () << " \n " ;
930
980
});
981
+ RegionStack.push_back (std::move (Region));
931
982
}
932
983
933
984
// / Replace the current region at \p Start with a new counter. If \p Start is
@@ -940,7 +991,7 @@ struct CoverageMapping : public ASTWalker {
940
991
if (Start && Counter.isZero ())
941
992
Start = llvm::None;
942
993
943
- RegionStack. emplace_back ( ASTNode (), Counter, Start, llvm::None );
994
+ pushRegion ( SourceMappingRegion::refined ( Counter, Start) );
944
995
}
945
996
946
997
// / Get the location for the end of the last token in \c Node.
@@ -956,6 +1007,10 @@ struct CoverageMapping : public ASTWalker {
956
1007
llvm::dbgs () << " \n " ;
957
1008
});
958
1009
1010
+ // Don't bother recording regions that are only present for scoping.
1011
+ if (Region.isForScopingOnly ())
1012
+ return ;
1013
+
959
1014
// Don't record incomplete regions.
960
1015
if (!Region.hasStartLoc ())
961
1016
return ;
@@ -1128,7 +1183,7 @@ struct CoverageMapping : public ASTWalker {
1128
1183
1129
1184
if (auto *BS = dyn_cast<BraceStmt>(S)) {
1130
1185
if (hasCounter (BS))
1131
- pushRegion (BS );
1186
+ pushRegion (SourceMappingRegion::forNode (BS, SM) );
1132
1187
1133
1188
} else if (auto *IS = dyn_cast<IfStmt>(S)) {
1134
1189
if (auto *Cond = getConditionNode (IS->getCond ()))
@@ -1222,7 +1277,7 @@ struct CoverageMapping : public ASTWalker {
1222
1277
Range = CS->getSourceRange ();
1223
1278
break ;
1224
1279
}
1225
- pushRegion (CS, Range);
1280
+ pushRegion (SourceMappingRegion::forNode ( CS, SM, Range) );
1226
1281
}
1227
1282
return Action::Continue (S);
1228
1283
}
@@ -1326,8 +1381,15 @@ struct CoverageMapping : public ASTWalker {
1326
1381
if (isa<LazyInitializerExpr>(E))
1327
1382
assignKnownCounter (E);
1328
1383
1329
- if (hasCounter (E))
1330
- pushRegion (E);
1384
+ if (hasCounter (E)) {
1385
+ pushRegion (SourceMappingRegion::forNode (E, SM));
1386
+ } else if (isa<OptionalTryExpr>(E)) {
1387
+ // If we have a `try?`, that doesn't already have a counter, record it
1388
+ // as a scoping-only region. We need it to scope child error branches,
1389
+ // but don't need it in the resulting set of regions.
1390
+ assignCounter (E, getCurrentCounter ());
1391
+ pushRegion (SourceMappingRegion::scopingOnly (E, SM));
1392
+ }
1331
1393
1332
1394
assert (!RegionStack.empty () && " Must be within a region" );
1333
1395
0 commit comments