@@ -76,53 +76,94 @@ class ShorthandFinder: public ASTWalker {
76
76
77
77
struct TupleSplatMigratorPass : public ASTMigratorPass ,
78
78
public SourceEntityWalker {
79
-
80
- bool handleClosureShorthandMismatch (FunctionConversionExpr *FC) {
81
- if (!SF->getASTContext ().LangOpts .isSwiftVersion3 () || !FC->isImplicit () ||
82
- !isa<ClosureExpr>(FC->getSubExpr ())) {
83
- return false ;
79
+
80
+ llvm::DenseSet<FunctionConversionExpr*> CallArgFuncConversions;
81
+
82
+ void blacklistFuncConversionArgs (CallExpr *CE) {
83
+ if (CE->isImplicit () || !SF->getASTContext ().LangOpts .isSwiftVersion3 ())
84
+ return ;
85
+
86
+ Expr *Arg = CE->getArg ();
87
+ if (auto *Shuffle = dyn_cast<TupleShuffleExpr>(Arg))
88
+ Arg = Shuffle->getSubExpr ();
89
+
90
+ if (auto *Paren = dyn_cast<ParenExpr>(Arg)) {
91
+ if (auto FC = dyn_cast_or_null<FunctionConversionExpr>(Paren->getSubExpr ()))
92
+ CallArgFuncConversions.insert (FC);
93
+ } else if (auto *Tuple = dyn_cast<TupleExpr>(Arg)){
94
+ for (auto Elem : Tuple->getElements ()) {
95
+ if (auto *FC = dyn_cast_or_null<FunctionConversionExpr>(Elem))
96
+ CallArgFuncConversions.insert (FC);
97
+ }
98
+ }
99
+ }
100
+
101
+ ClosureExpr *getShorthandClosure (Expr *E) {
102
+ if (auto *Closure = dyn_cast_or_null<ClosureExpr>(E)) {
103
+ if (Closure->hasAnonymousClosureVars ())
104
+ return Closure;
84
105
}
106
+ return nullptr ;
107
+ }
108
+
109
+ bool handleClosureShorthandMismatch (const FunctionConversionExpr *FC) {
110
+ if (!SF->getASTContext ().LangOpts .isSwiftVersion3 () || !FC->isImplicit ())
111
+ return false ;
85
112
86
- auto *Closure = cast<ClosureExpr> (FC->getSubExpr ());
87
- if (Closure-> getInLoc (). isValid () )
113
+ ClosureExpr *Closure = getShorthandClosure (FC->getSubExpr ());
114
+ if (! Closure)
88
115
return false ;
89
116
90
117
FunctionType *FuncTy = FC->getType ()->getAs <FunctionType>();
91
118
92
119
unsigned NativeArity = FuncTy->getParams ().size ();
93
120
unsigned ClosureArity = Closure->getParameters ()->size ();
94
- if (NativeArity < = ClosureArity)
121
+ if (NativeArity = = ClosureArity)
95
122
return false ;
96
123
97
- ShorthandFinder Finder (Closure);
98
-
99
124
if (ClosureArity == 1 && NativeArity > 1 ) {
100
125
// Remove $0. from existing references or if it's only $0, replace it
101
126
// with a tuple of the native arity, e.g. ($0, $1, $2)
102
- Finder.forEachReference ([this , NativeArity](Expr *Ref, ParamDecl *Def) {
103
- if (auto *TE = dyn_cast<TupleElementExpr>(Ref)) {
104
- SourceLoc Start = TE->getStartLoc ();
105
- SourceLoc End = TE->getLoc ();
106
- Editor.replace (CharSourceRange (SM, Start, End), " $" );
107
- } else {
108
- std::string TupleText;
109
- {
110
- llvm::raw_string_ostream OS (TupleText);
111
- for (size_t i = 1 ; i < NativeArity; ++i) {
112
- OS << " , $" << i;
127
+ ShorthandFinder (Closure)
128
+ .forEachReference ([this , NativeArity](Expr *Ref, ParamDecl *Def) {
129
+ if (auto *TE = dyn_cast<TupleElementExpr>(Ref)) {
130
+ SourceLoc Start = TE->getStartLoc ();
131
+ SourceLoc End = TE->getLoc ();
132
+ Editor.replace (CharSourceRange (SM, Start, End), " $" );
133
+ } else {
134
+ std::string TupleText;
135
+ {
136
+ llvm::raw_string_ostream OS (TupleText);
137
+ for (size_t i = 1 ; i < NativeArity; ++i) {
138
+ OS << " , $" << i;
139
+ }
140
+ OS << " )" ;
113
141
}
114
- OS << " )" ;
142
+ Editor.insert (Ref->getStartLoc (), " (" );
143
+ Editor.insertAfterToken (Ref->getEndLoc (), TupleText);
115
144
}
116
- Editor.insert (Ref->getStartLoc (), " (" );
117
- Editor.insertAfterToken (Ref->getEndLoc (), TupleText);
118
- }
119
- });
145
+ });
146
+ return true ;
147
+ }
148
+
149
+ // This direction is only needed if not passed as a call argument. e.g.
150
+ // someFunc({ $0 > $1 }) // doesn't need migration
151
+ // let x: ((Int, Int)) -> Bool = { $0 > $1 } // needs migration
152
+ if (NativeArity == 1 && ClosureArity > 1 && !CallArgFuncConversions.count (FC)) {
153
+ // Prepend $0. to existing references
154
+ ShorthandFinder (Closure)
155
+ .forEachReference ([this ](Expr *Ref, ParamDecl *Def) {
156
+ if (auto *TE = dyn_cast<TupleElementExpr>(Ref))
157
+ Ref = TE->getBase ();
158
+ SourceLoc AfterDollar = Ref->getStartLoc ().getAdvancedLoc (1 );
159
+ Editor.insert (AfterDollar, " 0." );
160
+ });
120
161
return true ;
121
162
}
122
163
return false ;
123
164
}
124
165
125
- // / Migrates code that compiles fine in Swift 3 but breaks in Swift 4 due to
166
+ // / Migrates code that compiles fine in Swift 3 but breaks in Swift 4 due to
126
167
// / changes in how the typechecker handles tuple arguments.
127
168
void handleTupleArgumentMismatches (const CallExpr *E) {
128
169
if (!SF->getASTContext ().LangOpts .isSwiftVersion3 ())
@@ -169,6 +210,7 @@ struct TupleSplatMigratorPass : public ASTMigratorPass,
169
210
if (auto *FCE = dyn_cast<FunctionConversionExpr>(E)) {
170
211
handleClosureShorthandMismatch (FCE);
171
212
} else if (auto *CE = dyn_cast<CallExpr>(E)) {
213
+ blacklistFuncConversionArgs (CE);
172
214
handleTupleArgumentMismatches (CE);
173
215
}
174
216
return true ;
0 commit comments