CF_OPTIONS is defined differently in the SDK based on
a __cplusplus preprocessor branch. As a result, declarations
referencing CF_OPTIONS are mangled differently depending
on if C++ interop is enabled.
This meant a module compiled with cxx interop on could
not be linked with a module compiled without and vice versa.
This patch modifies the mangler such that the mangled names
are consistent. This is achieved by feeding the mangler a modified
AST node that looks like the Objective-C definition of CF_OPTIONS,
even when we have cxx interop enabled.
When the ClangImporter imports a name, it associates it with a
an EffectiveClangContext. An EffectiveClangContext can be thought of
as the Clang scope the declaration will reside in, as far as importing
into Swift is concerned. This helps API notes and NS_SWIFT_NAME
to manipulate the SDK interface presented to Swift users.
When a entry is added to the Swift lookup table, it is associated
with a context. This context is a type and a name, used to effectively
namespace entries in the table. This context is derived from the
EffectiveClangContext associated with the name. This translation is
handled by SwiftLookupTable::translateContextDecl among other machinery.
This method in particular, understands only how to translate a set of
Clang nodes, and fails to create a context in other cases.
Prior to this patch, the EffectiveClangContext of declarations annotated
with UIKIT_EXTERN, with cxx-interop turned on, was a LinkageSpecDecl.
This results in context translation failure, and warnings produced in
SwiftLookupTable::finalizeLookupTable. This patch corrects name import
behavior to skip over the LinkageSpecDecl, and use the enclosing
TranslationUnit instead. This is appropriate and performed by
`determineEffectiveContext` as a LinkageSpecDecl is a so called
"transparent" context. That is its members are semantically declared and
accessible outside the context without additional qualification.
This patch tests using API notes, as that is the method UIKit uses. The
issue could just as easily be surface with a NS_SWIFT_NAME annotation.
Even without any annotation at all, the we would still fail to
translate, though there would likely be no corresponding warnings.
This patch fixes an issue with C++-Interop that has been making it so
that enums under interop were not getting properly looked up and
therefore not getting imported. The reason for this was that the proper
DeclContext was not getting applied when grabbing the decls use by
VisitDecls later in the ClangImporter.
The lookup code at SwiftLookupTable::lookup is given a clang TU which is
what implcitly gets turned into an EffectiveClangContext. The
EffectiveClangContext is the piece that decides which DeclContext to
use. In the case of an extern "C" (ie LinkageSpecDecl), the
EffectiveClangContext was not traversing inside the lexical scope of the
extern "C" as the context for searching the EnumDecl (the NS_OPTIONS
Enum).
This patch adds new behavior when EffectiveClangContext is given a
LinkageSpecDecl. It sets the DeclContext to the lexical decl context.
With this fix in place in the presence of C++-Interop we not only import
the NS_OPTIONS typedef properly, but we also import the enum (and
therefore the EnumConstants) correctly (which are used for getting to
the flags for populating the NS_OPTIONS bitfields.
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.
The C++ interop modules require C++ support. Explicitly require C++ as
a feature when building these modules. This has no impact on the
changes as all the tests enable C++ already.
Simply treat scoped enums as (pre-existing) "non frozen enums". C++
scoped enums are actually imported as Swift enums (unlike other enums)
and no global variables need be created (given their "scoped" nature).
This is a small fix to prevent a crash. This change simply adds another
condition for the "bool" branch that checks if "type" is associated with
a "clang::EnumDecl" with an underlying type of "bool", and if so, treats
"type" as a "Bool".