Skip to content

[5.9] revert "Revert "Revert "[cxx-interop] Import custom NS_OPTIONS correctly""" #68855

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 3 commits into from
Sep 29, 2023
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
3 changes: 3 additions & 0 deletions include/swift/AST/ClangModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ class ClangModuleLoader : public ModuleLoader {
virtual EffectiveClangContext getEffectiveClangContext(
const NominalTypeDecl *nominal) = 0;

virtual const clang::TypedefType *
getTypeDefForCXXCFOptionsDefinition(const clang::Decl *candidateDecl) = 0;

virtual SourceLoc importSourceLocation(clang::SourceLocation loc) = 0;
};

Expand Down
4 changes: 2 additions & 2 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,8 @@ class ClangImporter final : public ClangModuleLoader {
/// Enable the symbolic import experimental feature for the given callback.
void withSymbolicFeatureEnabled(llvm::function_ref<void(void)> callback);

static const clang::TypedefType *getTypedefForCXXCFOptionsDefinition(
const clang::Decl *candidateDecl, const ASTContext &ctx);
const clang::TypedefType *getTypeDefForCXXCFOptionsDefinition(
const clang::Decl *candidateDecl) override;

SourceLoc importSourceLocation(clang::SourceLocation loc) override;
};
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2551,8 +2551,8 @@ ASTMangler::getTypeDefForCXXCFOptionsDefinition(const ValueDecl *decl) {
if (!clangDecl)
return nullptr;

auto &ctx = decl->getASTContext();
return ClangImporter::getTypedefForCXXCFOptionsDefinition(clangDecl, ctx);
const auto &clangModuleLoader = decl->getASTContext().getClangModuleLoader();
return clangModuleLoader->getTypeDefForCXXCFOptionsDefinition(clangDecl);
}

const clang::NamedDecl *
Expand Down
22 changes: 10 additions & 12 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6958,23 +6958,26 @@ void ClangImporter::withSymbolicFeatureEnabled(
oldImportSymbolicCXXDecls.get());
}

const clang::TypedefType *ClangImporter::getTypedefForCXXCFOptionsDefinition(
const clang::Decl *candidateDecl, const ASTContext &ctx) {
if (!ctx.LangOpts.EnableCXXInterop)
const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
const clang::Decl *candidateDecl) {

if (!Impl.SwiftContext.LangOpts.EnableCXXInterop)
return nullptr;

auto enumDecl = dyn_cast<clang::EnumDecl>(candidateDecl);
if (!enumDecl)
return nullptr;

if (!enumDecl->getDeclName().isEmpty())
return nullptr;

const clang::ElaboratedType *elaboratedType =
enumDecl->getIntegerType()->getAs<clang::ElaboratedType>();
dyn_cast<clang::ElaboratedType>(enumDecl->getIntegerType().getTypePtr());
if (auto typedefType =
elaboratedType
? dyn_cast<clang::TypedefType>(elaboratedType->desugar())
: enumDecl->getIntegerType()->getAs<clang::TypedefType>()) {
: dyn_cast<clang::TypedefType>(
enumDecl->getIntegerType().getTypePtr())) {
auto enumExtensibilityAttr =
elaboratedType
? enumDecl->getAttr<clang::EnumExtensibilityAttr>()
Expand All @@ -6987,13 +6990,8 @@ const clang::TypedefType *ClangImporter::getTypedefForCXXCFOptionsDefinition(
enumExtensibilityAttr->getExtensibility() ==
clang::EnumExtensibilityAttr::Open &&
hasFlagEnumAttr) {
// Make sure the typedef is marked as unavailable in Swift.
auto typedefDecl = typedefType->getDecl();
for (auto *attr :
typedefDecl->specific_attrs<clang::AvailabilityAttr>()) {
if (attr->getPlatform()->getName() == "swift")
return typedefType;
}
return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType
: nullptr;
}
}

Expand Down
60 changes: 37 additions & 23 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2642,30 +2642,44 @@ ArgumentAttrs ClangImporter::Implementation::inferDefaultArgument(
}
} else if (const clang::TypedefType *typedefType =
type->getAs<clang::TypedefType>()) {
clang::TypedefNameDecl *typedefDecl = typedefType->getDecl();
// Find the next decl in the same context. If this typedef is a part of an
// NS/CF_OPTIONS declaration, the next decl will be an enum.
auto declsInContext = typedefDecl->getDeclContext()->decls();
auto declIter = llvm::find(declsInContext, typedefDecl);
if (declIter != declsInContext.end())
declIter++;
if (declIter != declsInContext.end()) {
if (auto enumDecl = dyn_cast<clang::EnumDecl>(*declIter)) {
if (auto cfOptionsTy =
ClangImporter::getTypedefForCXXCFOptionsDefinition(
enumDecl, nameImporter.getContext())) {
if (cfOptionsTy->getDecl() == typedefDecl) {
auto enumName = typedefDecl->getName();
ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true,
enumName);
for (auto word : llvm::reverse(camel_case::getWords(enumName))) {
if (camel_case::sameWordIgnoreFirstCase(word, "options")) {
argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
}
}
return argumentAttrs;
}
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
// If we've taken this branch it means we have an enum type, and it is
// likely an integer or NSInteger that is being used by NS/CF_OPTIONS to
// behave like a C enum in the presence of C++.
auto enumName = typedefType->getDecl()->getName();
ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true, enumName);
auto camelCaseWords = camel_case::getWords(enumName);
for (auto it = camelCaseWords.rbegin(); it != camelCaseWords.rend();
++it) {
auto word = *it;
auto next = std::next(it);
if (camel_case::sameWordIgnoreFirstCase(word, "options")) {
argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
return argumentAttrs;
}
if (camel_case::sameWordIgnoreFirstCase(word, "units"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "domain"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "action"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "event"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "events") &&
next != camelCaseWords.rend() &&
camel_case::sameWordIgnoreFirstCase(*next, "control"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "state"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "unit"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "position") &&
next != camelCaseWords.rend() &&
camel_case::sameWordIgnoreFirstCase(*next, "scroll"))
return argumentAttrs;
if (camel_case::sameWordIgnoreFirstCase(word, "edge"))
return argumentAttrs;
}
}
}
Expand Down
60 changes: 21 additions & 39 deletions test/Interop/Cxx/enum/Inputs/c-enums-withOptions-omit.h
Original file line number Diff line number Diff line change
@@ -1,57 +1,39 @@
typedef unsigned NSUInteger;

#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open)))
#if (__cplusplus)
#define CF_OPTIONS(_type, _name) __attribute__((availability(swift,unavailable))) _type _name; enum __CF_OPTIONS_ATTRIBUTES : _name
#else
#define CF_OPTIONS(_type, _name) enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; enum _name : _type
#endif

typedef CF_OPTIONS(NSUInteger, NSEnumerationOptions) {
NSEnumerationConcurrent = (1UL << 0),
NSEnumerationReverse = (1UL << 1),
};
// Enum usage that is bitwise-able and assignable in C++, aka how CF_OPTIONS
// does things.
typedef int __attribute__((availability(swift, unavailable))) NSEnumerationOptions;
enum : NSEnumerationOptions { NSEnumerationConcurrent, NSEnumerationReverse };

@interface NSSet
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts ;
@end

typedef CF_OPTIONS(NSUInteger, NSOrderedCollectionDifferenceCalculationOptions) {
typedef int __attribute__((availability(swift, unavailable))) NSOrderedCollectionDifferenceCalculationOptions;
enum : NSOrderedCollectionDifferenceCalculationOptions {
NSOrderedCollectionDifferenceCalculationOptions1,
NSOrderedCollectionDifferenceCalculationOptions2
};

typedef CF_OPTIONS(NSUInteger, NSCalendarUnit) {
NSCalendarUnit1,
NSCalendarUnit2
};
typedef int __attribute__((availability(swift, unavailable))) NSCalendarUnit;
enum : NSCalendarUnit { NSCalendarUnit1, NSCalendarUnit2 };

typedef CF_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
NSSearchPathDomainMask1,
NSSearchPathDomainMask2
};
typedef int __attribute__((availability(swift, unavailable))) NSSearchPathDomainMask;
enum : NSSearchPathDomainMask { NSSearchPathDomainMask1, NSSearchPathDomainMask2 };

typedef CF_OPTIONS(NSUInteger, NSControlCharacterAction) {
NSControlCharacterAction1,
NSControlCharacterAction2
};
typedef int __attribute__((availability(swift, unavailable))) NSControlCharacterAction;
enum : NSControlCharacterAction { NSControlCharacterAction1, NSControlCharacterAction2 };

typedef CF_OPTIONS(NSUInteger, UIControlState) {
UIControlState1,
UIControlState2
};
typedef int __attribute__((availability(swift, unavailable))) UIControlState;
enum : UIControlState { UIControlState1, UIControlState2 };

typedef CF_OPTIONS(NSUInteger, UITableViewCellStateMask) {
UITableViewCellStateMask1,
UITableViewCellStateMask2
};
typedef int __attribute__((availability(swift, unavailable))) UITableViewCellStateMask;
enum : UITableViewCellStateMask { UITableViewCellStateMask1, UITableViewCellStateMask2 };

typedef CF_OPTIONS(NSUInteger, UIControlEvents) {
UIControlEvents1,
UIControlEvents2
};
typedef int __attribute__((availability(swift, unavailable))) UIControlEvents;
enum : UIControlEvents { UIControlEvents1, UIControlEvents2 };

typedef CF_OPTIONS(NSUInteger, UITableViewScrollPosition) {
typedef int __attribute__((availability(swift, unavailable)))
UITableViewScrollPosition;
enum : UITableViewScrollPosition {
UITableViewScrollPosition1,
UITableViewScrollPosition2
};
Expand Down
6 changes: 0 additions & 6 deletions test/Interop/Cxx/objc-correctness/Inputs/customNSOptions.h

This file was deleted.

4 changes: 0 additions & 4 deletions test/Interop/Cxx/objc-correctness/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ module CxxClassWithNSStringInit {
requires cplusplus
}

module CustomNSOptions {
header "customNSOptions.h"
}

module NSOptionsMangling {
header "NSOptionsMangling.h"
}
Expand Down
16 changes: 0 additions & 16 deletions test/Interop/Cxx/objc-correctness/custom-nsoptions.swift

This file was deleted.