Add an @NSApplicationMain attribute.

This behaves like @UIApplicationMain, except for AppKit. Attach it to your NSApplicationDelegate, and an artificial "main" will be generated that invokes NSApplicationMain() for you. Implements rdar://problem/16904667.

Swift SVN r21697
This commit is contained in:
Joe Groff
2014-09-04 05:52:26 +00:00
parent ece743ea3b
commit d7c98dcff4
17 changed files with 195 additions and 47 deletions

View File

@@ -195,6 +195,9 @@ DECL_ATTR_ALIAS(unowned, Ownership)
DECL_ATTR(__objc_bridged, ObjCBridged, OnClass | NotSerialized, DECL_ATTR(__objc_bridged, ObjCBridged, OnClass | NotSerialized,
/* Not serialized */51) /* Not serialized */51)
SIMPLE_DECL_ATTR(NSApplicationMain, NSApplicationMain,
OnClass, 52)
// Reordering these platforms will break serialization. // Reordering these platforms will break serialization.
AVAILABILITY_PLATFORM(iOS, "iOS") AVAILABILITY_PLATFORM(iOS, "iOS")
AVAILABILITY_PLATFORM(OSX, "OS X") AVAILABILITY_PLATFORM(OSX, "OS X")

View File

@@ -993,25 +993,32 @@ ERROR(nscopying_doesnt_conform,sema_tcd,none,
"'NSCopying' attribute is only valid with types that conform to" "'NSCopying' attribute is only valid with types that conform to"
" the NSCopying protocol", ()) " the NSCopying protocol", ())
// UIApplicationMain attribute // UIApplicationMain/NSApplicationMain attribute
ERROR(attr_UIApplicationMain_not_class,sema_tcd,none, #define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'}"
"'UIApplicationMain' attribute may only be used on classes", ()) #define SELECT_APPLICATION_DELEGATE "select{'UIApplicationDelegate'|'NSApplicationDelegate'}"
ERROR(attr_UIApplicationMain_not_UIApplicationDelegate,sema_tcd,none,
"'UIApplicationMain' class must conform to the 'UIApplicationDelegate' protocol", ERROR(attr_ApplicationMain_not_class,sema_tcd,none,
()) "%" SELECT_APPLICATION_MAIN "0 attribute may only be used on classes",
ERROR(attr_generic_UIApplicationMain_not_supported,sema_tcd,none, (unsigned))
"generic 'UIApplicationMain' classes are not supported", ERROR(attr_ApplicationMain_not_ApplicationDelegate,sema_tcd,none,
()) "%" SELECT_APPLICATION_MAIN "0 class must conform to the %" SELECT_APPLICATION_DELEGATE "0 protocol",
ERROR(attr_UIApplicationMain_multiple,sema_tcd,none, (unsigned))
"'UIApplicationMain' attribute can only apply to one class in a module", ERROR(attr_generic_ApplicationMain_not_supported,sema_tcd,none,
()) "generic %" SELECT_APPLICATION_MAIN "0 classes are not supported",
ERROR(attr_UIApplicationMain_with_script,sema_tcd,none, (unsigned))
"'UIApplicationMain' attribute cannot be used in a module that contains " ERROR(attr_ApplicationMain_multiple,sema_tcd,none,
"%" SELECT_APPLICATION_MAIN "0 attribute can only apply to one class in a module",
(unsigned))
ERROR(attr_ApplicationMain_with_script,sema_tcd,none,
"%" SELECT_APPLICATION_MAIN "0 attribute cannot be used in a module that contains "
"top-level code", "top-level code",
()) (unsigned))
NOTE(attr_UIApplicationMain_script_here,sema_tcd,none, NOTE(attr_ApplicationMain_script_here,sema_tcd,none,
"top-level code defined in this source file", "top-level code defined in this source file",
()) (unsigned))
#undef SELECT_APPLICATION_MAIN
#undef SELECT_APPLICATION_DELEGATE
// lazy // lazy
ERROR(lazy_not_on_let,sema_tcd,none, ERROR(lazy_not_on_let,sema_tcd,none,

View File

@@ -191,7 +191,7 @@ private:
SmallVector<FileUnit *, 2> Files; SmallVector<FileUnit *, 2> Files;
/// The class in this module marked @UIApplicationMain. /// The class in this module marked @NS/UIApplicationMain.
ClassDecl *MainClass = nullptr; ClassDecl *MainClass = nullptr;
/// The source location of the main class. /// The source location of the main class.

View File

@@ -40,7 +40,7 @@ const uint16_t VERSION_MAJOR = 0;
/// Serialized module format minor version number. /// Serialized module format minor version number.
/// ///
/// When the format changes IN ANY WAY, this number should be incremented. /// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 132; const uint16_t VERSION_MINOR = 135;
using DeclID = Fixnum<31>; using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>; using DeclIDField = BCFixed<31>;

View File

@@ -1112,6 +1112,20 @@ bool Module::isBuiltinModule() const {
} }
bool Module::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) { bool Module::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) {
// %select indices for UI/NSApplication-related diagnostics.
enum : unsigned {
UIApplicationMainClass = 0,
NSApplicationMainClass = 1,
};
unsigned mainClassDiagKind;
if (mainClass->getAttrs().hasAttribute<UIApplicationMainAttr>())
mainClassDiagKind = UIApplicationMainClass;
else if (mainClass->getAttrs().hasAttribute<NSApplicationMainAttr>())
mainClassDiagKind = NSApplicationMainClass;
else
llvm_unreachable("main class has no @ApplicationMain attribute?!");
if (mainClass == MainClass) if (mainClass == MainClass)
return false; return false;
@@ -1119,11 +1133,13 @@ bool Module::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) {
// If we already have a main class, and we haven't diagnosed it, do so now. // If we already have a main class, and we haven't diagnosed it, do so now.
if (!DiagnosedMultipleMainClasses) { if (!DiagnosedMultipleMainClasses) {
getASTContext().Diags.diagnose(MainClassDiagLoc, getASTContext().Diags.diagnose(MainClassDiagLoc,
diag::attr_UIApplicationMain_multiple); diag::attr_ApplicationMain_multiple,
mainClassDiagKind);
DiagnosedMultipleMainClasses = true; DiagnosedMultipleMainClasses = true;
} }
getASTContext().Diags.diagnose(diagLoc, getASTContext().Diags.diagnose(diagLoc,
diag::attr_UIApplicationMain_multiple); diag::attr_ApplicationMain_multiple,
mainClassDiagKind);
return true; return true;
} }
@@ -1136,12 +1152,14 @@ bool Module::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) {
continue; continue;
if (sf->isScriptMode()) { if (sf->isScriptMode()) {
getASTContext().Diags.diagnose(diagLoc, getASTContext().Diags.diagnose(diagLoc,
diag::attr_UIApplicationMain_with_script); diag::attr_ApplicationMain_with_script,
mainClassDiagKind);
// Note the source file we're reading top-level code from. // Note the source file we're reading top-level code from.
if (auto bufID = sf->getBufferID()) { if (auto bufID = sf->getBufferID()) {
auto fileLoc = getASTContext().SourceMgr.getLocForBufferStart(*bufID); auto fileLoc = getASTContext().SourceMgr.getLocForBufferStart(*bufID);
getASTContext().Diags.diagnose(fileLoc, getASTContext().Diags.diagnose(fileLoc,
diag::attr_UIApplicationMain_script_here); diag::attr_ApplicationMain_script_here,
mainClassDiagKind);
} }
break; break;
} }
@@ -1371,9 +1389,14 @@ bool SourceFile::hasMainClass() const {
ArtificialMainKind SourceFile::getArtificialMainKind() const { ArtificialMainKind SourceFile::getArtificialMainKind() const {
if (getASTContext().LangOpts.EmitNSApplicationMain) if (getASTContext().LangOpts.EmitNSApplicationMain)
return ArtificialMainKind::NSApplicationMain; return ArtificialMainKind::NSApplicationMain;
if (hasMainClass() && getParentModule()->getMainClass()->getAttrs() if (hasMainClass()) {
.hasAttribute<UIApplicationMainAttr>()) auto &attrs = getParentModule()->getMainClass()->getAttrs();
return ArtificialMainKind::UIApplicationMain; if (attrs.hasAttribute<UIApplicationMainAttr>())
return ArtificialMainKind::UIApplicationMain;
if (attrs.hasAttribute<NSApplicationMainAttr>())
return ArtificialMainKind::NSApplicationMain;
llvm_unreachable("main class has no @ApplicationMain attr?!");
}
return ArtificialMainKind::None; return ArtificialMainKind::None;
} }

View File

@@ -51,6 +51,7 @@ public:
IGNORED_ATTR(ClassProtocol) IGNORED_ATTR(ClassProtocol)
IGNORED_ATTR(Final) IGNORED_ATTR(Final)
IGNORED_ATTR(IBDesignable) IGNORED_ATTR(IBDesignable)
IGNORED_ATTR(NSApplicationMain)
IGNORED_ATTR(NSCopying) IGNORED_ATTR(NSCopying)
IGNORED_ATTR(NoReturn) IGNORED_ATTR(NoReturn)
IGNORED_ATTR(ObjC) IGNORED_ATTR(ObjC)
@@ -536,7 +537,14 @@ public:
void visitAccessibilityAttr(AccessibilityAttr *attr); void visitAccessibilityAttr(AccessibilityAttr *attr);
void visitSetterAccessibilityAttr(SetterAccessibilityAttr *attr); void visitSetterAccessibilityAttr(SetterAccessibilityAttr *attr);
void checkApplicationMainAttribute(DeclAttribute *attr,
Identifier Id_ApplicationDelegate,
Identifier Id_Kit,
Identifier Id_ApplicationMain);
void visitNSApplicationMainAttr(NSApplicationMainAttr *attr);
void visitUIApplicationMainAttr(UIApplicationMainAttr *attr); void visitUIApplicationMainAttr(UIApplicationMainAttr *attr);
void visitUnsafeNoObjCTaggedPointerAttr(UnsafeNoObjCTaggedPointerAttr *attr); void visitUnsafeNoObjCTaggedPointerAttr(UnsafeNoObjCTaggedPointerAttr *attr);
void checkOperatorAttribute(DeclAttribute *attr); void checkOperatorAttribute(DeclAttribute *attr);
@@ -808,9 +816,23 @@ void AttributeChecker::visitNSCopyingAttr(NSCopyingAttr *attr) {
} }
void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) { void AttributeChecker::checkApplicationMainAttribute(DeclAttribute *attr,
//if (attr->isInvalid()) Identifier Id_ApplicationDelegate,
// return; Identifier Id_Kit,
Identifier Id_ApplicationMain) {
// %select indexes for ApplicationMain diagnostics.
enum : unsigned {
UIApplicationMainClass,
NSApplicationMainClass,
};
unsigned applicationMainKind;
if (isa<UIApplicationMainAttr>(attr))
applicationMainKind = UIApplicationMainClass;
else if (isa<NSApplicationMainAttr>(attr))
applicationMainKind = NSApplicationMainClass;
else
llvm_unreachable("not an ApplicationMain attr");
auto *CD = dyn_cast<ClassDecl>(D); auto *CD = dyn_cast<ClassDecl>(D);
@@ -821,33 +843,31 @@ void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) {
// The class cannot be generic. // The class cannot be generic.
if (CD->isGenericContext()) { if (CD->isGenericContext()) {
TC.diagnose(attr->getLocation(), TC.diagnose(attr->getLocation(),
diag::attr_generic_UIApplicationMain_not_supported); diag::attr_generic_ApplicationMain_not_supported,
applicationMainKind);
attr->setInvalid(); attr->setInvalid();
return; return;
} }
// @UIApplicationMain classes must conform to UIKit's UIApplicationDelegate // @XXApplicationMain classes must conform to the XXApplicationDelegate
// protocol. // protocol.
auto &C = D->getASTContext(); auto &C = D->getASTContext();
Identifier Id_UIApplicationDelegate
= C.getIdentifier("UIApplicationDelegate");
Identifier Id_UIKit
= C.getIdentifier("UIKit");
auto UIKitModule = C.getLoadedModule(Id_UIKit); auto KitModule = C.getLoadedModule(Id_Kit);
ProtocolDecl *uiApplicationDelegateProto = nullptr; ProtocolDecl *ApplicationDelegateProto = nullptr;
if (UIKitModule) { if (KitModule) {
UnqualifiedLookup lookup(Id_UIApplicationDelegate, UIKitModule, nullptr, UnqualifiedLookup lookup(Id_ApplicationDelegate, KitModule, nullptr,
SourceLoc(), /*IsType=*/true); SourceLoc(), /*IsType=*/true);
uiApplicationDelegateProto = dyn_cast_or_null<ProtocolDecl>( ApplicationDelegateProto = dyn_cast_or_null<ProtocolDecl>(
lookup.getSingleTypeResult()); lookup.getSingleTypeResult());
} }
if (!uiApplicationDelegateProto || if (!ApplicationDelegateProto ||
!TC.conformsToProtocol(CD->getDeclaredType(), uiApplicationDelegateProto, !TC.conformsToProtocol(CD->getDeclaredType(), ApplicationDelegateProto,
CD)) { CD)) {
TC.diagnose(attr->getLocation(), TC.diagnose(attr->getLocation(),
diag::attr_UIApplicationMain_not_UIApplicationDelegate); diag::attr_ApplicationMain_not_ApplicationDelegate,
applicationMainKind);
attr->setInvalid(); attr->setInvalid();
} }
@@ -860,8 +880,8 @@ void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) {
attr->setInvalid(); attr->setInvalid();
// Check that we have the needed symbols in the frameworks. // Check that we have the needed symbols in the frameworks.
UnqualifiedLookup lookupMain(C.getIdentifier("UIApplicationMain"), UnqualifiedLookup lookupMain(Id_ApplicationMain,
UIKitModule, nullptr, SourceLoc(), KitModule, nullptr, SourceLoc(),
/*IsType=*/false); /*IsType=*/false);
for (const auto &result : lookupMain.Results) { for (const auto &result : lookupMain.Results) {
if (result.hasValueDecl()) if (result.hasValueDecl())
@@ -879,6 +899,21 @@ void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) {
} }
} }
void AttributeChecker::visitNSApplicationMainAttr(NSApplicationMainAttr *attr) {
auto &C = D->getASTContext();
checkApplicationMainAttribute(attr,
C.getIdentifier("NSApplicationDelegate"),
C.getIdentifier("AppKit"),
C.getIdentifier("NSApplicationMain"));
}
void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) {
auto &C = D->getASTContext();
checkApplicationMainAttribute(attr,
C.getIdentifier("UIApplicationDelegate"),
C.getIdentifier("UIKit"),
C.getIdentifier("UIApplicationMain"));
}
void AttributeChecker::visitRequiredAttr(RequiredAttr *attr) { void AttributeChecker::visitRequiredAttr(RequiredAttr *attr) {
// The required attribute only applies to constructors. // The required attribute only applies to constructors.
auto ctor = cast<ConstructorDecl>(D); auto ctor = cast<ConstructorDecl>(D);

View File

@@ -5158,6 +5158,7 @@ public:
UNINTERESTING_ATTR(LLDBDebuggerFunction) UNINTERESTING_ATTR(LLDBDebuggerFunction)
UNINTERESTING_ATTR(Mutating) UNINTERESTING_ATTR(Mutating)
UNINTERESTING_ATTR(NonMutating) UNINTERESTING_ATTR(NonMutating)
UNINTERESTING_ATTR(NSApplicationMain)
UNINTERESTING_ATTR(NSCopying) UNINTERESTING_ATTR(NSCopying)
UNINTERESTING_ATTR(NSManaged) UNINTERESTING_ATTR(NSManaged)
UNINTERESTING_ATTR(ObjCBridged) UNINTERESTING_ATTR(ObjCBridged)

View File

@@ -120,3 +120,8 @@
extern NSString *NSViewFrameDidChangeNotification; extern NSString *NSViewFrameDidChangeNotification;
extern NSString *NSViewFocusDidChangeNotification; extern NSString *NSViewFocusDidChangeNotification;
@protocol NSApplicationDelegate
@end

View File

@@ -1,3 +1,6 @@
@import Foundation; @import Foundation;
@protocol NSApplicationDelegate
@end
int NSApplicationMain(int argc, const char *argv[]); int NSApplicationMain(int argc, const char *argv[]);

View File

@@ -1,10 +1,13 @@
// RUN: rm -rf %t/clang-module-cache // RUN: rm -rf %t/clang-module-cache
// RUN: %swift -emit-NSApplicationMain -emit-silgen -parse-as-library -module-cache-path %t/clang-module-cache -target x86_64-apple-macosx10.9 -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | FileCheck %s // RUN: %swift -emit-silgen -parse-as-library -module-cache-path %t/clang-module-cache -target x86_64-apple-macosx10.9 -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | FileCheck %s
// RUN: %swift -emit-NSApplicationMain -emit-ir -parse-as-library -module-cache-path %t/clang-module-cache -target x86_64-apple-macosx10.9 -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | FileCheck %s -check-prefix=IR // RUN: %swift -emit-ir -parse-as-library -module-cache-path %t/clang-module-cache -target x86_64-apple-macosx10.9 -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | FileCheck %s -check-prefix=IR
import Foundation import Foundation
import AppKit import AppKit
@NSApplicationMain
class MyDelegate: NSApplicationDelegate {}
// CHECK-LABEL: sil private @top_level_code // CHECK-LABEL: sil private @top_level_code
// CHECK: function_ref @NSApplicationMain // CHECK: function_ref @NSApplicationMain
// IR-LABEL: define internal void @top_level_code // IR-LABEL: define internal void @top_level_code

View File

@@ -0,0 +1,8 @@
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -parse-as-library -verify -module-cache-path %t/clang-module-cache %s
import AppKit
@NSApplicationMain
class MyDelegate: NSObject, NSApplicationDelegate {
}

View File

@@ -0,0 +1,8 @@
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -parse-as-library -verify -module-cache-path %t/clang-module-cache %s
import AppKit
@NSApplicationMain // expected-error{{generic 'NSApplicationMain' classes are not supported}}
class MyDelegate<T>: NSObject, NSApplicationDelegate {
}

View File

@@ -0,0 +1,10 @@
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -parse-as-library -verify -module-cache-path %t/clang-module-cache %s
import AppKit
class DelegateBase : NSObject, NSApplicationDelegate { }
@NSApplicationMain
class MyDelegate : DelegateBase { }

View File

@@ -0,0 +1,16 @@
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -parse-as-library -verify -module-cache-path %t/clang-module-cache %s
import AppKit
@NSApplicationMain // expected-error{{'NSApplicationMain' attribute can only apply to one class in a module}}
class MyDelegate1: NSObject, NSApplicationDelegate {
}
@NSApplicationMain // expected-error{{'NSApplicationMain' attribute can only apply to one class in a module}}
class MyDelegate2: NSObject, NSApplicationDelegate {
}
@NSApplicationMain // expected-error{{'NSApplicationMain' attribute can only apply to one class in a module}}
class MyDelegate3: NSObject, NSApplicationDelegate {
}

View File

@@ -0,0 +1,8 @@
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -parse-as-library -verify -module-cache-path %t/clang-module-cache %s
import AppKit
@NSApplicationMain // expected-error{{'NSApplicationMain' class must conform to the 'NSApplicationDelegate' protocol}}
class MyNonDelegate {
}

View File

@@ -0,0 +1,13 @@
// This file is a part of the multi-file test driven by 'main.swift'.
// NB: No "-verify"--this file should parse successfully on its own.
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -parse-as-library -module-cache-path %t/clang-module-cache %s
import AppKit
@NSApplicationMain // expected-error{{'NSApplicationMain' attribute cannot be used in a module that contains top-level code}}
class MyDelegate: NSObject, NSApplicationDelegate {
}
func hi() {}

View File

@@ -0,0 +1,5 @@
// expected-note{{top-level code defined in this source file}}
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -parse -verify -module-cache-path %t/clang-module-cache %s %S/delegate.swift
hi()