@@ -196,6 +196,13 @@ static bool skipExpr(Expr *E) {
196
196
return !E->getStartLoc ().isValid () || !E->getEndLoc ().isValid ();
197
197
}
198
198
199
+ // / Whether the children of an unmapped decl should still be walked.
200
+ static bool shouldWalkUnmappedDecl (const Decl *D) {
201
+ // We want to walk into the initializer for a pattern binding decl. This
202
+ // allows us to map LazyInitializerExprs.
203
+ return isa<PatternBindingDecl>(D);
204
+ }
205
+
199
206
// / An ASTWalker that maps ASTNodes to profiling counters.
200
207
struct MapRegionCounters : public ASTWalker {
201
208
// / The next counter value to assign.
@@ -207,6 +214,12 @@ struct MapRegionCounters : public ASTWalker {
207
214
MapRegionCounters (llvm::DenseMap<ASTNode, unsigned > &CounterMap)
208
215
: CounterMap(CounterMap) {}
209
216
217
+ LazyInitializerWalking getLazyInitializerWalkingBehavior () override {
218
+ // We want to walk lazy initializers present in the synthesized getter for
219
+ // a lazy variable.
220
+ return LazyInitializerWalking::InAccessor;
221
+ }
222
+
210
223
void mapRegion (ASTNode N) {
211
224
CounterMap[N] = NextCounter;
212
225
@@ -225,7 +238,7 @@ struct MapRegionCounters : public ASTWalker {
225
238
226
239
bool walkToDeclPre (Decl *D) override {
227
240
if (isUnmapped (D))
228
- return false ;
241
+ return shouldWalkUnmappedDecl (D) ;
229
242
230
243
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
231
244
return visitFunctionDecl (*this , AFD, [&] { mapRegion (AFD->getBody ()); });
@@ -274,14 +287,8 @@ struct MapRegionCounters : public ASTWalker {
274
287
mapRegion (IE->getThenExpr ());
275
288
}
276
289
277
- // rdar://42792053
278
- // TODO: There's an outstanding issue here with LazyInitializerExpr. A LIE
279
- // is copied into the body of a property getter after type-checking (before
280
- // coverage). ASTWalker only visits this expression once via the property's
281
- // VarDecl, and does not visit it again within the getter. This results in
282
- // missing coverage. SILGen treats the init expr as part of the getter, but
283
- // its SILProfiler has no information about the init because the LIE isn't
284
- // visited here.
290
+ if (isa<LazyInitializerExpr>(E))
291
+ mapRegion (E);
285
292
286
293
return {true , E};
287
294
}
@@ -579,7 +586,7 @@ struct PGOMapping : public ASTWalker {
579
586
580
587
bool walkToDeclPre (Decl *D) override {
581
588
if (isUnmapped (D))
582
- return false ;
589
+ return shouldWalkUnmappedDecl (D) ;
583
590
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
584
591
return visitFunctionDecl (*this , AFD, [&] {
585
592
setKnownExecutionCount (AFD->getBody ());
@@ -591,6 +598,12 @@ struct PGOMapping : public ASTWalker {
591
598
return true ;
592
599
}
593
600
601
+ LazyInitializerWalking getLazyInitializerWalkingBehavior () override {
602
+ // We want to walk lazy initializers present in the synthesized getter for
603
+ // a lazy variable.
604
+ return LazyInitializerWalking::InAccessor;
605
+ }
606
+
594
607
std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
595
608
unsigned parent = getParentCounter ();
596
609
auto parentCount = LoadedCounts.Counts [parent];
@@ -674,6 +687,9 @@ struct PGOMapping : public ASTWalker {
674
687
}
675
688
setExecutionCount (elseExpr, subtract (count, thenCount));
676
689
}
690
+ if (isa<LazyInitializerExpr>(E))
691
+ setKnownExecutionCount (E);
692
+
677
693
return {true , E};
678
694
}
679
695
};
@@ -903,6 +919,12 @@ struct CoverageMapping : public ASTWalker {
903
919
public:
904
920
CoverageMapping (const SourceManager &SM) : SM(SM) {}
905
921
922
+ LazyInitializerWalking getLazyInitializerWalkingBehavior () override {
923
+ // We want to walk lazy initializers present in the synthesized getter for
924
+ // a lazy variable.
925
+ return LazyInitializerWalking::InAccessor;
926
+ }
927
+
906
928
// / Generate the coverage counter mapping regions from collected
907
929
// / source regions.
908
930
SILCoverageMap *emitSourceRegions (
@@ -930,7 +952,7 @@ struct CoverageMapping : public ASTWalker {
930
952
931
953
bool walkToDeclPre (Decl *D) override {
932
954
if (isUnmapped (D))
933
- return false ;
955
+ return shouldWalkUnmappedDecl (D) ;
934
956
935
957
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
936
958
return visitFunctionDecl (*this , AFD, [&] {
@@ -1124,6 +1146,9 @@ struct CoverageMapping : public ASTWalker {
1124
1146
}
1125
1147
}
1126
1148
1149
+ if (isa<LazyInitializerExpr>(E))
1150
+ assignCounter (E);
1151
+
1127
1152
if (hasCounter (E) && !Parent.isNull ())
1128
1153
pushRegion (E);
1129
1154
return {true , E};
0 commit comments