Skip to content

Commit c99b417

Browse files
committed
[ClangImporter] Handle underscore-punctuated enum names (used by CoreMedia).
<rdar://problem/17594425> Swift SVN r19732
1 parent d347bb5 commit c99b417

File tree

5 files changed

+84
-14
lines changed

5 files changed

+84
-14
lines changed

lib/Basic/StringExtras.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,32 @@ bool swift::isLinkingVerb(StringRef word) {
4848
void WordIterator::computeNextPosition() const {
4949
assert(Position < String.size() && "Already at end of string");
5050

51-
// Skip over any uppercase letters at the beginning of the word.
5251
unsigned i = Position, n = String.size();
52+
53+
// Treat _ as a word on its own. Don't coalesce.
54+
if (String[i] == '_') {
55+
NextPosition = i + 1;
56+
NextPositionValid = true;
57+
return;
58+
}
59+
60+
// Skip over any uppercase letters at the beginning of the word.
5361
while (i < n && clang::isUppercase(String[i]))
5462
++i;
5563

5664
// If there was more than one uppercase letter, this is an
5765
// acronym.
5866
if (i - Position > 1) {
5967
// If we hit the end of the string, that's it. Otherwise, this
60-
// word ends at the last uppercase letter, so that the next word
61-
// starts with the last uppercase letter.
68+
// word ends before the last uppercase letter if the next word is alphabetic
69+
// (URL_Loader) or after the last uppercase letter if it's not (UTF_8).
6270
NextPosition = (i == n || !clang::isLowercase(String[i])) ? i : i-1;
6371
NextPositionValid = true;
6472
return;
6573
}
6674

6775
// Skip non-uppercase letters.
68-
while (i < n && !clang::isUppercase(String[i]))
76+
while (i < n && !clang::isUppercase(String[i]) && String[i] != '_')
6977
++i;
7078

7179
NextPosition = i;
@@ -75,18 +83,28 @@ void WordIterator::computeNextPosition() const {
7583
void WordIterator::computePrevPosition() const {
7684
assert(Position > 0 && "Already at beginning of string");
7785

78-
// While we see non-uppercase letters, keep moving back.
7986
unsigned i = Position;
80-
while (i > 0 && !clang::isUppercase(String[i-1]))
87+
88+
// While we see non-uppercase letters, keep moving back.
89+
while (i > 0 && !clang::isUppercase(String[i-1]) && String[i-1] != '_')
8190
--i;
8291

8392
// If we found any lowercase letters, this was a normal camel case
8493
// word (not an acronym).
8594
if (i < Position) {
86-
// If we hit the beginning of the string, that's it. Otherwise,
87-
// this word starts at the uppercase letter that terminated the
88-
// search above.
89-
PrevPosition = (i == 0 || !clang::isLowercase(String[i])) ? i : i-1;
95+
// If we hit the beginning of the string, that's it. Otherwise, this
96+
// word starts with an uppercase letter if the next word is alphabetic
97+
// (URL_Loader) or after the last uppercase letter if it's not (UTF_8).
98+
PrevPosition = i;
99+
if (i != 0 && clang::isLowercase(String[i]) && String[i-1] != '_')
100+
--PrevPosition;
101+
PrevPositionValid = true;
102+
return;
103+
}
104+
105+
// Treat _ as a word on its own. Don't coalesce.
106+
if (String[i-1] == '_') {
107+
PrevPosition = i - 1;
90108
PrevPositionValid = true;
91109
return;
92110
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,18 +1317,21 @@ namespace {
13171317
if (!commonPrefix.empty()) {
13181318
StringRef checkPrefix = commonPrefix;
13191319

1320+
// Account for the 'EnumName_Constant' convention on enumerators.
1321+
if (checkPrefix.back() == '_' && !followedByNonIdentifier)
1322+
checkPrefix = checkPrefix.drop_back();
1323+
13201324
// Account for the 'kConstant' naming convention on enumerators.
1321-
bool dropKPrefix = false;
13221325
if (checkPrefix[0] == 'k' &&
13231326
((checkPrefix.size() >= 2 && clang::isUppercase(checkPrefix[1])) ||
13241327
!followedByNonIdentifier)) {
1325-
checkPrefix = checkPrefix.substr(1);
1326-
dropKPrefix = true;
1328+
checkPrefix = checkPrefix.drop_front();
13271329
}
13281330

13291331
StringRef commonWithEnum = getCommonPluralPrefix(checkPrefix,
13301332
enumName.str());
1331-
commonPrefix = commonPrefix.slice(0, commonWithEnum.size()+dropKPrefix);
1333+
size_t delta = commonPrefix.size() - checkPrefix.size();
1334+
commonPrefix = commonPrefix.slice(0, commonWithEnum.size() + delta);
13321335
}
13331336
Impl.EnumConstantNamePrefixes.insert({decl, commonPrefix});
13341337
}

test/ClangModules/objc_ns_options.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ let bitmapFormat2: NSBitmapFormat2 = .NSU16a | .NSU32a;
4040
let bitmapFormat3: NSBitmapFormat3 = .NSU16b | .NSS32b;
4141
let bitmapFormat4: NSUBitmapFormat4 = .NSU16c | .NSU32c;
4242
let bitmapFormat5: NSABitmapFormat5 = .NSAA16d | .NSAB32d;
43+
44+
// Drop trailing underscores when possible.
45+
let timeFlags: CMTimeFlags = .Valid | .HasBeenRounded
46+
let timeFlags2: CMTimeFlagsWithNumber = ._Valid | ._888

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,21 @@ typedef NS_OPTIONS(NSInteger, CBCharacteristicProperties) {
269269
CBCharacteristicPropertyIndicateEncryptionRequired /*NS_ENUM_AVAILABLE(10_9, 6_0)*/ = 0x200
270270
};
271271

272+
// From CoreMedia
273+
typedef CF_OPTIONS(unsigned int, CMTimeFlags) {
274+
kCMTimeFlags_Valid = 1UL<<0,
275+
kCMTimeFlags_HasBeenRounded = 1UL<<1,
276+
kCMTimeFlags_PositiveInfinity = 1UL<<2,
277+
kCMTimeFlags_NegativeInfinity = 1UL<<3,
278+
kCMTimeFlags_Indefinite = 1UL<<4,
279+
kCMTimeFlags_ImpliedValueFlagsMask = kCMTimeFlags_PositiveInfinity | kCMTimeFlags_NegativeInfinity | kCMTimeFlags_Indefinite
280+
};
281+
typedef CF_OPTIONS(unsigned int, CMTimeFlagsWithNumber) {
282+
kCMTimeFlagsWithNumber_Valid = 1UL<<0,
283+
kCMTimeFlagsWithNumber_888 = 1UL<<1,
284+
};
285+
286+
272287
// Contrived name with a plural "-es"...normally these are "beeps".
273288
typedef NS_OPTIONS(NSInteger, AlertBuzzes) {
274289
AlertBuzzFunk,

unittests/Basic/StringExtrasTest.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,36 @@ TEST(CamelCaseWordsTest, Iteration) {
5656
EXPECT_EQ(iter, words.end());
5757
}
5858

59+
TEST(CamelCaseWordsTest, WordsWithUnderscores) {
60+
auto words = camel_case::getWords("CF_Flags_789");
61+
EXPECT_EQ(5, std::distance(words.begin(), words.end()));
62+
63+
auto iter = words.begin();
64+
EXPECT_EQ("CF", *iter++);
65+
EXPECT_EQ("_", *iter++);
66+
EXPECT_EQ("Flags", *iter++);
67+
EXPECT_EQ("_", *iter++);
68+
EXPECT_EQ("789", *iter++);
69+
EXPECT_EQ("789", *--iter);
70+
EXPECT_EQ("_", *--iter);
71+
EXPECT_EQ("Flags", *--iter);
72+
EXPECT_EQ("_", *--iter);
73+
EXPECT_EQ("CF", *--iter);
74+
75+
auto manyUnderscores = camel_case::getWords("___ABC");
76+
EXPECT_EQ(4, std::distance(manyUnderscores.begin(), manyUnderscores.end()));
77+
78+
iter = manyUnderscores.begin();
79+
EXPECT_EQ("_", *iter++);
80+
EXPECT_EQ("_", *iter++);
81+
EXPECT_EQ("_", *iter++);
82+
EXPECT_EQ("ABC", *iter++);
83+
EXPECT_EQ("ABC", *--iter);
84+
EXPECT_EQ("_", *--iter);
85+
EXPECT_EQ("_", *--iter);
86+
EXPECT_EQ("_", *--iter);
87+
}
88+
5989
TEST(ToLowercaseTest, Words) {
6090
llvm::SmallString<64> scratch;
6191

0 commit comments

Comments
 (0)