Eliminates extraneous newlines between top-level Objective-C declarations in `-emit-objc-header` headers. Specifically, there should now always be exactly one—no more, no less—empty line between `@end` and whatever follows it.
Besides being more aesthetically pleasing, this eliminates ordering-dependent behavior where PrintAsClang would print an extra newline when visiting an empty extension, which meant that the order in which empty and non-empty extensions were visited during printing could result in whitespace differences in the compiler output. Printing the blank line is now conditional on whether `tell()` indicates that characters were actually written to the output.
Fixes rdar://143533893.
When printing an ObjC member into a header with an `Int` parameter or result, PrintAsClang would look up any imported Objective-C member it overrode to see if ClangImporter imported `NSUInteger` as `Int`, and if so, would print `NSUInteger` instead of `NSInteger`. However, it did not do the same for protocol requirements the member witnessed. Correct this oversight.
Fixes rdar://124300674.
Previously we only excluded implicitly-created overrides, but it turns out explicit overrides are just as problematic and just as unnecessary.
Fixes rdar://123633538.
`module.map` as a module map name has been discouraged since 2014, and
Clang will soon warn on its usage. This patch renames all instances of
`module.map` in the Swift tests to `module.modulemap` in preparation
for this change to Clang.
rdar://106123303
When swift-frontend is explicitly passed the pch file as bridging header
on command-line through `-import-objc-header`, it needs to print the
original source file name if needed to the generated objc header.
rdar://109411245
PrintAsClang was not aware of @objcImplementation. Teach it to skip over both member implementations (which are declared in handwritten headers, so printing them would be a redeclaration) and overrides (which may not be valid in a category, if e.g. they are declaring a designated initializer).
Fixes rdar://106035578.
Currently headers produced with `-emit-objc-header` /
`-emit-objc-header-path` produce headers that include modular imports.
If the consumer wishes to operate without modules enabled, these headers
cannot be used. This patch introduces a new flag
(`-emit-clang-header-nonmodular-includes`) that when enabled
attempts to argument each modular import included in such a header with
a set of equivalent textual imports.
Currently headers produced with `-emit-objc-header` /
`-emit-objc-header-path` produce headers that include modular imports.
If the consumer wishes to operate without modules enabled, these headers
cannot be used. This patch introduces a new flag
(`-emit-clang-header-nonmodular-includes`) that when enabled
attempts to argument each modular import included in such a header with
a set of equivalent textual imports.
This change removes the -emit-cxx-header option, and adds a new -emit-clang-header-path option instead. It's aliased to -emit-objc-header-path for now, but in the future, -emit-objc-header-path will alias to it. After this change Swift can start emitting a single header file that can be expose declarations to C, Objective-C, or C++. For now C++ interface is generated (for all public decls) only when -enable-cxx-interop flag is passed, but that behavior will change once attribute is supported.
When @compatibility_alias is used with an ObjC generic class, this ends up importing as a generic typealias. PrintAsObjC previously didn’t handle declarations involving these types correctly; it would fail an assertion in asserts compilers, and potentially print an incorrect compatibility header in non-asserts compilers.
This PR makes it so that PrintAsObjC can now correctly use generic typealiases imported from Objective-C modules. It is, of course, still not possible to declare a generic typealias in Swift that will be printed into the Objective-C header.
Fixes rdar://67256866.
The assertion here is too strict. The TypeAliasDecl will inherit a
generic signature from the outer context even if it does not have
generic parameters of its own. Instead, let's just assert that the
TypeAliasDecl does not have its own generic parameters.
Fixes <rdar://problem/63188938>.
Compatibility header may #import bridging header if specified with -import-underlying-module.
How these two headers are relative to each other is subject to project setting. To accommodate
this, we should allow users to specify bridging header directory for header generating purposes.
rdar://59110975
When an @_implementationOnly import includes Objective-C categories
for existing types, it's useful to be able to override the members
provided in those categories without exposing them to clients of the
framework being built. Allow this as long as the overriding
declaration is marked as @_implementationOnly itself, with an
additional check that the type of the declaration does not change.
(Normally overrides are allowed to change in covariant ways.)
Part of rdar://50827914
Without -enable-resilient-objc-class-stubs, don't print classes with
resilient ancestry at all, since they're not actually visible to
Clang and referencing one will not actually work.
When the flag is specified, such classes do appear in the generated
header with the new objc_class_stub Clang attribute.
This ensures that 'Foo' always gets imported before 'Foo_Private'.
This shouldn't strictly be necessary but does end up with more
reliable results in practice.
rdar://problem/36159006
This allows them to be used in generic arguments for NSArray et al.
We already do this for the ones that wrap bridged values (like
NSString/String), but failed to do it for objects that /weren't/
bridged to Swift values (class instances and protocol compositions),
or for Error-which-is-special.
In addition to this being a sensible thing to do, /not/ doing this led
to IRGen getting very confused (i.e. crashing) when we imported a
Objective-C protocol that actually used an NS_TYPED_ENUM in this way.
(We actually shouldn't be using Swift's IRGen logic to emit protocol
descriptors for imported protocols at all, because it's possible we
weren't able to import all the requirements. But that's a separate
issue.)
https://bugs.swift.org/browse/SR-6844
The general policy has been that even if something crashes at run
time, we don't make it a hard error in Swift 4 mode (or Swift 3 mode!)
if it wasn't a hard error in Swift 4.0 (3.0). In this case, we thought
we could get away with it, and then it turns out it actually caused
some problems. (And as 2bc010681 shows, we can still make mistakes.)
This change isn't perfect because the diagnostic appears in /clients/
rather than in the module that's being compiled as Swift 4 (instead of
Swift 5). But it still means that someone who hasn't changed
/anything/ from a valid Swift 4.0 project will be able to compile
without any changes, even if they were relying on being able to call
+new when -init was unavailable for some reason.
More rdar://problem/35942058
SourceKit uses a clever pragma to automatically attach an attribute to
every declaration in the file. However, the form of this pragma (clang
attribute push) uses a parenthesized list marked with 'any', which turns
out to be a name that people sometimes use for macros. Guard against this
using the push_macro pragma (originally from MSVC), under the assumption
that anyone who supports the highly-use-specific 'external_source_symbol'
attribute probably implements this more common extension. This does make
the generated header a little uglier, but it's not like it was really
pretty to begin with.
rdar://problem/34168022
Since Swift 3 and Swift 4 might have different views of an Objective-C
API's nullability, we can end up with incompatible overrides,
including with inherited initializers. This is unfortunate but also
realistic; the Swift 3 code is /not/ set up to handle the new nullability
used by Swift 4 and Objective-C. Just silence the warning.
(It would be nice to not print inherited initializers at all, but that
would mean making sure there are no convenience initializers we have
to print as well. Otherwise the class would get mistaken for one
without explicit designated initializers.)
rdar://problem/32571301
These are TypeAliasDecls whose Clang nodes are not TypedefNameDecls.
This worked all right for classes, but dropped the tag keyword
(e.g. 'struct') for tag decls with names of their own, and didn't
print any name at all for C types that used the
typedef-for-anonymous-tag pattern.
rdar://problem/32514335
For historic reasons, Clang's representation of an Objective-C class
declaration ObjCInterfaceDecl) and compatibility alias
(ObjCCompatibleAliasDecl) are not actually Clang TypeDecl nodes. Cope
with this in Objective-C printing, fixing rdar://problem/32308192.
I'm not sure why this didn't occur to me in 8282160d: of course if you
see a generic type with arguments, you need to see the @interface for
that type in order to supply the arguments. Maybe I was thinking the
generated interface would automatically import anything the module
itself imports, but that hasn't ever been true.
rdar://problem/28738008
More specifically, don't try to emit a definition for them. Just fall
through to what we do for forward-declarations...which also needed some
fixing, to make sure we don't use a Swift typealias as its underlying
type but never import the underlying type.
https://bugs.swift.org/browse/SR-2352
Like Swift generics, Objective-C generics may have constraints; unlike
Swift generics, Objective-C doesn't do separate parsing and
type-checking passes. This means that any generic arguments for
constrained generic parameters must be fully-defined, in order to
check that they satisfy the constraints.
This commit addresses this problem with three different mechanisms,
one for each kind of declaration that might run into this issue:
- For classes, if a member references a type with constrained generic
parameter, and the corresponding argument type hasn't been printed
yet, that member is "delayed", which means it is put into a category
at the end of the file.
- Protocols cannot have categories, so for protocols we instead see if
we can print the definition of the other type first. To break
circular dependencies, the printer will not attempt this if both the
type and the protocol are already being depended on. This isn't
perfect (see below).
- Rather than delaying members of extensions, we just delay them
wholesale. This keeps related members together, but also has
problems (see below).
These approaches solve the most common cases while still not crashing
in the uncommon ones. However, there are still a number of problems:
- The protocol heuristic is overly negative, which means we may generate
an invalid header even when there's a reasonable ordering. For example,
a single class might inherit from a class A and conform to protocol P,
and protocol P depends on class A as a generic argument. In this case,
defining class A first is the right thing to do, but it's possible for
the printer to decide that there's circularity here and just forward-
declare A instead.
- Protocols really can be circular. This can be fixed by printing a
forward-declared protocol alongside the generic constraints, i.e.
'id <MoreThanNSCopying, NSCopying>' instead of just
'id <MoreThanNSCopying>'.
- Extensions can introduce protocols as well. This is not modeled at
all; if a member depends on a protocol conformance, it's assumed
that simply printing the class would be sufficient. This could be
fixed by checking how a generic argument satisfies its constraints,
possibly delaying individual members from extensions in order to
print them sooner.
- More cases I haven't thought about.
Test cases for some of these problems are in the new
circularity-errors.swift file, mostly to make sure the ObjC printer
doesn't crash when it encounters them.
rdar://problem/27109377
...because otherwise option sets that get imported as members using
NS_SWIFT_NAME are printed with an 'enum' tag, and the definition of
NS_OPTIONS only declares the typedef under C++.
We should come back and figure out something more principled for this
later, but for now this solves an issue with generated headers
imported into C++ translation units.
rdar://problem/27130343