Skip to content

Commit d275e7d

Browse files
authored
Merge pull request #17120 from nkcsgexi/migrator-fix
migrator: avoid inserting round-trip conversion functions.
2 parents a6a6ad8 + 6433bc5 commit d275e7d

File tree

4 files changed

+99
-51
lines changed

4 files changed

+99
-51
lines changed

lib/Migrator/APIDiffMigratorPass.cpp

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,19 @@ static ValueDecl* getReferencedDecl(Expr *E) {
250250
}
251251
}
252252

253+
struct ConversionFunctionInfo {
254+
Expr *ExpressionToWrap;
255+
SmallString<256> Buffer;
256+
unsigned FuncNameStart;
257+
unsigned FuncNameEnd;
258+
ConversionFunctionInfo(Expr *ExpressionToWrap):
259+
ExpressionToWrap(ExpressionToWrap) {}
260+
StringRef getFuncDef() const { return Buffer.str(); }
261+
StringRef getFuncName() const {
262+
return Buffer.substr(FuncNameStart, FuncNameEnd - FuncNameStart);
263+
}
264+
};
265+
253266
struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
254267

255268
APIDiffItemStore DiffStore;
@@ -328,20 +341,53 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
328341
return false;
329342
}
330343

331-
std::set<std::string> InsertedFunctions;
344+
std::vector<ConversionFunctionInfo> HelperFuncInfo;
332345
SourceLoc FileEndLoc;
346+
333347
APIDiffMigratorPass(EditorAdapter &Editor, SourceFile *SF,
334348
const MigratorOptions &Opts):
335349
ASTMigratorPass(Editor, SF, Opts), DiffStore(Diags),
336-
FileEndLoc(SM.getRangeForBuffer(BufferID).getEnd()) {
337-
SmallVector<Decl*, 16> TopDecls;
338-
SF->getTopLevelDecls(TopDecls);
339-
for (auto *D: TopDecls) {
340-
if (auto *FD = dyn_cast<FuncDecl>(D)) {
341-
InsertedFunctions.insert(FD->getBaseName().getIdentifier().str());
342-
}
350+
FileEndLoc(SM.getRangeForBuffer(BufferID).getEnd()) {}
351+
352+
~APIDiffMigratorPass() {
353+
Editor.disableCache();
354+
SWIFT_DEFER { Editor.enableCache(); };
355+
356+
// Collect inserted functions to avoid re-insertion.
357+
std::set<std::string> InsertedFunctions;
358+
SmallVector<Decl*, 16> TopDecls;
359+
SF->getTopLevelDecls(TopDecls);
360+
for (auto *D: TopDecls) {
361+
if (auto *FD = dyn_cast<FuncDecl>(D)) {
362+
InsertedFunctions.insert(FD->getBaseName().getIdentifier().str());
343363
}
344364
}
365+
for (auto &Cur: HelperFuncInfo) {
366+
// Avoid wrapping nil expression.
367+
if (isNilExpr(Cur.ExpressionToWrap))
368+
continue;
369+
370+
// Avoid wrapping a single expression with multiple conversion functions.
371+
auto count = std::count_if(HelperFuncInfo.begin(), HelperFuncInfo.end(),
372+
[&] (ConversionFunctionInfo &Info) {
373+
return Info.ExpressionToWrap->getSourceRange() ==
374+
Cur.ExpressionToWrap->getSourceRange();
375+
});
376+
if (count > 1)
377+
continue;
378+
assert(count == 1);
379+
auto FuncName = Cur.getFuncName();
380+
381+
// Avoid inserting the helper function if it's already present.
382+
if (!InsertedFunctions.count(FuncName)) {
383+
Editor.insert(FileEndLoc, Cur.getFuncDef());
384+
InsertedFunctions.insert(FuncName);
385+
}
386+
Editor.insertBefore(Cur.ExpressionToWrap->getStartLoc(),
387+
(Twine(FuncName) + "(").str());
388+
Editor.insertAfterToken(Cur.ExpressionToWrap->getEndLoc(), ")");
389+
}
390+
}
345391

346392
void run() {
347393
if (Opts.APIDigesterDataStorePaths.empty())
@@ -737,12 +783,9 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
737783
}
738784
if (!Kind.hasValue())
739785
return false;
740-
if (Kind && !isNilExpr(WrapperTarget)) {
741-
SmallString<256> Buffer;
742-
auto Func = insertHelperFunction(*Kind, LeftComment, RightComment, Buffer,
743-
FromString);
744-
Editor.insert(WrapperTarget->getStartLoc(), (Twine(Func) + "(").str());
745-
Editor.insertAfterToken(WrapperTarget->getEndLoc(), ")");
786+
if (Kind) {
787+
insertHelperFunction(*Kind, LeftComment, RightComment, FromString,
788+
WrapperTarget);
746789
}
747790
if (!Rename.empty()) {
748791
replaceExpr(Reference, Rename);
@@ -751,8 +794,6 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
751794
}
752795

753796
bool handleAssignDestMigration(Expr *E) {
754-
Editor.disableCache();
755-
SWIFT_DEFER { Editor.enableCache(); };
756797
auto *ASE = dyn_cast<AssignExpr>(E);
757798
if (!ASE || !ASE->getDest() || !ASE->getSrc())
758799
return false;
@@ -771,14 +812,16 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
771812
return wrapAttributeReference(E, E, false);
772813
}
773814

774-
StringRef insertHelperFunction(NodeAnnotation Anno, StringRef RawType,
775-
StringRef NewType,
776-
SmallString<256> &Buffer, bool FromString) {
777-
llvm::raw_svector_ostream OS(Buffer);
815+
void insertHelperFunction(NodeAnnotation Anno, StringRef RawType,
816+
StringRef NewType, bool FromString,
817+
Expr *Wrappee) {
818+
HelperFuncInfo.emplace_back(Wrappee);
819+
ConversionFunctionInfo &Info = HelperFuncInfo.back();
820+
llvm::raw_svector_ostream OS(Info.Buffer);
778821
OS << "\n";
779822
OS << "// Helper function inserted by Swift 4.2 migrator.\n";
780823
OS << "fileprivate func ";
781-
unsigned FuncNameStart = Buffer.size();
824+
Info.FuncNameStart = Info.Buffer.size();
782825
OS << (FromString ? "convertTo" : "convertFrom");
783826
SmallVector<std::string, 8> Segs;
784827
StringRef guard = "\tguard let input = input else { return nil }\n";
@@ -835,24 +878,17 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
835878
for (auto P: Parts)
836879
OS << P;
837880
OS << Segs[1];
838-
auto FuncName = Buffer.str().substr(FuncNameStart);
839-
if (!InsertedFunctions.count(FuncName)) {
840-
if (FromString) {
841-
OS << "(_ input: " << Segs[2] << ") -> " << Segs[3] << " {\n";
842-
OS << Segs[4] << "\n}\n";
843-
} else {
844-
OS << "(_ input: " << Segs[3] << ") -> " << Segs[2] << " {\n";
845-
OS << Segs[5] << "\n}\n";
846-
}
847-
Editor.insert(FileEndLoc, OS.str());
848-
InsertedFunctions.insert(FuncName);
881+
Info.FuncNameEnd = Info.Buffer.size();
882+
if (FromString) {
883+
OS << "(_ input: " << Segs[2] << ") -> " << Segs[3] << " {\n";
884+
OS << Segs[4] << "\n}\n";
885+
} else {
886+
OS << "(_ input: " << Segs[3] << ") -> " << Segs[2] << " {\n";
887+
OS << Segs[5] << "\n}\n";
849888
}
850-
return FuncName;
851889
}
852890

853891
void handleStringRepresentableArg(ValueDecl *FD, Expr *Arg, Expr *Call) {
854-
Editor.disableCache();
855-
SWIFT_DEFER { Editor.enableCache(); };
856892
NodeAnnotation Kind;
857893
StringRef RawType;
858894
StringRef NewAttributeType;
@@ -880,19 +916,14 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
880916
if (AllArgs.size() <= ArgIdx)
881917
return;
882918
WrapTarget = AllArgs[ArgIdx].ArgExp;
883-
// Avoid wrapping nil literal.
884-
if (isNilExpr(WrapTarget))
885-
return;
886919
}
887920
assert(WrapTarget);
888-
SmallString<256> Buffer;
889-
auto FuncName = insertHelperFunction(Kind, RawType, NewAttributeType, Buffer,
890-
FromString);
891-
Editor.insert(WrapTarget->getStartLoc(), (Twine(FuncName) + "(").str());
892-
Editor.insertAfterToken(WrapTarget->getEndLoc(), ")");
921+
insertHelperFunction(Kind, RawType, NewAttributeType, FromString, WrapTarget);
893922
}
894923

895924
bool walkToExprPre(Expr *E) override {
925+
if (E->getSourceRange().isInvalid())
926+
return false;
896927
if (handleQualifiedReplacement(E))
897928
return false;
898929
if (handleAssignDestMigration(E))

test/Migrator/Inputs/string-representable.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,15 @@
216216
"NewPrintedName": "NewAttribute",
217217
"NewTypeName": "AttributeWrapper"
218218
},
219+
{
220+
"DiffItemKind": "CommonDiffItem",
221+
"NodeKind": "Constructor",
222+
"NodeAnnotation": "OptionalDictionaryKeyUpdate",
223+
"ChildIndex": "1",
224+
"LeftUsr": "c:objc(cs)BarForwardDeclaredClass(im)initWithOldLabel0:",
225+
"LeftComment": "Int",
226+
"RightUsr": "",
227+
"RightComment": "AwesomeIntWrapper",
228+
"ModuleName": "bar"
229+
},
219230
]

test/Migrator/string-representable.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// REQUIRES: objc_interop
22
// RUN: %empty-directory(%t.mod)
33
// 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 -primary-file %s -I %t.mod -api-diff-data-file %S/Inputs/string-representable.json -emit-migrated-file-path %t/string-representable.swift.result -disable-migrator-fixits -o /dev/null
4+
// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -I %t.mod -api-diff-data-file %S/Inputs/string-representable.json -emit-migrated-file-path %t/string-representable.swift.result -disable-migrator-fixits -o /dev/null -F %S/mock-sdk
55
// RUN: diff -u %S/string-representable.swift.expected %t/string-representable.swift.result
66

77
import Cities
8+
import Bar
89

910
func foo(_ c: Container) -> String {
1011
c.Value = ""
@@ -42,3 +43,5 @@ func foo(_ c: Container) -> String {
4243
c.optionalAttrDict = nil
4344
return c.Value
4445
}
46+
47+
class C: BarForwardDeclaredClass {}

test/Migrator/string-representable.swift.expected

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// REQUIRES: objc_interop
22
// RUN: %empty-directory(%t.mod)
33
// 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 -primary-file %s -I %t.mod -api-diff-data-file %S/Inputs/string-representable.json -emit-migrated-file-path %t/string-representable.swift.result -disable-migrator-fixits -o /dev/null
4+
// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -I %t.mod -api-diff-data-file %S/Inputs/string-representable.json -emit-migrated-file-path %t/string-representable.swift.result -disable-migrator-fixits -o /dev/null -F %S/mock-sdk
55
// RUN: diff -u %S/string-representable.swift.expected %t/string-representable.swift.result
66

77
import Cities
8+
import Bar
89

910
func foo(_ c: Container) -> String {
1011
c.Value = convertToNewAttribute("")
@@ -27,22 +28,24 @@ func foo(_ c: Container) -> String {
2728
_ = convertFromSimpleAttributeArray(c.getAttrArray())
2829
_ = convertFromOptionalSimpleAttributeArray(c.getOptionalAttrArray())
2930

30-
c.addingAttributes(convertToCitiesContainerAttributeDictionary(convertFromSimpleAttributeDictionary(c.getAttrDictionary())))
31-
c.adding(optionalAttributes: convertToOptionalSimpleAttributeDictionary(convertFromSimpleAttributeDictionary(c.getAttrDictionary())))
31+
c.addingAttributes(c.getAttrDictionary())
32+
c.adding(optionalAttributes: c.getAttrDictionary())
3233

3334
c.attrDict = convertToSimpleAttributeDictionary(["a": "b", "a": "b", "a": "b"])
3435
c.attrArr = convertToSimpleAttributeArray(["key1", "key2"])
3536
_ = convertFromSimpleAttributeArray(c.attrArr)
3637
_ = convertFromSimpleAttributeDictionary(c.attrDict)
37-
c.adding(attributes: convertToSimpleAttributeDictionary(convertFromSimpleAttributeDictionary(c.attrDict)))
38-
_ = Container(optionalAttrArray: convertToOptionalSimpleAttributeArray(convertFromSimpleAttributeArray(c.attrArr)))
39-
c.adding(optionalAttributes: convertToOptionalSimpleAttributeDictionary(convertFromOptionalSimpleAttributeDictionary(c.optionalAttrDict)))
38+
c.adding(attributes: c.attrDict)
39+
_ = Container(optionalAttrArray: c.attrArr)
40+
c.adding(optionalAttributes: c.optionalAttrDict)
4041
_ = convertFromNewAttribute(AttributeWrapper.NewAttribute)
41-
c.Value = convertToNewAttribute(convertFromNewAttribute(AttributeWrapper.NewAttribute))
42+
c.Value = AttributeWrapper.NewAttribute
4243
c.optionalAttrDict = nil
4344
return convertFromNewAttribute(c.Value)
4445
}
4546

47+
class C: BarForwardDeclaredClass {}
48+
4649
// Helper function inserted by Swift 4.2 migrator.
4750
fileprivate func convertToNewAttribute(_ input: String) -> NewAttribute {
4851
return NewAttribute(rawValue: input)

0 commit comments

Comments
 (0)