@@ -290,6 +290,14 @@ static void tryDiagnoseUnnecessaryCastOverOptionSet(ASTContext &Ctx,
290
290
.fixItRemove (SourceRange (ME->getDotLoc (), E->getEndLoc ()));
291
291
}
292
292
293
+ // / Whether the given enclosing function is a "defer" body.
294
+ static bool isDefer (Optional<AnyFunctionRef> enclosingFunc) {
295
+ if (!enclosingFunc.hasValue ()) return false ;
296
+ auto *FD = dyn_cast_or_null<FuncDecl>
297
+ (enclosingFunc.getValue ().getAbstractFunctionDecl ());
298
+ return FD && FD->isDeferBody ();
299
+ }
300
+
293
301
// / Check that a labeled statement doesn't shadow another statement with the
294
302
// / same label.
295
303
static void checkLabeledStmtShadowing (
@@ -311,6 +319,104 @@ static void checkLabeledStmtShadowing(
311
319
}
312
320
}
313
321
322
+ static void
323
+ emitUnresolvedLabelDiagnostics (DiagnosticEngine &DE,
324
+ SourceLoc targetLoc, Identifier targetName,
325
+ TopCollection<unsigned , LabeledStmt *> corrections) {
326
+ // If an unresolved label was used, but we have a single correction,
327
+ // produce the specific diagnostic and fixit.
328
+ if (corrections.size () == 1 ) {
329
+ DE.diagnose (targetLoc, diag::unresolved_label_corrected,
330
+ targetName, corrections.begin ()->Value ->getLabelInfo ().Name )
331
+ .highlight (SourceRange (targetLoc))
332
+ .fixItReplace (SourceRange (targetLoc),
333
+ corrections.begin ()->Value ->getLabelInfo ().Name .str ());
334
+ DE.diagnose (corrections.begin ()->Value ->getLabelInfo ().Loc ,
335
+ diag::decl_declared_here,
336
+ corrections.begin ()->Value ->getLabelInfo ().Name );
337
+ } else {
338
+ // If we have multiple corrections or none, produce a generic diagnostic
339
+ // and all corrections available.
340
+ DE.diagnose (targetLoc, diag::unresolved_label, targetName)
341
+ .highlight (SourceRange (targetLoc));
342
+ for (auto &entry : corrections)
343
+ DE.diagnose (entry.Value ->getLabelInfo ().Loc , diag::note_typo_candidate,
344
+ entry.Value ->getLabelInfo ().Name .str ())
345
+ .fixItReplace (SourceRange (targetLoc),
346
+ entry.Value ->getLabelInfo ().Name .str ());
347
+ }
348
+ }
349
+
350
+ // / Find the target of a break statement.
351
+ // /
352
+ // / \returns the target, if one was found, or \c nullptr if no such target
353
+ // / exists.
354
+ static LabeledStmt *findBreakStmtTarget (
355
+ ASTContext &ctx, SourceFile *sourceFile, BreakStmt *breakStmt,
356
+ Optional<AnyFunctionRef> enclosingFunc) {
357
+ TopCollection<unsigned , LabeledStmt *> labelCorrections (3 );
358
+
359
+ // Pick the nearest break target that matches the specified name.
360
+ auto activeLabeledStmts = ASTScope::lookupLabeledStmts (
361
+ sourceFile, breakStmt->getStartLoc ());
362
+ if (breakStmt->getTargetName ().empty ()) {
363
+ for (auto labeledStmt : activeLabeledStmts) {
364
+ // 'break' with no label looks through non-loop structures
365
+ // except 'switch'.
366
+ if (!labeledStmt->requiresLabelOnJump ()) {
367
+ return labeledStmt;
368
+ }
369
+ }
370
+ } else {
371
+ // Scan inside out until we find something with the right label.
372
+ for (auto labeledStmt : activeLabeledStmts) {
373
+ if (breakStmt->getTargetName () == labeledStmt->getLabelInfo ().Name ) {
374
+ return labeledStmt;
375
+ }
376
+
377
+ unsigned distance =
378
+ TypeChecker::getCallEditDistance (
379
+ DeclNameRef (breakStmt->getTargetName ()),
380
+ labeledStmt->getLabelInfo ().Name ,
381
+ TypeChecker::UnreasonableCallEditDistance);
382
+ if (distance < TypeChecker::UnreasonableCallEditDistance)
383
+ labelCorrections.insert (distance, std::move (labeledStmt));
384
+ }
385
+ labelCorrections.filterMaxScoreRange (
386
+ TypeChecker::MaxCallEditDistanceFromBestCandidate);
387
+ }
388
+
389
+ // If we're in a defer, produce a tailored diagnostic.
390
+ if (isDefer (enclosingFunc)) {
391
+ ctx.Diags .diagnose (
392
+ breakStmt->getLoc (), diag::jump_out_of_defer, " break" );
393
+ return nullptr ;
394
+ }
395
+
396
+ if (breakStmt->getTargetName ().empty ()) {
397
+ // If we're dealing with an unlabeled break inside of an 'if' or 'do'
398
+ // statement, produce a more specific error.
399
+ if (llvm::any_of (activeLabeledStmts,
400
+ [&](Stmt *S) -> bool {
401
+ return isa<IfStmt>(S) || isa<DoStmt>(S);
402
+ })) {
403
+ ctx.Diags .diagnose (
404
+ breakStmt->getLoc (), diag::unlabeled_break_outside_loop);
405
+ return nullptr ;
406
+ }
407
+
408
+ // Otherwise produce a generic error.
409
+ ctx.Diags .diagnose (breakStmt->getLoc (), diag::break_outside_loop);
410
+ return nullptr ;
411
+ }
412
+
413
+ // Provide potential corrections for an incorrect label.
414
+ emitUnresolvedLabelDiagnostics (
415
+ ctx.Diags , breakStmt->getTargetLoc (), breakStmt->getTargetName (),
416
+ labelCorrections);
417
+ return nullptr ;
418
+ }
419
+
314
420
namespace {
315
421
class StmtChecker : public StmtVisitor <StmtChecker, Stmt*> {
316
422
public:
@@ -423,10 +529,7 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
423
529
// ===--------------------------------------------------------------------===//
424
530
425
531
bool isInDefer () const {
426
- if (!TheFunc.hasValue ()) return false ;
427
- auto *FD = dyn_cast_or_null<FuncDecl>
428
- (TheFunc.getValue ().getAbstractFunctionDecl ());
429
- return FD && FD->isDeferBody ();
532
+ return isDefer (TheFunc);
430
533
}
431
534
432
535
template <typename StmtTy>
@@ -739,67 +842,9 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
739
842
}
740
843
741
844
Stmt *visitBreakStmt (BreakStmt *S) {
742
- LabeledStmt *Target = nullptr ;
743
- TopCollection<unsigned , LabeledStmt *> labelCorrections (3 );
744
- // Pick the nearest break target that matches the specified name.
745
- if (S->getTargetName ().empty ()) {
746
- for (auto I = ActiveLabeledStmts.rbegin (), E = ActiveLabeledStmts.rend ();
747
- I != E; ++I) {
748
- // 'break' with no label looks through non-loop structures
749
- // except 'switch'.
750
- if (!(*I)->requiresLabelOnJump ()) {
751
- Target = *I;
752
- break ;
753
- }
754
- }
845
+ if (auto target = findBreakStmtTarget (getASTContext (), DC->getParentSourceFile (), S, TheFunc))
846
+ S->setTarget (target);
755
847
756
- } else {
757
- // Scan inside out until we find something with the right label.
758
- for (auto I = ActiveLabeledStmts.rbegin (), E = ActiveLabeledStmts.rend ();
759
- I != E; ++I) {
760
- if (S->getTargetName () == (*I)->getLabelInfo ().Name ) {
761
- Target = *I;
762
- break ;
763
- } else {
764
- unsigned distance =
765
- TypeChecker::getCallEditDistance (
766
- DeclNameRef (S->getTargetName ()), (*I)->getLabelInfo ().Name ,
767
- TypeChecker::UnreasonableCallEditDistance);
768
- if (distance < TypeChecker::UnreasonableCallEditDistance)
769
- labelCorrections.insert (distance, std::move (*I));
770
- }
771
- }
772
- labelCorrections.filterMaxScoreRange (
773
- TypeChecker::MaxCallEditDistanceFromBestCandidate);
774
- }
775
-
776
- if (!Target) {
777
- // If we're in a defer, produce a tailored diagnostic.
778
- if (isInDefer ()) {
779
- getASTContext ().Diags .diagnose (S->getLoc (),
780
- diag::jump_out_of_defer, " break" );
781
- } else if (S->getTargetName ().empty ()) {
782
- // If we're dealing with an unlabeled break inside of an 'if' or 'do'
783
- // statement, produce a more specific error.
784
- if (std::any_of (ActiveLabeledStmts.rbegin (),
785
- ActiveLabeledStmts.rend (),
786
- [&](Stmt *S) -> bool {
787
- return isa<IfStmt>(S) || isa<DoStmt>(S);
788
- })) {
789
- getASTContext ().Diags .diagnose (S->getLoc (),
790
- diag::unlabeled_break_outside_loop);
791
- } else {
792
- // Otherwise produce a generic error.
793
- getASTContext ().Diags .diagnose (S->getLoc (), diag::break_outside_loop);
794
- }
795
- } else {
796
- emitUnresolvedLabelDiagnostics (getASTContext ().Diags ,
797
- S->getTargetLoc (), S->getTargetName (),
798
- labelCorrections);
799
- }
800
- return nullptr ;
801
- }
802
- S->setTarget (Target);
803
848
return S;
804
849
}
805
850
@@ -866,34 +911,6 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
866
911
return S;
867
912
}
868
913
869
- static void
870
- emitUnresolvedLabelDiagnostics (DiagnosticEngine &DE,
871
- SourceLoc targetLoc, Identifier targetName,
872
- TopCollection<unsigned , LabeledStmt *> corrections) {
873
- // If an unresolved label was used, but we have a single correction,
874
- // produce the specific diagnostic and fixit.
875
- if (corrections.size () == 1 ) {
876
- DE.diagnose (targetLoc, diag::unresolved_label_corrected,
877
- targetName, corrections.begin ()->Value ->getLabelInfo ().Name )
878
- .highlight (SourceRange (targetLoc))
879
- .fixItReplace (SourceRange (targetLoc),
880
- corrections.begin ()->Value ->getLabelInfo ().Name .str ());
881
- DE.diagnose (corrections.begin ()->Value ->getLabelInfo ().Loc ,
882
- diag::decl_declared_here,
883
- corrections.begin ()->Value ->getLabelInfo ().Name );
884
- } else {
885
- // If we have multiple corrections or none, produce a generic diagnostic
886
- // and all corrections available.
887
- DE.diagnose (targetLoc, diag::unresolved_label, targetName)
888
- .highlight (SourceRange (targetLoc));
889
- for (auto &entry : corrections)
890
- DE.diagnose (entry.Value ->getLabelInfo ().Loc , diag::note_typo_candidate,
891
- entry.Value ->getLabelInfo ().Name .str ())
892
- .fixItReplace (SourceRange (targetLoc),
893
- entry.Value ->getLabelInfo ().Name .str ());
894
- }
895
- }
896
-
897
914
Stmt *visitFallthroughStmt (FallthroughStmt *S) {
898
915
if (!SwitchLevel) {
899
916
getASTContext ().Diags .diagnose (S->getLoc (),
0 commit comments