From a8d43cc3447fd00db9be8e86ba670cdefbb83f26 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 25 Jul 2018 14:20:25 -0700 Subject: [PATCH] migrator: handle AppKit protocol migrations. rdar://42480588 --- lib/Migrator/APIDiffMigratorPass.cpp | 98 ++++++++++++++- test/Migrator/remove_override.swift | 126 +++++++++++++++++++ test/Migrator/remove_override.swift.expected | 126 +++++++++++++++++++ 3 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 test/Migrator/remove_override.swift create mode 100644 test/Migrator/remove_override.swift.expected diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index 8c8eac0c94e7a..a2753d2450211 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -363,6 +363,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { std::vector HelperFuncInfo; SourceLoc FileEndLoc; + llvm::StringSet<> OverridingRemoveNames; /// For a given expression, check whether the type of this expression is /// name alias type, and the name alias type is known to change to raw @@ -385,7 +386,8 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { APIDiffMigratorPass(EditorAdapter &Editor, SourceFile *SF, const MigratorOptions &Opts): ASTMigratorPass(Editor, SF, Opts), DiffStore(Diags), - FileEndLoc(SM.getRangeForBuffer(BufferID).getEnd()) {} + FileEndLoc(SM.getRangeForBuffer(BufferID).getEnd()), + OverridingRemoveNames(funcNamesForOverrideRemoval()) {} ~APIDiffMigratorPass() { Editor.disableCache(); @@ -1290,6 +1292,92 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } } + llvm::StringSet<> funcNamesForOverrideRemoval() { + llvm::StringSet<> Results; + Results.insert("c:objc(cs)NSObject(im)application:delegateHandlesKey:"); + Results.insert("c:objc(cs)NSObject(im)changeColor:"); + Results.insert("c:objc(cs)NSObject(im)controlTextDidBeginEditing:"); + Results.insert("c:objc(cs)NSObject(im)controlTextDidEndEditing:"); + Results.insert("c:objc(cs)NSObject(im)controlTextDidChange:"); + Results.insert("c:objc(cs)NSObject(im)changeFont:"); + Results.insert("c:objc(cs)NSObject(im)validModesForFontPanel:"); + Results.insert("c:objc(cs)NSObject(im)discardEditing"); + Results.insert("c:objc(cs)NSObject(im)commitEditing"); + Results.insert("c:objc(cs)NSObject(im)commitEditingWithDelegate:didCommitSelector:contextInfo:"); + Results.insert("c:objc(cs)NSObject(im)commitEditingAndReturnError:"); + Results.insert("c:objc(cs)NSObject(im)objectDidBeginEditing:"); + Results.insert("c:objc(cs)NSObject(im)objectDidEndEditing:"); + Results.insert("c:objc(cs)NSObject(im)validateMenuItem:"); + Results.insert("c:objc(cs)NSObject(im)pasteboard:provideDataForType:"); + Results.insert("c:objc(cs)NSObject(im)pasteboardChangedOwner:"); + Results.insert("c:objc(cs)NSObject(im)validateToolbarItem:"); + Results.insert("c:objc(cs)NSObject(im)layer:shouldInheritContentsScale:fromWindow:"); + Results.insert("c:objc(cs)NSObject(im)view:stringForToolTip:point:userData:"); + return Results; + } + + SourceLoc shouldRemoveOverride(AbstractFunctionDecl *AFD) { + if (AFD->getKind() != DeclKind::Func) + return SourceLoc(); + SourceLoc OverrideLoc; + + // Get the location of override keyword. + if (auto *Override = AFD->getAttrs().getAttribute()) { + if (Override->getRange().isValid()) { + OverrideLoc = Override->getLocation(); + } + } + if (OverrideLoc.isInvalid()) + return SourceLoc(); + auto *OD = AFD->getOverriddenDecl(); + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream OS(Buffer); + if (swift::ide::printDeclUSR(OD, OS)) + return SourceLoc(); + return OverridingRemoveNames.find(OS.str()) == OverridingRemoveNames.end() ? + SourceLoc() : OverrideLoc; + } + + struct SuperRemoval: public ASTWalker { + EditorAdapter &Editor; + llvm::StringSet<> &USRs; + SuperRemoval(EditorAdapter &Editor, llvm::StringSet<> &USRs): + Editor(Editor), USRs(USRs) {} + bool isSuperExpr(Expr *E) { + if (E->isImplicit()) + return false; + // Check if the expression is super.foo(). + if (auto *CE = dyn_cast(E)) { + if (auto *DSC = dyn_cast(CE->getFn())) { + if (DSC->getBase()->getKind() != ExprKind::SuperRef) + return false; + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream OS(Buffer); + auto *RD = DSC->getFn()->getReferencedDecl().getDecl(); + if (swift::ide::printDeclUSR(RD, OS)) + return false; + return USRs.find(OS.str()) != USRs.end(); + } + } + // We should handle try super.foo() too. + if (auto *TE = dyn_cast(E)) { + return isSuperExpr(TE->getSubExpr()); + } + return false; + } + std::pair walkToStmtPre(Stmt *S) override { + if (auto *BS = dyn_cast(S)) { + for(auto Ele: BS->getElements()) { + if (Ele.is() && isSuperExpr(Ele.get())) { + Editor.remove(Ele.getSourceRange()); + } + } + } + // We only handle top-level expressions, so avoid visiting further. + return {false, S}; + } + }; + bool walkToDeclPre(Decl *D, CharSourceRange Range) override { if (D->isImplicit()) return true; @@ -1305,6 +1393,14 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { handleLocalParameterBridge(AFD, DiffItem); } } + auto OverrideLoc = shouldRemoveOverride(AFD); + if (OverrideLoc.isValid()) { + // Remove override keyword. + Editor.remove(OverrideLoc); + // Remove super-dot call. + SuperRemoval Removal(Editor, OverridingRemoveNames); + D->walk(Removal); + } } return true; } diff --git a/test/Migrator/remove_override.swift b/test/Migrator/remove_override.swift new file mode 100644 index 0000000000000..eb06035cc373e --- /dev/null +++ b/test/Migrator/remove_override.swift @@ -0,0 +1,126 @@ +// REQUIRES: objc_interop +// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -disable-migrator-fixits -primary-file %s -I %t.mod -emit-migrated-file-path %t/remove_override.swift.result -o %t/rename-func-decl.swift.remap +// RUN: diff -u %S/remove_override.swift.expected %t/remove_override.swift.result + +import AppKit + +class AppDelegate: NSObject { + override class func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool { + super.application(sender, delegateHandlesKey: key) + return false + } + override func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool { + return super.application(sender, delegateHandlesKey: key) + } + override class func changeColor(_ sender: Any?) { + super.changeColor(sender) + } + override func changeColor(_ sender: Any?) { + + } + override class func controlTextDidBeginEditing(_ obj: Notification) { + + } + override func controlTextDidBeginEditing(_ obj: Notification) { + + } + override class func controlTextDidEndEditing(_ obj: Notification) { + + } + override func controlTextDidEndEditing(_ obj: Notification) { + + } + override class func controlTextDidChange(_ obj: Notification) { + + } + override func controlTextDidChange(_ obj: Notification) { + + } + override class func changeFont(_ sender: Any?) { + + } + override func changeFont(_ sender: Any?) { + + } + override class func validModesForFontPanel(_ fontPanel: NSFontPanel) -> NSFontPanel.ModeMask { + return [] + } + override func validModesForFontPanel(_ fontPanel: NSFontPanel) -> NSFontPanel.ModeMask { + return [] + } + override class func discardEditing() { + + } + override func discardEditing() { + + } + override class func commitEditing() -> Bool { + return false + } + override func commitEditing() -> Bool { + return false + } + override class func commitEditing(withDelegate delegate: Any?, didCommit didCommitSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) { + + } + override func commitEditing(withDelegate delegate: Any?, didCommit didCommitSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) { + + } + override class func commitEditingAndReturnError() throws { + + } + override func commitEditingAndReturnError() throws { + + } + override class func objectDidBeginEditing(_ editor: Any) { + + } + override func objectDidBeginEditing(_ editor: Any) { + + } + override class func objectDidEndEditing(_ editor: Any) { + + } + override func objectDidEndEditing(_ editor: Any) { + + } + override class func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + return false + } + override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + return false + } + override class func pasteboard(_ sender: NSPasteboard, provideDataForType type: NSPasteboard.PasteboardType) { + + } + override func pasteboard(_ sender: NSPasteboard, provideDataForType type: NSPasteboard.PasteboardType) { + + } + override class func pasteboardChangedOwner(_ sender: NSPasteboard) { + + } + override func pasteboardChangedOwner(_ sender: NSPasteboard) { + + } + override class func layer(_ layer: CALayer, shouldInheritContentsScale newScale: CGFloat, from window: NSWindow) -> Bool { + return false + } + override func layer(_ layer: CALayer, shouldInheritContentsScale newScale: CGFloat, from window: NSWindow) -> Bool { + return false + } + override class func view(_ view: NSView, stringForToolTip tag: NSView.ToolTipTag, point: NSPoint, userData data: UnsafeMutableRawPointer?) -> String { + return "" + } + override func view(_ view: NSView, stringForToolTip tag: NSView.ToolTipTag, point: NSPoint, userData data: UnsafeMutableRawPointer?) -> String { + return "" + } +} + +// We shouldn't migrate further sub-class. +class MyAppDelegate: AppDelegate { + override func commitEditing() -> Bool { + super.commitEditing() + return false + } +} + diff --git a/test/Migrator/remove_override.swift.expected b/test/Migrator/remove_override.swift.expected new file mode 100644 index 0000000000000..257c7aa12cfe8 --- /dev/null +++ b/test/Migrator/remove_override.swift.expected @@ -0,0 +1,126 @@ +// REQUIRES: objc_interop +// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -disable-migrator-fixits -primary-file %s -I %t.mod -emit-migrated-file-path %t/remove_override.swift.result -o %t/rename-func-decl.swift.remap +// RUN: diff -u %S/remove_override.swift.expected %t/remove_override.swift.result + +import AppKit + +class AppDelegate: NSObject { + class func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool { + + return false + } + func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool { + return super.application(sender, delegateHandlesKey: key) + } + class func changeColor(_ sender: Any?) { + + } + func changeColor(_ sender: Any?) { + + } + class func controlTextDidBeginEditing(_ obj: Notification) { + + } + func controlTextDidBeginEditing(_ obj: Notification) { + + } + class func controlTextDidEndEditing(_ obj: Notification) { + + } + func controlTextDidEndEditing(_ obj: Notification) { + + } + class func controlTextDidChange(_ obj: Notification) { + + } + func controlTextDidChange(_ obj: Notification) { + + } + class func changeFont(_ sender: Any?) { + + } + func changeFont(_ sender: Any?) { + + } + class func validModesForFontPanel(_ fontPanel: NSFontPanel) -> NSFontPanel.ModeMask { + return [] + } + func validModesForFontPanel(_ fontPanel: NSFontPanel) -> NSFontPanel.ModeMask { + return [] + } + class func discardEditing() { + + } + func discardEditing() { + + } + class func commitEditing() -> Bool { + return false + } + func commitEditing() -> Bool { + return false + } + class func commitEditing(withDelegate delegate: Any?, didCommit didCommitSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) { + + } + func commitEditing(withDelegate delegate: Any?, didCommit didCommitSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) { + + } + class func commitEditingAndReturnError() throws { + + } + func commitEditingAndReturnError() throws { + + } + class func objectDidBeginEditing(_ editor: Any) { + + } + func objectDidBeginEditing(_ editor: Any) { + + } + class func objectDidEndEditing(_ editor: Any) { + + } + func objectDidEndEditing(_ editor: Any) { + + } + class func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + return false + } + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + return false + } + class func pasteboard(_ sender: NSPasteboard, provideDataForType type: NSPasteboard.PasteboardType) { + + } + func pasteboard(_ sender: NSPasteboard, provideDataForType type: NSPasteboard.PasteboardType) { + + } + class func pasteboardChangedOwner(_ sender: NSPasteboard) { + + } + func pasteboardChangedOwner(_ sender: NSPasteboard) { + + } + class func layer(_ layer: CALayer, shouldInheritContentsScale newScale: CGFloat, from window: NSWindow) -> Bool { + return false + } + func layer(_ layer: CALayer, shouldInheritContentsScale newScale: CGFloat, from window: NSWindow) -> Bool { + return false + } + class func view(_ view: NSView, stringForToolTip tag: NSView.ToolTipTag, point: NSPoint, userData data: UnsafeMutableRawPointer?) -> String { + return "" + } + func view(_ view: NSView, stringForToolTip tag: NSView.ToolTipTag, point: NSPoint, userData data: UnsafeMutableRawPointer?) -> String { + return "" + } +} + +// We shouldn't migrate further sub-class. +class MyAppDelegate: AppDelegate { + override func commitEditing() -> Bool { + super.commitEditing() + return false + } +} +