Skip to content

[migrator] Handle AppKit protocol migrations #18310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 97 additions & 1 deletion lib/Migrator/APIDiffMigratorPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {

std::vector<ConversionFunctionInfo> 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
Expand All @@ -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();
Expand Down Expand Up @@ -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<OverrideAttr>()) {
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<CallExpr>(E)) {
if (auto *DSC = dyn_cast<DotSyntaxCallExpr>(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<AnyTryExpr>(E)) {
return isSuperExpr(TE->getSubExpr());
}
return false;
}
std::pair<bool, Stmt*> walkToStmtPre(Stmt *S) override {
if (auto *BS = dyn_cast<BraceStmt>(S)) {
for(auto Ele: BS->getElements()) {
if (Ele.is<Expr*>() && isSuperExpr(Ele.get<Expr*>())) {
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;
Expand All @@ -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;
}
Expand Down
127 changes: 127 additions & 0 deletions test/Migrator/remove_override.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// REQUIRES: OS=macosx
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -c -update-code -swift-version 4 -disable-migrator-fixits -primary-file %s -emit-migrated-file-path %t/remove_override.result.swift -o %t/rename-func-decl.swift.remap
// RUN: diff -u %S/remove_override.swift.expected %t/remove_override.result.swift

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
}
}

127 changes: 127 additions & 0 deletions test/Migrator/remove_override.swift.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// REQUIRES: OS=macosx
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -c -update-code -swift-version 4 -disable-migrator-fixits -primary-file %s -emit-migrated-file-path %t/remove_override.result.swift -o %t/rename-func-decl.swift.remap
// RUN: diff -u %S/remove_override.swift.expected %t/remove_override.result.swift

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
}
}