Skip to content

Commit 8297d75

Browse files
authored
Merge pull request #17894 from nkcsgexi/41828411-4.2
[4.2] migrator: handle changed parameter declarations by introducing bridging local variables.
2 parents 4275fd1 + 6e721b7 commit 8297d75

File tree

5 files changed

+182
-70
lines changed

5 files changed

+182
-70
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4830,6 +4830,9 @@ class ParamDecl : public VarDecl {
48304830
/// Retrieve the argument (API) name for this function parameter.
48314831
Identifier getArgumentName() const { return ArgumentName; }
48324832

4833+
/// Retrieve the parameter (local) name for this function parameter.
4834+
Identifier getParameterName() const { return getName(); }
4835+
48334836
/// Retrieve the source location of the argument (API) name.
48344837
///
48354838
/// The resulting source location will be valid if the argument name

lib/Migrator/APIDiffMigratorPass.cpp

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,27 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
404404
InsertedFunctions.insert(FD->getBaseName().getIdentifier().str());
405405
}
406406
}
407+
408+
// Handle helper functions without wrappees first.
409+
for (auto &Cur: HelperFuncInfo) {
410+
if (Cur.ExpressionToWrap)
411+
continue;
412+
auto FuncName = Cur.getFuncName();
413+
// Avoid inserting the helper function if it's already present.
414+
if (!InsertedFunctions.count(FuncName)) {
415+
Editor.insert(FileEndLoc, Cur.getFuncDef());
416+
InsertedFunctions.insert(FuncName);
417+
}
418+
}
419+
420+
// Remove all helper functions that're without expressions to wrap.
421+
HelperFuncInfo.erase(std::remove_if(HelperFuncInfo.begin(),
422+
HelperFuncInfo.end(), [](const ConversionFunctionInfo& Info) {
423+
return !Info.ExpressionToWrap;
424+
}), HelperFuncInfo.end());
425+
407426
for (auto &Cur: HelperFuncInfo) {
427+
assert(Cur.ExpressionToWrap);
408428
// Avoid wrapping nil expression.
409429
if (isNilExpr(Cur.ExpressionToWrap))
410430
continue;
@@ -885,9 +905,11 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
885905
return wrapAttributeReference(E, E, false);
886906
}
887907

888-
void insertHelperFunction(NodeAnnotation Anno, StringRef RawType,
889-
StringRef NewType, bool FromString,
890-
Expr *Wrappee) {
908+
ConversionFunctionInfo &insertHelperFunction(NodeAnnotation Anno,
909+
StringRef RawType,
910+
StringRef NewType,
911+
bool FromString,
912+
Expr *Wrappee) {
891913
HelperFuncInfo.emplace_back(Wrappee);
892914
ConversionFunctionInfo &Info = HelperFuncInfo.back();
893915
llvm::raw_svector_ostream OS(Info.Buffer);
@@ -959,6 +981,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
959981
OS << "(_ input: " << Segs[3] << ") -> " << Segs[2] << " {\n";
960982
OS << Segs[5] << "\n}\n";
961983
}
984+
return Info;
962985
}
963986

964987
void handleStringRepresentableArg(ValueDecl *FD, Expr *Arg, Expr *Call) {
@@ -1106,6 +1129,18 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
11061129
return true;
11071130
}
11081131

1132+
static void collectParamters(AbstractFunctionDecl *AFD,
1133+
SmallVectorImpl<ParamDecl*> &Results) {
1134+
for (auto PL : AFD->getParameterLists()) {
1135+
for (auto *PD: *PL) {
1136+
// Self parameter should not be updated.
1137+
if (PD->isSelfParameter())
1138+
continue;
1139+
Results.push_back(PD);
1140+
}
1141+
}
1142+
}
1143+
11091144
void handleFuncDeclRename(AbstractFunctionDecl *AFD,
11101145
CharSourceRange NameRange) {
11111146
bool IgnoreBase = false;
@@ -1114,29 +1149,26 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
11141149
if (!IgnoreBase)
11151150
Editor.replace(NameRange, View.base());
11161151
unsigned Index = 0;
1117-
for (auto PL : AFD->getParameterLists()) {
1118-
for (auto *PD : *PL) {
1119-
if (Index == View.argSize())
1120-
break;
1121-
// Self parameter should not be updated.
1122-
if (PD->isSelfParameter())
1123-
continue;
1124-
StringRef NewArg = View.args()[Index++];
1125-
auto ArgLoc = PD->getArgumentNameLoc();
1126-
1127-
// Represent empty label with underscore.
1128-
if (NewArg.empty())
1129-
NewArg = "_";
1130-
1131-
// If the argument name is not specified, add the argument name before
1132-
// the parameter name.
1133-
if (ArgLoc.isInvalid())
1134-
Editor.insertBefore(PD->getNameLoc(),
1135-
(llvm::Twine(NewArg) + " ").str());
1136-
else {
1137-
// Otherwise, replace the argument name directly.
1138-
Editor.replaceToken(ArgLoc, NewArg);
1139-
}
1152+
SmallVector<ParamDecl*, 4> Params;
1153+
collectParamters(AFD, Params);
1154+
for (auto *PD: Params) {
1155+
if (Index == View.argSize())
1156+
break;
1157+
StringRef NewArg = View.args()[Index++];
1158+
auto ArgLoc = PD->getArgumentNameLoc();
1159+
1160+
// Represent empty label with underscore.
1161+
if (NewArg.empty())
1162+
NewArg = "_";
1163+
1164+
// If the argument name is not specified, add the argument name before
1165+
// the parameter name.
1166+
if (ArgLoc.isInvalid())
1167+
Editor.insertBefore(PD->getNameLoc(),
1168+
(llvm::Twine(NewArg) + " ").str());
1169+
else {
1170+
// Otherwise, replace the argument name directly.
1171+
Editor.replaceToken(ArgLoc, NewArg);
11401172
}
11411173
}
11421174
}
@@ -1224,6 +1256,49 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
12241256
}
12251257
}
12261258

1259+
// When users override a SDK function whose parameter types have been changed,
1260+
// we should introduce a local variable in the body of the function definition
1261+
// to shadow the changed parameter. Also, a proper conversion function should
1262+
// be defined to bridge the parameter to the local variable.
1263+
void handleLocalParameterBridge(AbstractFunctionDecl *AFD,
1264+
CommonDiffItem *DiffItem) {
1265+
assert(AFD);
1266+
assert(DiffItem->isStringRepresentableChange());
1267+
1268+
// We only handle top-level parameter type change.
1269+
if (DiffItem->getChildIndices().size() != 1)
1270+
return;
1271+
auto Idx = DiffItem->getChildIndices().front();
1272+
1273+
// We don't handle return type change.
1274+
if (Idx == 0)
1275+
return;
1276+
Idx --;
1277+
SmallVector<ParamDecl*, 4> Params;
1278+
collectParamters(AFD, Params);
1279+
if (Params.size() <= Idx)
1280+
return;
1281+
1282+
// Get the internal name of the changed paramter.
1283+
auto VariableName = Params[Idx]->getParameterName().str();
1284+
1285+
// Insert the helper function to convert the type back to raw types.
1286+
auto &Info = insertHelperFunction(DiffItem->DiffKind, DiffItem->LeftComment,
1287+
DiffItem->RightComment, /*From String*/false,
1288+
/*No expression to wrap*/nullptr);
1289+
1290+
if (auto *BD = AFD->getBody()) {
1291+
auto BL = BD->getLBraceLoc();
1292+
if (BL.isValid()) {
1293+
// Insert the local variable declaration after the opening brace.
1294+
Editor.insertAfterToken(BL,
1295+
(llvm::Twine("\n// Local variable inserted by Swift 4.2 migrator.") +
1296+
"\nlet " + VariableName + " = " + Info.getFuncName() + "(" +
1297+
VariableName + ")\n").str());
1298+
}
1299+
}
1300+
}
1301+
12271302
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
12281303
if (D->isImplicit())
12291304
return true;
@@ -1235,6 +1310,8 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
12351310
handleOverridingTypeChange(AFD, DiffItem);
12361311
else if (DiffItem->isToPropertyChange())
12371312
handleOverridingPropertyChange(AFD, DiffItem);
1313+
else if (DiffItem->isStringRepresentableChange())
1314+
handleLocalParameterBridge(AFD, DiffItem);
12381315
}
12391316
}
12401317
}

test/Migrator/Inputs/Cities.swift

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,26 @@ public func globalCityFunc4(_ c : Cities, _ p : Int, _ q: Int) -> Int { return 0
3535
public func globalCityFunc5() -> Int { return 0 }
3636
public func globalCityPointerTaker(_ c : UnsafePointer<Cities>, _ p : Int, _ q: Int) -> Int { return 0 }
3737

38-
public class Container {
39-
public var Value: String = ""
40-
public var attrDict: [String: Any] = [:]
41-
public var attrArr: [String] = []
42-
public var optionalAttrDict: [String: Any]? = nil
43-
public func addingAttributes(_ input: [String: Any]) {}
44-
public func adding(attributes: [String: Any]) {}
45-
public func adding(optionalAttributes: [String: Any]?) {}
38+
open class Container {
4639
public init(optionalAttributes: [String: Any]?) {}
47-
public func adding(attrArray: [String]) {}
4840
public init(optionalAttrArray: [String]?) {}
49-
public func add(single: String) {}
50-
public func add(singleOptional: String?) {}
51-
public func getAttrArray() -> [String] { return [] }
52-
public func getOptionalAttrArray() -> [String]? { return [] }
53-
public func getAttrDictionary() -> [String: Any] { return [:] }
54-
public func getOptionalAttrDictionary() -> [String: Any]? { return nil }
55-
public func getSingleAttr() -> String { return "" }
56-
public func getOptionalSingleAttr() -> String? { return nil }
41+
42+
open func adding(attrArray: [String]) {}
43+
open var Value: String = ""
44+
open var attrDict: [String: Any] = [:]
45+
open var attrArr: [String] = []
46+
open var optionalAttrDict: [String: Any]? = nil
47+
open func addingAttributes(_ input: [String: Any]) {}
48+
open func adding(attributes: [String: Any]) {}
49+
open func adding(optionalAttributes: [String: Any]?) {}
50+
open func add(single: String) {}
51+
open func add(singleOptional: String?) {}
52+
open func getAttrArray() -> [String] { return [] }
53+
open func getOptionalAttrArray() -> [String]? { return [] }
54+
open func getAttrDictionary() -> [String: Any] { return [:] }
55+
open func getOptionalAttrDictionary() -> [String: Any]? { return nil }
56+
open func getSingleAttr() -> String { return "" }
57+
open func getOptionalSingleAttr() -> String? { return nil }
5758
}
5859

5960
open class ToplevelType {

test/Migrator/string-representable.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,11 @@ func bar(_ c: Container) {
6565
let attr: AliasAttribute = ""
6666
c.add(single: attr)
6767
}
68+
69+
public class SubContainer: Container {
70+
public override func adding(optionalAttributes subname: [String: Any]?) {}
71+
public override func adding(attributes myname: [String: Any]) {}
72+
public override func adding(attrArray: [String]) {}
73+
public override func add(single: String) {}
74+
public override func add(singleOptional: String?) {}
75+
}

test/Migrator/string-representable.swift.expected

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,56 @@ func bar(_ c: Container) {
6666
c.add(single: attr)
6767
}
6868

69+
public class SubContainer: Container {
70+
public override func adding(optionalAttributes subname: [String: Any]?) {
71+
// Local variable inserted by Swift 4.2 migrator.
72+
let subname = convertFromOptionalSimpleAttributeDictionary(subname)
73+
}
74+
public override func adding(attributes myname: [String: Any]) {
75+
// Local variable inserted by Swift 4.2 migrator.
76+
let myname = convertFromSimpleAttributeDictionary(myname)
77+
}
78+
public override func adding(attrArray: [String]) {
79+
// Local variable inserted by Swift 4.2 migrator.
80+
let attrArray = convertFromSimpleAttributeArray(attrArray)
81+
}
82+
public override func add(single: String) {
83+
// Local variable inserted by Swift 4.2 migrator.
84+
let single = convertFromSimpleAttribute(single)
85+
}
86+
public override func add(singleOptional: String?) {
87+
// Local variable inserted by Swift 4.2 migrator.
88+
let singleOptional = convertFromOptionalSimpleAttribute(singleOptional)
89+
}
90+
}
91+
92+
// Helper function inserted by Swift 4.2 migrator.
93+
fileprivate func convertFromOptionalSimpleAttributeDictionary(_ input: [SimpleAttribute: Any]?) -> [String: Any]? {
94+
guard let input = input else { return nil }
95+
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
96+
}
97+
98+
// Helper function inserted by Swift 4.2 migrator.
99+
fileprivate func convertFromSimpleAttributeDictionary(_ input: [SimpleAttribute: Any]) -> [String: Any] {
100+
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
101+
}
102+
103+
// Helper function inserted by Swift 4.2 migrator.
104+
fileprivate func convertFromSimpleAttributeArray(_ input: [SimpleAttribute]) -> [String] {
105+
return input.map { key in key.rawValue }
106+
}
107+
108+
// Helper function inserted by Swift 4.2 migrator.
109+
fileprivate func convertFromSimpleAttribute(_ input: SimpleAttribute) -> String {
110+
return input.rawValue
111+
}
112+
113+
// Helper function inserted by Swift 4.2 migrator.
114+
fileprivate func convertFromOptionalSimpleAttribute(_ input: SimpleAttribute?) -> String? {
115+
guard let input = input else { return nil }
116+
return input.rawValue
117+
}
118+
69119
// Helper function inserted by Swift 4.2 migrator.
70120
fileprivate func convertToNewAttribute(_ input: String) -> NewAttribute {
71121
return NewAttribute(rawValue: input)
@@ -109,33 +159,6 @@ fileprivate func convertToOptionalSimpleAttribute(_ input: String?) -> SimpleAtt
109159
return SimpleAttribute(rawValue: input)
110160
}
111161

112-
// Helper function inserted by Swift 4.2 migrator.
113-
fileprivate func convertFromSimpleAttributeDictionary(_ input: [SimpleAttribute: Any]) -> [String: Any] {
114-
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
115-
}
116-
117-
// Helper function inserted by Swift 4.2 migrator.
118-
fileprivate func convertFromOptionalSimpleAttributeDictionary(_ input: [SimpleAttribute: Any]?) -> [String: Any]? {
119-
guard let input = input else { return nil }
120-
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
121-
}
122-
123-
// Helper function inserted by Swift 4.2 migrator.
124-
fileprivate func convertFromSimpleAttribute(_ input: SimpleAttribute) -> String {
125-
return input.rawValue
126-
}
127-
128-
// Helper function inserted by Swift 4.2 migrator.
129-
fileprivate func convertFromOptionalSimpleAttribute(_ input: SimpleAttribute?) -> String? {
130-
guard let input = input else { return nil }
131-
return input.rawValue
132-
}
133-
134-
// Helper function inserted by Swift 4.2 migrator.
135-
fileprivate func convertFromSimpleAttributeArray(_ input: [SimpleAttribute]) -> [String] {
136-
return input.map { key in key.rawValue }
137-
}
138-
139162
// Helper function inserted by Swift 4.2 migrator.
140163
fileprivate func convertFromOptionalSimpleAttributeArray(_ input: [SimpleAttribute]?) -> [String]? {
141164
guard let input = input else { return nil }

0 commit comments

Comments
 (0)