@@ -668,7 +668,10 @@ class EffectsHandlingWalker : public ASTWalker {
668668 recurse = asImpl ().checkThrow (thr);
669669 } else if (auto forEach = dyn_cast<ForEachStmt>(S)) {
670670 recurse = asImpl ().checkForEach (forEach);
671+ } else if (auto labeled = dyn_cast<LabeledConditionalStmt>(S)) {
672+ asImpl ().noteLabeledConditionalStmt (labeled);
671673 }
674+
672675 if (!recurse)
673676 return Action::SkipNode (S);
674677
@@ -690,6 +693,8 @@ class EffectsHandlingWalker : public ASTWalker {
690693 }
691694
692695 void visitExprPre (Expr *expr) { asImpl ().visitExprPre (expr); }
696+
697+ void noteLabeledConditionalStmt (LabeledConditionalStmt *stmt) { }
693698};
694699
695700// / A potential reason why something might have an effect.
@@ -3420,6 +3425,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
34203425 // / passed directly into an explicitly `@safe` function.
34213426 llvm::DenseSet<const Expr *> assumedSafeArguments;
34223427
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+
34233432 // / Tracks all of the uncovered uses of unsafe constructs based on their
34243433 // / anchor expression, so we can emit diagnostics at the end.
34253434 llvm::MapVector<Expr *, std::vector<UnsafeUse>> uncoveredUnsafeUses;
@@ -4429,7 +4438,67 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
44294438 Ctx.Diags .diagnose (E->getUnsafeLoc (), diag::no_unsafe_in_unsafe)
44304439 .fixItRemove (E->getUnsafeLoc ());
44314440 }
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+
44334502 std::pair<SourceLoc, std::string>
44344503 getFixItForUncoveredSite (const Expr *anchor, StringRef keyword) const {
44354504 SourceLoc insertLoc = anchor->getStartLoc ();
@@ -4442,13 +4511,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
44424511 insertLoc = tryExpr->getSubExpr ()->getStartLoc ();
44434512 // Supply a tailored fixIt including the identifier if we are
44444513 // 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 ());
44524518 }
44534519 return std::make_pair (insertLoc, insertText);
44544520 }
0 commit comments