@@ -668,7 +668,10 @@ class EffectsHandlingWalker : public ASTWalker {
668
668
recurse = asImpl ().checkThrow (thr);
669
669
} else if (auto forEach = dyn_cast<ForEachStmt>(S)) {
670
670
recurse = asImpl ().checkForEach (forEach);
671
+ } else if (auto labeled = dyn_cast<LabeledConditionalStmt>(S)) {
672
+ asImpl ().noteLabeledConditionalStmt (labeled);
671
673
}
674
+
672
675
if (!recurse)
673
676
return Action::SkipNode (S);
674
677
@@ -690,6 +693,8 @@ class EffectsHandlingWalker : public ASTWalker {
690
693
}
691
694
692
695
void visitExprPre (Expr *expr) { asImpl ().visitExprPre (expr); }
696
+
697
+ void noteLabeledConditionalStmt (LabeledConditionalStmt *stmt) { }
693
698
};
694
699
695
700
// / A potential reason why something might have an effect.
@@ -3420,6 +3425,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3420
3425
// / passed directly into an explicitly `@safe` function.
3421
3426
llvm::DenseSet<const Expr *> assumedSafeArguments;
3422
3427
3428
+ // / Keeps track of the expressions that were synthesized as initializers for
3429
+ // / the "if let x" shorthand syntax.
3430
+ llvm::SmallPtrSet<const Expr *, 4 > synthesizedIfLetInitializers;
3431
+
3423
3432
// / Tracks all of the uncovered uses of unsafe constructs based on their
3424
3433
// / anchor expression, so we can emit diagnostics at the end.
3425
3434
llvm::MapVector<Expr *, std::vector<UnsafeUse>> uncoveredUnsafeUses;
@@ -4429,7 +4438,67 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
4429
4438
Ctx.Diags .diagnose (E->getUnsafeLoc (), diag::no_unsafe_in_unsafe)
4430
4439
.fixItRemove (E->getUnsafeLoc ());
4431
4440
}
4432
-
4441
+
4442
+ void noteLabeledConditionalStmt (LabeledConditionalStmt *stmt) {
4443
+ // Make a note of any initializers that are the synthesized right-hand side
4444
+ // for an "if let x".
4445
+ for (const auto &condition: stmt->getCond ()) {
4446
+ switch (condition.getKind ()) {
4447
+ case StmtConditionElement::CK_Availability:
4448
+ case StmtConditionElement::CK_Boolean:
4449
+ case StmtConditionElement::CK_HasSymbol:
4450
+ continue ;
4451
+
4452
+ case StmtConditionElement::CK_PatternBinding:
4453
+ break ;
4454
+ }
4455
+
4456
+ auto init = condition.getInitializer ();
4457
+ if (!init)
4458
+ continue ;
4459
+
4460
+ auto pattern = condition.getPattern ();
4461
+ if (!pattern)
4462
+ continue ;
4463
+
4464
+ auto optPattern = dyn_cast<OptionalSomePattern>(pattern);
4465
+ if (!optPattern)
4466
+ continue ;
4467
+
4468
+ auto var = optPattern->getSubPattern ()->getSingleVar ();
4469
+ if (!var)
4470
+ continue ;
4471
+
4472
+ // If the right-hand side has the same location as the variable, it was
4473
+ // synthesized.
4474
+ if (var->getLoc ().isValid () &&
4475
+ var->getLoc () == init->getStartLoc () &&
4476
+ init->getStartLoc () == init->getEndLoc ())
4477
+ synthesizedIfLetInitializers.insert (init);
4478
+ }
4479
+ }
4480
+
4481
+ // / Determine whether this is the synthesized right-hand-side when we have
4482
+ // / expanded an "if let x" into its semantic equivalent, "if let x = x".
4483
+ VarDecl *isShorthandIfLetSyntax (const Expr *expr) const {
4484
+ // Check whether this is referencing a variable.
4485
+ VarDecl *var = nullptr ;
4486
+ if (auto declRef = dyn_cast<DeclRefExpr>(expr)) {
4487
+ var = dyn_cast_or_null<VarDecl>(declRef->getDecl ());
4488
+ } else if (auto memberRef = dyn_cast<MemberRefExpr>(expr)) {
4489
+ var = dyn_cast_or_null<VarDecl>(memberRef->getMember ().getDecl ());
4490
+ }
4491
+
4492
+ if (!var)
4493
+ return nullptr ;
4494
+
4495
+ // If we identified this as one of the bindings, return the variable.
4496
+ if (synthesizedIfLetInitializers.contains (expr))
4497
+ return var;
4498
+
4499
+ return nullptr ;
4500
+ }
4501
+
4433
4502
std::pair<SourceLoc, std::string>
4434
4503
getFixItForUncoveredSite (const Expr *anchor, StringRef keyword) const {
4435
4504
SourceLoc insertLoc = anchor->getStartLoc ();
@@ -4442,13 +4511,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
4442
4511
insertLoc = tryExpr->getSubExpr ()->getStartLoc ();
4443
4512
// Supply a tailored fixIt including the identifier if we are
4444
4513
// looking at a shorthand optional binding.
4445
- } else if (anchor->isImplicit ()) {
4446
- if (auto declRef = dyn_cast<DeclRefExpr>(anchor))
4447
- if (auto var = dyn_cast_or_null<VarDecl>(declRef->getDecl ())) {
4448
- insertText = (" = " + keyword).str () + " " + var->getNameStr ().str ();
4449
- insertLoc = Lexer::getLocForEndOfToken (Ctx.Diags .SourceMgr ,
4450
- anchor->getStartLoc ());
4451
- }
4514
+ } else if (auto var = isShorthandIfLetSyntax (anchor)) {
4515
+ insertText = (" = " + keyword).str () + " " + var->getNameStr ().str ();
4516
+ insertLoc = Lexer::getLocForEndOfToken (Ctx.Diags .SourceMgr ,
4517
+ anchor->getStartLoc ());
4452
4518
}
4453
4519
return std::make_pair (insertLoc, insertText);
4454
4520
}
0 commit comments