Skip to content

Commit a0985a0

Browse files
committed
[C++-Interop] Teach omitNeedlessWords to handle raw integer C-enums in C++
As I understand it, enums in C++ do not allow for bitwise operations that can also be assigned or returned as the same enum type. As a result there are macros in (Core)Foundation like NS/CF_OPTIONS that produce enums differently depending on #if __cplusplus or not. Because of this, code in omitNeedlessWordsInFunctionName and subsequently inferDefaultArgument in the ClangImporter that is in charge of replacing "needless words" from method and enum names does not trigger in the case of C++ because it is looking for EnumDecls that do not exists because they are actually typedefs on wrap integers or NSIntegers. This change attempts to do the renaming off of the typedef alone when such code exists. Special thanks to @bulbazord (Alex Langford) for taking the time to investigate this issue.
1 parent 29cd551 commit a0985a0

File tree

4 files changed

+35
-0
lines changed

4 files changed

+35
-0
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,6 +2431,19 @@ DefaultArgumentKind ClangImporter::Implementation::inferDefaultArgument(
24312431
return DefaultArgumentKind::EmptyArray;
24322432
}
24332433
}
2434+
} else if (const clang::TypedefType *typedefType =
2435+
type->getAs<clang::TypedefType>()) {
2436+
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
2437+
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
2438+
// If we've taken this branch it means we have an enum type, and it is
2439+
// likely an integer or NSInteger that is being used by NS/CF_OPTIONS to
2440+
// behave like a C enum in the presence of C++.
2441+
auto enumName = typedefType->getDecl()->getDeclName().getAsString();
2442+
for (auto word : llvm::reverse(camel_case::getWords(enumName))) {
2443+
if (camel_case::sameWordIgnoreFirstCase(word, "options"))
2444+
return DefaultArgumentKind::EmptyArray;
2445+
}
2446+
}
24342447
}
24352448

24362449
// NSDictionary arguments default to [:] (or nil, if nullable) if "options",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Enum usage that is bitwise-able and assignable in C++, aka how CF_OPTIONS
2+
// does things.
3+
typedef int __attribute__((availability(swift, unavailable))) NSEnumerationOptions;
4+
enum : NSEnumerationOptions { NSEnumerationConcurrent, NSEnumerationReverse };
5+
6+
@interface NSSet
7+
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts ;
8+
@end

test/Interop/Cxx/enum/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ module AnonymousWithSwiftName {
1212
header "anonymous-with-swift-name.h"
1313
requires cplusplus
1414
}
15+
16+
module CenumsWithOptionsOmit {
17+
header "c-enums-withOptions-omit.h"
18+
requires cplusplus
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=CenumsWithOptionsOmit -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
2+
// REQUIRES: objc_interop
3+
4+
import CenumsWithOptionsOmit
5+
6+
// CHECK: class NSSet {
7+
// CHECK-NEXT: class func enumerateObjects(options
8+
// CHECK-NEXT: func enumerateObjects(options
9+
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "enumerateObjects(options:)")

0 commit comments

Comments
 (0)