Skip to content

Commit c6a64a9

Browse files
committed
migrator: handle function's return type changes from nonnull to nullable. rdar://47265255
Adding exclamation brings an optional type back to its original nonnull version.
1 parent ada75dc commit c6a64a9

File tree

5 files changed

+79
-2
lines changed

5 files changed

+79
-2
lines changed

lib/Migrator/APIDiffMigratorPass.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,31 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
10771077
return false;
10781078
}
10791079

1080+
void handleResultTypeChange(ValueDecl *FD, Expr *Call) {
1081+
Optional<NodeAnnotation> ChangeKind;
1082+
1083+
// look for related change item for the function decl.
1084+
for (auto Item: getRelatedDiffItems(FD)) {
1085+
if (auto *CI = dyn_cast<CommonDiffItem>(Item)) {
1086+
// check if the function's return type has been changed from nonnull
1087+
// to nullable.
1088+
if (CI->DiffKind == NodeAnnotation::WrapOptional &&
1089+
CI->getChildIndices().size() == 1 &&
1090+
CI->getChildIndices().front() == 0) {
1091+
ChangeKind = NodeAnnotation::WrapOptional;
1092+
break;
1093+
}
1094+
}
1095+
}
1096+
if (!ChangeKind.hasValue())
1097+
return;
1098+
// If a function's return type has been changed from nonnull to nullable,
1099+
// append ! to the original call expression.
1100+
if (*ChangeKind == NodeAnnotation::WrapOptional) {
1101+
Editor.insertAfterToken(Call->getSourceRange().End, "!");
1102+
}
1103+
}
1104+
10801105
bool walkToExprPre(Expr *E) override {
10811106
if (E->getSourceRange().isInvalid())
10821107
return false;
@@ -1100,6 +1125,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
11001125
handleTypeHoist(FD, CE, Args);
11011126
handleSpecialCases(FD, CE, Args);
11021127
handleStringRepresentableArg(FD, Args, CE);
1128+
handleResultTypeChange(FD, CE);
11031129
}
11041130
break;
11051131
}
@@ -1110,15 +1136,16 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
11101136
handleFunctionCallToPropertyChange(FD, DSC->getFn(), Args);
11111137
handleSpecialCases(FD, CE, Args);
11121138
handleStringRepresentableArg(FD, Args, CE);
1139+
handleResultTypeChange(FD, CE);
11131140
}
11141141
break;
11151142
}
11161143
case ExprKind::ConstructorRefCall: {
11171144
auto CCE = cast<ConstructorRefCallExpr>(Fn);
11181145
if (auto FD = CCE->getFn()->getReferencedDecl().getDecl()) {
1119-
auto *CE = CCE->getFn();
11201146
handleFuncRename(FD, CE, Args);
11211147
handleStringRepresentableArg(FD, Args, CE);
1148+
handleResultTypeChange(FD, CE);
11221149
}
11231150
break;
11241151
}

test/Migrator/Inputs/CallExpr.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[
2+
{
3+
"DiffItemKind": "CommonDiffItem",
4+
"NodeKind": "Function",
5+
"NodeAnnotation": "WrapOptional",
6+
"ChildIndex": "0",
7+
"LeftUsr": "s:6CitiesAAC1xABSi_tcfc",
8+
"LeftComment": "",
9+
"RightUsr": "",
10+
"RightComment": "",
11+
"ModuleName": "Cities"
12+
},
13+
{
14+
"DiffItemKind": "CommonDiffItem",
15+
"NodeKind": "Function",
16+
"NodeAnnotation": "WrapOptional",
17+
"ChildIndex": "0",
18+
"LeftUsr": "s:6CitiesAAC5noosaSaySDySSABGSgGyF",
19+
"LeftComment": "",
20+
"RightUsr": "",
21+
"RightComment": "",
22+
"ModuleName": "Cities"
23+
}
24+
]

test/Migrator/call_expr_result.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t.mod)
3+
// RUN: %target-swift-frontend -emit-module -o %t.mod/Cities.swiftmodule %S/Inputs/Cities.swift -module-name Cities -parse-as-library
4+
// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -disable-migrator-fixits -primary-file %s -I %t.mod -api-diff-data-file %S/Inputs/CallExpr.json -emit-migrated-file-path %t/call_expr_result.swift.result -o /dev/null
5+
// RUN: diff -u %S/call_expr_result.swift.expected %t/call_expr_result.swift.result
6+
7+
import Cities
8+
9+
func foo() {
10+
let c1 = Cities(x: 3)
11+
_ = Cities.init(x: 3)
12+
_ = c1.noosa()
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t.mod)
3+
// RUN: %target-swift-frontend -emit-module -o %t.mod/Cities.swiftmodule %S/Inputs/Cities.swift -module-name Cities -parse-as-library
4+
// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -disable-migrator-fixits -primary-file %s -I %t.mod -api-diff-data-file %S/Inputs/CallExpr.json -emit-migrated-file-path %t/call_expr_result.swift.result -o /dev/null
5+
// RUN: diff -u %S/call_expr_result.swift.expected %t/call_expr_result.swift.result
6+
7+
import Cities
8+
9+
func foo() {
10+
let c1 = Cities(x: 3)!
11+
_ = Cities.init(x: 3)!
12+
_ = c1.noosa()!
13+
}

test/Migrator/wrap_optional.swift.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import Cities
88

99
class MyCities : Cities {
10-
override init?(x: Int?) { super.init(x: x) }
10+
override init?(x: Int?) { super.init(x: x)! }
1111
override init?(y: Int) { super.init(y: y) }
1212
override func newMooloolaba(newX x: Cities?, newY y: Cities) {}
1313
override func toowoomba(x: [Cities?], y: [Cities?]) {}

0 commit comments

Comments
 (0)