Another preposition splitting option: directional prepositions.

Swift SVN r15297
This commit is contained in:
Doug Gregor
2014-03-20 21:24:57 +00:00
parent 2cd0940d16
commit 5d0abd9849
8 changed files with 460 additions and 62 deletions

View File

@@ -31,7 +31,9 @@ namespace swift {
/// Split before the last preposition.
BeforePreposition,
/// Split after the last preposition.
AfterPreposition
AfterPreposition,
/// Split before directional prepositions, after other prepositions.
DirectionalPreposition,
};
/// \brief A collection of options that affect the language dialect and

View File

@@ -108,6 +108,9 @@ def enable_source_import : Flag<["-"], "enable-source-import">,
def enable_objc_optional : Flag<["-"], "enable-objc-optional">,
HelpText<"Import Objective-C references using UncheckedOptional">;
def split_objc_selectors : Flag<["-"], "split-objc-selectors">,
HelpText<"Split imported Objective-C selectors based on prepositions">;
def split_objc_selectors_before : Flag<["-"], "split-objc-selectors-before">,
HelpText<"Split imported Objective-C selectors before the last preposition">;

View File

@@ -580,11 +580,15 @@ splitSelectorPieceAt(StringRef selector, unsigned index,
/// Determine whether the given word (which should have its first
/// letter already capitalized) is a preposition.
static bool isPreposition(StringRef word) {
return llvm::StringSwitch<bool>(word)
#define PREPOSITION(Word) .Case(#Word, true)
///
/// The stored boolean indicates whether the preposition has
/// direction.
static Optional<bool> isPreposition(StringRef word) {
return llvm::StringSwitch<Optional<bool>>(word)
#define DIRECTIONAL_PREPOSITION(Word) .Case(#Word, true)
#define PREPOSITION(Word) .Case(#Word, false)
#include "Prepositions.def"
.Default(false);
.Default(Nothing);
}
std::pair<StringRef, StringRef>
@@ -602,7 +606,6 @@ ClangImporter::Implementation::splitFirstSelectorPiece(
unsigned selectorEnd = selector.size();
unsigned wordStart = selector.size();
unsigned wordEnd = wordStart;
bool splitBefore = SplitPrepositions == SelectorSplitKind::BeforePreposition;
for (;;) {
// Skip over any lowercase letters.
while (wordStart > 0 && clang::isLowercase(selector[wordStart-1]))
@@ -617,11 +620,29 @@ ClangImporter::Implementation::splitFirstSelectorPiece(
break;
// If this word is a preposition, and it isn't the last word, split here.
if (wordEnd != selectorEnd &&
isPreposition(selector.substr(wordStart, wordEnd - wordStart))) {
return splitSelectorPieceAt(selector,
splitBefore ? wordStart : wordEnd,
buffer);
if (wordEnd != selectorEnd) {
if (auto isPrep = isPreposition(
selector.substr(wordStart, wordEnd - wordStart))) {
unsigned splitLocation;
switch (SplitPrepositions) {
case SelectorSplitKind::None:
llvm_unreachable("not splitting selectors");
case SelectorSplitKind::BeforePreposition:
splitLocation = wordStart;
break;
case SelectorSplitKind::AfterPreposition:
splitLocation = wordEnd;
break;
case SelectorSplitKind::DirectionalPreposition:
splitLocation = *isPrep ? wordStart : wordEnd;
break;
}
return splitSelectorPieceAt(selector, splitLocation, buffer);
}
}
// Look for the next word.

View File

@@ -16,14 +16,16 @@
# error Define PREPOSITION(Word) before including this file.
#endif
PREPOSITION(Abaft)
PREPOSITION(Aboard)
#ifndef DIRECTIONAL_PREPOSITION
# define DIRECTIONAL_PREPOSITION(Word) PREPOSITION(Word)
#endif
PREPOSITION(About)
PREPOSITION(Above)
DIRECTIONAL_PREPOSITION(Above)
PREPOSITION(Absent)
PREPOSITION(Across)
PREPOSITION(Afore)
PREPOSITION(After)
DIRECTIONAL_PREPOSITION(Afore)
DIRECTIONAL_PREPOSITION(After)
PREPOSITION(Against)
PREPOSITION(Along)
PREPOSITION(Alongside)
@@ -40,84 +42,70 @@ PREPOSITION(Aside)
PREPOSITION(Astride)
PREPOSITION(At)
PREPOSITION(Athwart)
PREPOSITION(Atop)
DIRECTIONAL_PREPOSITION(Atop)
PREPOSITION(Barring)
PREPOSITION(Before)
PREPOSITION(Behind)
PREPOSITION(Below)
PREPOSITION(Beneath)
DIRECTIONAL_PREPOSITION(Before)
DIRECTIONAL_PREPOSITION(Behind)
DIRECTIONAL_PREPOSITION(Below)
DIRECTIONAL_PREPOSITION(Beneath)
PREPOSITION(Beside)
PREPOSITION(Besides)
PREPOSITION(Between)
PREPOSITION(Betwixt)
PREPOSITION(Beyond)
PREPOSITION(But)
DIRECTIONAL_PREPOSITION(Beyond)
PREPOSITION(By)
PREPOSITION(Circa)
PREPOSITION(Concerning)
PREPOSITION(Despite)
PREPOSITION(Down)
DIRECTIONAL_PREPOSITION(Down)
PREPOSITION(During)
PREPOSITION(Except)
PREPOSITION(Excluding)
PREPOSITION(Failing)
PREPOSITION(Following)
DIRECTIONAL_PREPOSITION(Following)
PREPOSITION(For)
PREPOSITION(Forenenst)
PREPOSITION(From)
DIRECTIONAL_PREPOSITION(From)
PREPOSITION(Given)
PREPOSITION(In)
PREPOSITION(Including)
PREPOSITION(Inside)
PREPOSITION(Into)
DIRECTIONAL_PREPOSITION(Inside)
DIRECTIONAL_PREPOSITION(Into)
PREPOSITION(Lest)
PREPOSITION(Like)
PREPOSITION(Mid)
PREPOSITION(Midst)
PREPOSITION(Minus)
PREPOSITION(Modulo)
PREPOSITION(Near)
PREPOSITION(Next)
DIRECTIONAL_PREPOSITION(Minus)
DIRECTIONAL_PREPOSITION(Modulo)
DIRECTIONAL_PREPOSITION(Near)
PREPOSITION(Notwithstanding)
PREPOSITION(Of)
PREPOSITION(Off)
PREPOSITION(On)
PREPOSITION(Onto)
DIRECTIONAL_PREPOSITION(Onto)
PREPOSITION(Opposite)
PREPOSITION(Out)
PREPOSITION(Outside)
DIRECTIONAL_PREPOSITION(Outside)
PREPOSITION(Over)
PREPOSITION(Pace)
PREPOSITION(Past)
DIRECTIONAL_PREPOSITION(Past)
PREPOSITION(Per)
PREPOSITION(Plus)
PREPOSITION(Pro)
PREPOSITION(Qua)
DIRECTIONAL_PREPOSITION(Plus)
PREPOSITION(Regarding)
PREPOSITION(Round)
PREPOSITION(Sans)
PREPOSITION(Save)
PREPOSITION(Since)
DIRECTIONAL_PREPOSITION(Since)
PREPOSITION(Than)
PREPOSITION(Through)
PREPOSITION(Throughout)
PREPOSITION(Times)
PREPOSITION(To)
PREPOSITION(Toward)
PREPOSITION(Towards)
PREPOSITION(Under)
PREPOSITION(Underneath)
DIRECTIONAL_PREPOSITION(Times)
DIRECTIONAL_PREPOSITION(To)
DIRECTIONAL_PREPOSITION(Toward)
DIRECTIONAL_PREPOSITION(Towards)
DIRECTIONAL_PREPOSITION(Under)
DIRECTIONAL_PREPOSITION(Underneath)
PREPOSITION(Unlike)
PREPOSITION(Until)
DIRECTIONAL_PREPOSITION(Until)
PREPOSITION(Unto)
PREPOSITION(Up)
DIRECTIONAL_PREPOSITION(Up)
PREPOSITION(Upon)
PREPOSITION(Versus)
PREPOSITION(Via)
PREPOSITION(Vs)
PREPOSITION(With)
PREPOSITION(Within)
PREPOSITION(Without)
PREPOSITION(Worth)
DIRECTIONAL_PREPOSITION(Within)
DIRECTIONAL_PREPOSITION(Without)
#undef DIRECTIONAL_PREPOSITION
#undef PREPOSITION

View File

@@ -534,9 +534,12 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.EnableObjCOptional = Args.hasArg(OPT_enable_objc_optional);
if (const Arg *A = Args.getLastArg(OPT_split_objc_selectors_before,
if (const Arg *A = Args.getLastArg(OPT_split_objc_selectors,
OPT_split_objc_selectors_before,
OPT_split_objc_selectors_after)) {
if (A->getOption().matches(OPT_split_objc_selectors_before))
if (A->getOption().matches(OPT_split_objc_selectors))
Opts.SplitPrepositions = SelectorSplitKind::DirectionalPreposition;
else if (A->getOption().matches(OPT_split_objc_selectors_before))
Opts.SplitPrepositions = SelectorSplitKind::BeforePreposition;
else
Opts.SplitPrepositions = SelectorSplitKind::AfterPreposition;

View File

@@ -0,0 +1,376 @@
// RUN: rm -rf %t/clang-module-cache
// RUN: %swift %clang-importer-sdk -emit-sil -module-cache-path %t/clang-module-cache -I %S/Inputs/custom-modules -target x86_64-apple-darwin13 -split-objc-selectors %s -verify
// RUN: ls -lR %t/clang-module-cache | grep ObjectiveC.pcm
import AppKit
import objc_ext
import TestProtocols
func testAnyObject(obj: AnyObject) {
var optStr = obj.nsstringProperty
}
// Construction
func construction() {
var b = B()
}
// Subtyping
func treatBAsA(b: B) -> A {
return b
}
// Instance method invocation
func instanceMethods(b: B) {
var i = b.method(1, withFloat:2.5)
i = i + b.method(1, withDouble:2.5)
// BOOL
b.setEnabled(true)
// SEL
b.performSelector("isEqual:", withObject:b)
// Renaming of redundant parameters.
b.performAdd(1, withValue:2, withValue2:3, withValue:4)
// Renaming of redundant parameters.
b.performMultiplyWith(value:1, value:2)
// Splitting does not split a preposition at the end
b.moveFor(5)
// Both class and instance methods exist.
b.description()
b.instanceTakesObjectClassTakesFloat(b)
b.instanceTakesObjectClassTakesFloat(2.0) // expected-error{{does not type-check}}
}
// Class method invocation
func classMethods(b: B, other: NSObject) {
var i = B.classMethod()
i += B.classMethod(1)
i += B.classMethod(1, withInt:2)
i += b.classMethod() // expected-error{{'B' does not have a member named 'classMethod'}}
// Both class and instance methods exist.
B.description()
B.instanceTakesObjectClassTakesFloat(2.0)
B.instanceTakesObjectClassTakesFloat(other) // expected-error{{does not type-check}}
// Call an instance method of NSObject.
var c: AnyClass = B.myClass() // no-warning
c = b.myClass() // no-warning
}
// Instance method invocation on extensions
func instanceMethodsInExtensions(b: B) {
b.method(1, onCat1:2.5)
b.method(1, onExtA:2.5)
b.method(1, onExtB:2.5)
b.method(1, separateExtMethod:3.5)
let m1 = b.method:onCat1: // expected-error{{partial application of Objective-C method is not allowed}}
m1(1, 2.5)
let m2 = b.method:onExtA: // expected-error{{partial application of Objective-C method is not allowed}}
m2(1, 2.5)
let m3 = b.method:onExtB: // expected-error{{partial application of Objective-C method is not allowed}}
m3(1, 2.5)
let m4 = b.method:separateExtMethod: // expected-error{{partial application of Objective-C method is not allowed}}
m4(1, 2.5)
}
func dynamicLookupMethod(b: AnyObject) {
if let m5 = b.method:separateExtMethod: {
m5(1, 2.5)
}
}
// Properties
func properties(b: B) {
var i = b.counter
b.counter = i + 1
i = i + b.readCounter
b.readCounter = i + 1 // expected-error{{cannot assign to the result of this expression}}
b.setCounter(5) // expected-error{{'B' does not have a member named 'setCounter'}}
// Informal properties in Objective-C map to methods, not variables.
b.informalProp()
// An informal property cannot be made formal in a subclass. The
// formal property is simply ignored.
b.informalMadeFormal()
b.informalMadeFormal = i // expected-error{{cannot assign to the result of this expression}}
b.setInformalMadeFormal(5)
b.overriddenProp = 17
// Dynamic properties.
var obj : AnyObject = b
var optStr = obj.nsstringProperty
if optStr {
var s : String = optStr!
}
}
// Construction.
func newConstruction(a: A, aproxy: AProxy) {
var b : B = B()
b = B(17)
b = B(withInt:17)
b = B(withDouble:17.5, 3.14159)
b = B(BBB:b)
b = B(forWorldDomination:())
b = B(17, andDouble : 3.14159)
b = B.newWith(a:a)
B.alloc()._initFoo()
b.notAnInit()
// init methods are not imported by themselves.
b.initWithInt(17) // expected-error{{'B' does not have a member named 'initWithInt'}}
// init methods on non-NSObject-rooted classes
AProxy(5)
}
// Indexed subscripting
func indexedSubscripting(b: B, idx: Int, a: A) {
b[idx] = a
var a2 = (b[idx] as A)!
}
// Keyed subscripting
func keyedSubscripting(b: B, idx: A, a: A) {
b[a] = a
var a2 = (b[a] as A)!
}
// Typed indexed subscripting
func checkHive(hive: Hive, b: B) {
var b2 = (hive.bees[5] as B)!
b2.method(1, withFloat:1.5)
}
// Protocols
func testProtocols(b: B, bp: BProto) {
var bp2 : BProto = b
var b2 : B = bp // expected-error{{'BProto' is not convertible to 'B'}}
bp.method(1, withFloat:2.5)
bp.method(1, withDouble:2.5) // expected-error{{expression does not type-check}}
bp2 = b.getAsProto()
var c1 : Cat1Proto = b
var bcat1 = b.getAsProtoWithCat()
c1 = bcat1
bcat1 = c1 // expected-error{{type 'Cat1Proto' does not conform to protocol 'BProto'}}
}
// Methods only defined in a protocol
func testProtocolMethods(b: B) {
b.otherMethod(1, withFloat:3.14159)
b.p2Method()
b.initViaP2(3.14159, second:3.14159)
// Imported constructor.
var b2 = B(3.14159, second:3.14159)
}
func testId(x: AnyObject) {
x.performSelector!("foo:", x)
}
class MySubclass : B {
// Override a regular method.
@override func anotherMethodOnB() {}
// Override a category method
@override func anotherCategoryMethod() {}
}
func getDescription(array: NSArray) {
array.description()
}
// Method overriding with unfortunate ordering.
func overridingTest(srs: SuperRefsSub) {
var rs : RefedSub
rs.overridden()
}
func almostSubscriptableValueMismatch(as1: AlmostSubscriptable, a: A) {
// FIXME: Crummy diagnostic.
as1[a] // expected-error{{'AlmostSubscriptable' does not have a member named 'subscript'}}
}
func almostSubscriptableKeyMismatch(bc: BadCollection, key: NSString) {
// FIXME: We end up importing this as read-only due to the mismatch between
// getter/setter element types.
var v : AnyObject = bc[key]
}
func almostSubscriptableKeyMismatchInherited(bc: BadCollectionChild,
key: String) {
var value : AnyObject = bc[key] // no-warning, inherited from parent
bc[key] = value // expected-error{{expression does not type-check}}
}
func almostSubscriptableKeyMismatchInherited(roc: ReadOnlyCollectionChild,
key: String) {
var value : AnyObject = roc[key] // no-warning, inherited from parent
roc[key] = value // expected-error{{expression does not type-check}}
}
// Use of 'Class' via dynamic lookup.
func classAnyObject(obj: NSObject) {
obj.myClass().description!()
}
// Protocol conformances
class Wobbler : NSWobbling {
func wobble() { }
func returnMyself() -> Self { return self }
}
func optionalMemberAccess(w: NSWobbling) {
w.wobble()
w.wibble() // expected-error{{'() -> $T3' is not identical to '(() -> Void)?'}}
var x: AnyObject = w[5] // expected-error{{type 'AnyObject?' does not conform to protocol 'AnyObject'}}
}
func protocolInheritance(s: NSString) {
var coding: NSCoding = s
}
func ivars(hive: Hive) {
hive.bees.description() // no-warning
hive.queen.description() // expected-error{{'Hive' does not have a member named 'queen'}}
}
class NSObjectable : NSObjectProtocol {
@objc func description() -> AnyObject { }
}
// Properties with custom accessors
func customAccessors(hive: Hive, bee: B) {
println(hive.makingHoney)
println(hive.isMakingHoney()) // expected-error{{'Hive' does not have a member named 'isMakingHoney'}}
hive.setMakingHoney(true) // expected-error{{'Hive' does not have a member named 'setMakingHoney'}}
hive.guard.description() // okay
hive.guard.description!() // no-warning
hive.guard = bee // no-warning
}
// instancetype/Dynamic Self invocation.
func testDynamicSelf(queen: B, wobbler: NSWobbling) {
var hive = Hive()
// Factory method with instancetype result.
var hive1 = Hive.hiveWith(queen: queen)
hive1 = hive
hive = hive1
// Instance method with instancetype result.
var hive2 = hive.visit()
hive2 = hive
hive = hive2
// Instance method on a protocol with instancetype result.
var wobbler2 = wobbler.returnMyself()
var wobbler: NSWobbling = wobbler2
wobbler2 = wobbler
}
func testRepeatedProtocolAdoption(w: NSWindow) {
w.description()
}
class ProtocolAdopter1 : FooProto {
var bar: CInt // no-warning
init() { bar = 5 }
}
class ProtocolAdopter2 : FooProto {
var bar: CInt {
get { return 42 }
set { /* do nothing! */ }
}
}
class ProtocolAdopterBad1 : FooProto { // expected-error{{type 'ProtocolAdopterBad1' does not conform to protocol 'FooProto'}}
var bar: Int = 0 // expected-note{{candidate has non-matching type 'Int'}}
}
class ProtocolAdopterBad2 : FooProto { // expected-error{{type 'ProtocolAdopterBad2' does not conform to protocol 'FooProto'}}
let bar: CInt = 0 // expected-note{{candidate is not settable, but protocol requires it}}
}
class ProtocolAdopterBad3 : FooProto { // expected-error{{type 'ProtocolAdopterBad3' does not conform to protocol 'FooProto'}}
var bar: CInt { // expected-note{{candidate is not settable, but protocol requires it}}
return 42
}
}
// Subclassing and designated initializers
func testNSInterestingDesignated() {
NSInterestingDesignated()
NSInterestingDesignated(withString:"hello")
NSInterestingDesignatedSub()
NSInterestingDesignatedSub(withString:"hello")
}
class MyDocument1 : NSDocument {
init() {
super.init()
}
}
func createMyDocument1() {
var md = MyDocument1()
md = MyDocument1(withURL: "http://llvm.org")
}
class MyDocument2 : NSDocument {
init withURL(url: String) {
return super.init(withURL: url) // expected-error{{must call a designated initializer of the superclass 'NSDocument'}}
}
}
class MyDocument3 : NSAwesomeDocument {
init() {
super.init()
}
}
func createMyDocument3() {
var md = MyDocument3()
md = MyDocument3(withURL: "http://llvm.org")
}
class MyInterestingDesignated : NSInterestingDesignatedSub {
init withString(str: String) {
super.init(withString: str)
}
init withInt(i: Int) {
super.init() // expected-error{{must call a designated initializer of the superclass 'NSInterestingDesignatedSub'}}
}
}
func createMyInterestingDesignated() {
var md = MyInterestingDesignated(withURL: "http://llvm.org")
}
func testNoReturn(a : NSAwesomeDocument) -> Int {
a.noReturnMethod(42)
return 17 // TODO: In principle, we should produce an unreachable code diagnostic here.
}
func splitting(doc: NSDocument, url: NSURL) {
doc.copyDocument(fromURL: url, toURL: url)
}

View File

@@ -13,6 +13,8 @@
@interface NSDocument : NSObject
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithURL:(NSString*)url;
- (void)copyDocumentFromURL:(NSURL*)fromURL toURL:(NSURL*)toURL;
@end
@interface NSAwesomeDocument : NSDocument

View File

@@ -140,3 +140,6 @@ typedef NS_OPTIONS(NSUInteger, NSSingleOptions) {
@end
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
@interface NSURL : NSObject
@end