|
31 | 31 | #include "clang/AST/DeclObjC.h"
|
32 | 32 | #include "clang/Basic/CharInfo.h"
|
33 | 33 | #include "clang/Basic/Module.h"
|
| 34 | +#include "clang/Lex/Lexer.h" |
34 | 35 | #include "llvm/ADT/SetVector.h"
|
35 | 36 | #include "llvm/ADT/StringSwitch.h"
|
36 | 37 | #include "llvm/ADT/STLExtras.h"
|
@@ -125,6 +126,38 @@ static bool looksLikeInitMethod(ObjCSelector selector) {
|
125 | 126 | return !(firstPiece.size() > 4 && clang::isLowercase(firstPiece[4]));
|
126 | 127 | }
|
127 | 128 |
|
| 129 | +/// Returns the name of an <os/object.h> type minus the leading "OS_", |
| 130 | +/// or an empty string if \p decl is not an <os/object.h> type. |
| 131 | +static StringRef maybeGetOSObjectBaseName(const clang::NamedDecl *decl) { |
| 132 | + StringRef name = decl->getName(); |
| 133 | + if (!name.consume_front("OS_")) |
| 134 | + return StringRef(); |
| 135 | + |
| 136 | + clang::SourceLocation loc = decl->getLocation(); |
| 137 | + if (!loc.isMacroID()) |
| 138 | + return StringRef(); |
| 139 | + |
| 140 | + // Hack: check to see if the name came from a macro in <os/object.h>. |
| 141 | + clang::SourceManager &sourceMgr = decl->getASTContext().getSourceManager(); |
| 142 | + clang::SourceLocation expansionLoc = |
| 143 | + sourceMgr.getImmediateExpansionRange(loc).first; |
| 144 | + clang::SourceLocation spellingLoc = sourceMgr.getSpellingLoc(expansionLoc); |
| 145 | + |
| 146 | + if (!sourceMgr.getFilename(spellingLoc).endswith("/os/object.h")) |
| 147 | + return StringRef(); |
| 148 | + |
| 149 | + return name; |
| 150 | +} |
| 151 | + |
| 152 | +/// Returns true if \p decl represents an <os/object.h> type. |
| 153 | +static bool isOSObjectType(const clang::Decl *decl) { |
| 154 | + auto *named = dyn_cast_or_null<clang::NamedDecl>(decl); |
| 155 | + if (!named) |
| 156 | + return false; |
| 157 | + return !maybeGetOSObjectBaseName(named).empty(); |
| 158 | +} |
| 159 | + |
| 160 | + |
128 | 161 | namespace {
|
129 | 162 | using DelayedMemberSet = llvm::SmallSetVector<const ValueDecl *, 32>;
|
130 | 163 |
|
@@ -1320,18 +1353,21 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
|
1320 | 1353 | assert(CD->isObjC());
|
1321 | 1354 | auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(CD->getClangDecl());
|
1322 | 1355 | if (clangDecl) {
|
1323 |
| - if (isa<clang::ObjCInterfaceDecl>(clangDecl)) { |
| 1356 | + // Hack for <os/object.h> types, which use classes in Swift but |
| 1357 | + // protocols in Objective-C, and a typedef to hide the difference. |
| 1358 | + StringRef osObjectName = maybeGetOSObjectBaseName(clangDecl); |
| 1359 | + if (!osObjectName.empty()) { |
| 1360 | + os << osObjectName << "_t"; |
| 1361 | + } else if (isa<clang::ObjCInterfaceDecl>(clangDecl)) { |
1324 | 1362 | os << clangDecl->getName() << " *";
|
1325 |
| - printNullability(optionalKind); |
1326 | 1363 | } else {
|
1327 | 1364 | maybePrintTagKeyword(CD);
|
1328 | 1365 | os << clangDecl->getName();
|
1329 |
| - printNullability(optionalKind); |
1330 | 1366 | }
|
1331 | 1367 | } else {
|
1332 | 1368 | os << getNameForObjC(CD) << " *";
|
1333 |
| - printNullability(optionalKind); |
1334 | 1369 | }
|
| 1370 | + printNullability(optionalKind); |
1335 | 1371 | }
|
1336 | 1372 |
|
1337 | 1373 | void visitProtocolType(ProtocolType *PT,
|
@@ -1799,7 +1835,8 @@ class ModuleWriter {
|
1799 | 1835 |
|
1800 | 1836 | bool forwardDeclare(const ClassDecl *CD) {
|
1801 | 1837 | if (!CD->isObjC() ||
|
1802 |
| - CD->getForeignClassKind() == ClassDecl::ForeignKind::CFType) { |
| 1838 | + CD->getForeignClassKind() == ClassDecl::ForeignKind::CFType || |
| 1839 | + isOSObjectType(CD->getClangDecl())) { |
1803 | 1840 | return false;
|
1804 | 1841 | }
|
1805 | 1842 | forwardDeclare(CD, [&]{ os << "@class " << getNameForObjC(CD) << ";\n"; });
|
|
0 commit comments