@@ -2508,7 +2508,15 @@ void swift::performAbstractFuncDeclDiagnostics(TypeChecker &TC,
2508
2508
2509
2509
// / Diagnose C style for loops.
2510
2510
2511
- static Expr *endConditionValueForConvertingCStyleForLoop (const ForStmt *FS, VarDecl *loopVar) {
2511
+ namespace {
2512
+ enum class OperatorKind : char {
2513
+ Greater,
2514
+ Smaller,
2515
+ NotEqual,
2516
+ };
2517
+
2518
+ static Expr *endConditionValueForConvertingCStyleForLoop (const ForStmt *FS,
2519
+ VarDecl *loopVar, OperatorKind &OpKind) {
2512
2520
auto *Cond = FS->getCond ().getPtrOrNull ();
2513
2521
if (!Cond)
2514
2522
return nullptr ;
@@ -2527,8 +2535,15 @@ static Expr *endConditionValueForConvertingCStyleForLoop(const ForStmt *FS, VarD
2527
2535
2528
2536
// Verify that the condition is a simple != or < comparison to the loop variable.
2529
2537
auto comparisonOpName = binaryFuncExpr->getDecl ()->getNameStr ();
2530
- if (comparisonOpName != " !=" && comparisonOpName != " <" )
2538
+ if (comparisonOpName == " !=" )
2539
+ OpKind = OperatorKind::NotEqual;
2540
+ else if (comparisonOpName == " <" )
2541
+ OpKind = OperatorKind::Smaller;
2542
+ else if (comparisonOpName == " >" )
2543
+ OpKind = OperatorKind::Greater;
2544
+ else
2531
2545
return nullptr ;
2546
+
2532
2547
auto args = binaryExpr->getArg ()->getElements ();
2533
2548
auto loadExpr = dyn_cast<LoadExpr>(args[0 ]);
2534
2549
if (!loadExpr)
@@ -2541,7 +2556,9 @@ static Expr *endConditionValueForConvertingCStyleForLoop(const ForStmt *FS, VarD
2541
2556
return args[1 ];
2542
2557
}
2543
2558
2544
- static bool unaryIncrementForConvertingCStyleForLoop (const ForStmt *FS, VarDecl *loopVar) {
2559
+ static bool unaryOperatorCheckForConvertingCStyleForLoop (const ForStmt *FS,
2560
+ VarDecl *loopVar,
2561
+ StringRef OpName) {
2545
2562
auto *Increment = FS->getIncrement ().getPtrOrNull ();
2546
2563
if (!Increment)
2547
2564
return false ;
@@ -2552,19 +2569,33 @@ static bool unaryIncrementForConvertingCStyleForLoop(const ForStmt *FS, VarDecl
2552
2569
return false ;
2553
2570
auto inoutExpr = dyn_cast<InOutExpr>(unaryExpr->getArg ());
2554
2571
if (!inoutExpr)
2555
- return false ;
2572
+ return false ;
2556
2573
auto incrementDeclRefExpr = dyn_cast<DeclRefExpr>(inoutExpr->getSubExpr ());
2557
2574
if (!incrementDeclRefExpr)
2558
2575
return false ;
2559
2576
auto unaryFuncExpr = dyn_cast<DeclRefExpr>(unaryExpr->getFn ());
2560
2577
if (!unaryFuncExpr)
2561
2578
return false ;
2562
- if (unaryFuncExpr->getDecl ()->getNameStr () != " ++ " )
2579
+ if (unaryFuncExpr->getDecl ()->getNameStr () != OpName )
2563
2580
return false ;
2564
- return incrementDeclRefExpr->getDecl () == loopVar;
2581
+ return incrementDeclRefExpr->getDecl () == loopVar;
2565
2582
}
2566
2583
2567
- static bool plusEqualOneIncrementForConvertingCStyleForLoop (TypeChecker &TC, const ForStmt *FS, VarDecl *loopVar) {
2584
+
2585
+ static bool unaryIncrementForConvertingCStyleForLoop (const ForStmt *FS,
2586
+ VarDecl *loopVar) {
2587
+ return unaryOperatorCheckForConvertingCStyleForLoop (FS, loopVar, " ++" );
2588
+ }
2589
+
2590
+ static bool unaryDecrementForConvertingCStyleForLoop (const ForStmt *FS,
2591
+ VarDecl *loopVar) {
2592
+ return unaryOperatorCheckForConvertingCStyleForLoop (FS, loopVar, " --" );
2593
+ }
2594
+
2595
+ static bool binaryOperatorCheckForConvertingCStyleForLoop (TypeChecker &TC,
2596
+ const ForStmt *FS,
2597
+ VarDecl *loopVar,
2598
+ StringRef OpName) {
2568
2599
auto *Increment = FS->getIncrement ().getPtrOrNull ();
2569
2600
if (!Increment)
2570
2601
return false ;
@@ -2574,7 +2605,7 @@ static bool plusEqualOneIncrementForConvertingCStyleForLoop(TypeChecker &TC, con
2574
2605
auto binaryFuncExpr = dyn_cast<DeclRefExpr>(binaryExpr->getFn ());
2575
2606
if (!binaryFuncExpr)
2576
2607
return false ;
2577
- if (binaryFuncExpr->getDecl ()->getNameStr () != " += " )
2608
+ if (binaryFuncExpr->getDecl ()->getNameStr () != OpName )
2578
2609
return false ;
2579
2610
auto argTupleExpr = dyn_cast<TupleExpr>(binaryExpr->getArg ());
2580
2611
if (!argTupleExpr)
@@ -2595,6 +2626,19 @@ static bool plusEqualOneIncrementForConvertingCStyleForLoop(TypeChecker &TC, con
2595
2626
if (!declRefExpr)
2596
2627
return false ;
2597
2628
return declRefExpr->getDecl () == loopVar;
2629
+
2630
+ }
2631
+
2632
+ static bool plusEqualOneIncrementForConvertingCStyleForLoop (TypeChecker &TC,
2633
+ const ForStmt *FS,
2634
+ VarDecl *loopVar) {
2635
+ return binaryOperatorCheckForConvertingCStyleForLoop (TC, FS, loopVar, " +=" );
2636
+ }
2637
+
2638
+ static bool minusEqualOneDecrementForConvertingCStyleForLoop (TypeChecker &TC,
2639
+ const ForStmt *FS,
2640
+ VarDecl *loopVar) {
2641
+ return binaryOperatorCheckForConvertingCStyleForLoop (TC, FS, loopVar, " -=" );
2598
2642
}
2599
2643
2600
2644
static void checkCStyleForLoop (TypeChecker &TC, const ForStmt *FS) {
@@ -2616,13 +2660,18 @@ static void checkCStyleForLoop(TypeChecker &TC, const ForStmt *FS) {
2616
2660
2617
2661
VarDecl *loopVar = dyn_cast<VarDecl>(initializers[1 ]);
2618
2662
Expr *startValue = loopVarDecl->getInit (0 );
2619
- Expr *endValue = endConditionValueForConvertingCStyleForLoop (FS, loopVar);
2663
+ OperatorKind OpKind;
2664
+ Expr *endValue = endConditionValueForConvertingCStyleForLoop (FS, loopVar, OpKind);
2620
2665
bool strideByOne = unaryIncrementForConvertingCStyleForLoop (FS, loopVar) ||
2621
2666
plusEqualOneIncrementForConvertingCStyleForLoop (TC, FS, loopVar);
2667
+ bool strideBackByOne = unaryDecrementForConvertingCStyleForLoop (FS, loopVar) ||
2668
+ minusEqualOneDecrementForConvertingCStyleForLoop (TC, FS, loopVar);
2622
2669
2623
- if (!loopVar || !startValue || !endValue || !strideByOne)
2670
+ if (!loopVar || !startValue || !endValue || ( !strideByOne && !strideBackByOne) )
2624
2671
return ;
2625
-
2672
+
2673
+ assert (strideBackByOne != strideByOne && " cannot be both increment and decrement." );
2674
+
2626
2675
// Verify that the loop variable is invariant inside the body.
2627
2676
VarDeclUsageChecker checker (TC, loopVar);
2628
2677
checker.suppressDiagnostics ();
@@ -2639,15 +2688,31 @@ static void checkCStyleForLoop(TypeChecker &TC, const ForStmt *FS) {
2639
2688
SourceLoc endOfIncrementLoc =
2640
2689
Lexer::getLocForEndOfToken (TC.Context .SourceMgr ,
2641
2690
FS->getIncrement ().getPtrOrNull ()->getEndLoc ());
2642
-
2643
- diagnostic
2644
- .fixItRemoveChars (loopVarDecl->getLoc (), loopVar->getLoc ())
2645
- .fixItReplaceChars (loopPatternEnd, startValue->getStartLoc (), " in " )
2646
- .fixItReplaceChars (FS->getFirstSemicolonLoc (), endValue->getStartLoc (),
2647
- " ..< " )
2648
- .fixItRemoveChars (FS->getSecondSemicolonLoc (), endOfIncrementLoc);
2649
- }
2650
2691
2692
+ if (strideByOne && OpKind != OperatorKind::Greater) {
2693
+ diagnostic
2694
+ .fixItRemoveChars (loopVarDecl->getLoc (), loopVar->getLoc ())
2695
+ .fixItReplaceChars (loopPatternEnd, startValue->getStartLoc (), " in " )
2696
+ .fixItReplaceChars (FS->getFirstSemicolonLoc (), endValue->getStartLoc (),
2697
+ " ..< " )
2698
+ .fixItRemoveChars (FS->getSecondSemicolonLoc (), endOfIncrementLoc);
2699
+ return ;
2700
+ } else if (strideBackByOne && OpKind != OperatorKind::Smaller) {
2701
+ SourceLoc startValueEnd = Lexer::getLocForEndOfToken (TC.Context .SourceMgr ,
2702
+ startValue->getEndLoc ());
2703
+
2704
+ StringRef endValueStr = CharSourceRange (TC.Context .SourceMgr , endValue->getStartLoc (),
2705
+ Lexer::getLocForEndOfToken (TC.Context .SourceMgr , endValue->getEndLoc ())).str ();
2706
+
2707
+ diagnostic
2708
+ .fixItRemoveChars (loopVarDecl->getLoc (), loopVar->getLoc ())
2709
+ .fixItReplaceChars (loopPatternEnd, startValue->getStartLoc (), " in " )
2710
+ .fixItInsert (startValue->getStartLoc (), (llvm::Twine (" ((" ) + endValueStr + " + 1)..." ).str ())
2711
+ .fixItInsert (startValueEnd, " ).reversed()" )
2712
+ .fixItRemoveChars (FS->getFirstSemicolonLoc (), endOfIncrementLoc);
2713
+ }
2714
+ }
2715
+ }// Anonymous namespace end.
2651
2716
2652
2717
// Perform MiscDiagnostics on Switch Statements.
2653
2718
static void checkSwitch (TypeChecker &TC, const SwitchStmt *stmt) {
0 commit comments