@@ -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.
@@ -3416,6 +3421,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3416
3421
// / passed directly into an explicitly `@safe` function.
3417
3422
llvm::DenseSet<const Expr *> assumedSafeArguments;
3418
3423
3424
+ // / Keeps track of the expressions that were synthesized as initializers for
3425
+ // / the "if let x" shorthand syntax.
3426
+ llvm::SmallPtrSet<const Expr *, 4 > synthesizedIfLetInitializers;
3427
+
3419
3428
// / Tracks all of the uncovered uses of unsafe constructs based on their
3420
3429
// / anchor expression, so we can emit diagnostics at the end.
3421
3430
llvm::MapVector<Expr *, std::vector<UnsafeUse>> uncoveredUnsafeUses;
@@ -4425,7 +4434,67 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
4425
4434
Ctx.Diags .diagnose (E->getUnsafeLoc (), diag::no_unsafe_in_unsafe)
4426
4435
.fixItRemove (E->getUnsafeLoc ());
4427
4436
}
4428
-
4437
+
4438
+ void noteLabeledConditionalStmt (LabeledConditionalStmt *stmt) {
4439
+ // Make a note of any initializers that are the synthesized right-hand side
4440
+ // for an "if let x".
4441
+ for (const auto &condition: stmt->getCond ()) {
4442
+ switch (condition.getKind ()) {
4443
+ case StmtConditionElement::CK_Availability:
4444
+ case StmtConditionElement::CK_Boolean:
4445
+ case StmtConditionElement::CK_HasSymbol:
4446
+ continue ;
4447
+
4448
+ case StmtConditionElement::CK_PatternBinding:
4449
+ break ;
4450
+ }
4451
+
4452
+ auto init = condition.getInitializer ();
4453
+ if (!init)
4454
+ continue ;
4455
+
4456
+ auto pattern = condition.getPattern ();
4457
+ if (!pattern)
4458
+ continue ;
4459
+
4460
+ auto optPattern = dyn_cast<OptionalSomePattern>(pattern);
4461
+ if (!optPattern)
4462
+ continue ;
4463
+
4464
+ auto var = optPattern->getSubPattern ()->getSingleVar ();
4465
+ if (!var)
4466
+ continue ;
4467
+
4468
+ // If the right-hand side has the same location as the variable, it was
4469
+ // synthesized.
4470
+ if (var->getLoc ().isValid () &&
4471
+ var->getLoc () == init->getStartLoc () &&
4472
+ init->getStartLoc () == init->getEndLoc ())
4473
+ synthesizedIfLetInitializers.insert (init);
4474
+ }
4475
+ }
4476
+
4477
+ // / Determine whether this is the synthesized right-hand-side when we have
4478
+ // / expanded an "if let x" into its semantic equivalent, "if let x = x".
4479
+ VarDecl *isShorthandIfLetSyntax (const Expr *expr) const {
4480
+ // Check whether this is referencing a variable.
4481
+ VarDecl *var = nullptr ;
4482
+ if (auto declRef = dyn_cast<DeclRefExpr>(expr)) {
4483
+ var = dyn_cast_or_null<VarDecl>(declRef->getDecl ());
4484
+ } else if (auto memberRef = dyn_cast<MemberRefExpr>(expr)) {
4485
+ var = dyn_cast_or_null<VarDecl>(memberRef->getMember ().getDecl ());
4486
+ }
4487
+
4488
+ if (!var)
4489
+ return nullptr ;
4490
+
4491
+ // If we identified this as one of the bindings, return the variable.
4492
+ if (synthesizedIfLetInitializers.contains (expr))
4493
+ return var;
4494
+
4495
+ return nullptr ;
4496
+ }
4497
+
4429
4498
std::pair<SourceLoc, std::string>
4430
4499
getFixItForUncoveredSite (const Expr *anchor, StringRef keyword) const {
4431
4500
SourceLoc insertLoc = anchor->getStartLoc ();
@@ -4438,13 +4507,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
4438
4507
insertLoc = tryExpr->getSubExpr ()->getStartLoc ();
4439
4508
// Supply a tailored fixIt including the identifier if we are
4440
4509
// looking at a shorthand optional binding.
4441
- } else if (anchor->isImplicit ()) {
4442
- if (auto declRef = dyn_cast<DeclRefExpr>(anchor))
4443
- if (auto var = dyn_cast_or_null<VarDecl>(declRef->getDecl ())) {
4444
- insertText = (" = " + keyword).str () + " " + var->getNameStr ().str ();
4445
- insertLoc = Lexer::getLocForEndOfToken (Ctx.Diags .SourceMgr ,
4446
- anchor->getStartLoc ());
4447
- }
4510
+ } else if (auto var = isShorthandIfLetSyntax (anchor)) {
4511
+ insertText = (" = " + keyword).str () + " " + var->getNameStr ().str ();
4512
+ insertLoc = Lexer::getLocForEndOfToken (Ctx.Diags .SourceMgr ,
4513
+ anchor->getStartLoc ());
4448
4514
}
4449
4515
return std::make_pair (insertLoc, insertText);
4450
4516
}
0 commit comments