Skip to content

Commit c09a095

Browse files
authored
Merge pull request #10651 from DougGregor/module-print-ns-error-enum-4.0jun23
[4.0jun23][Clang importer/module printing] Correctly print NS_ERROR_ENUMs.
2 parents 753dcc2 + 3f406f2 commit c09a095

File tree

5 files changed

+82
-23
lines changed

5 files changed

+82
-23
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2272,7 +2272,14 @@ void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl<Decl*> &results) const {
22722272
owner.importDecl(decl, owner.CurrentVersion);
22732273
if (!importedDecl) continue;
22742274

2275-
auto ext = dyn_cast<ExtensionDecl>(importedDecl->getDeclContext());
2275+
// Find the enclosing extension, if there is one.
2276+
ExtensionDecl *ext = nullptr;
2277+
for (auto importedDC = importedDecl->getDeclContext();
2278+
!importedDC->isModuleContext();
2279+
importedDC = importedDC->getParent()) {
2280+
ext = dyn_cast<ExtensionDecl>(importedDC);
2281+
if (ext) break;
2282+
}
22762283
if (!ext) continue;
22772284

22782285
if (knownExtensions.insert(ext).second)

lib/ClangImporter/ImportDecl.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7921,8 +7921,18 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
79217921

79227922
// Then try to import the decl under the specified name.
79237923
auto *member = importDecl(decl, nameVersion);
7924-
if (!member || member->getDeclContext() != ext)
7925-
return;
7924+
if (!member) return;
7925+
7926+
// Find the member that will land in an extension context.
7927+
while (!isa<ExtensionDecl>(member->getDeclContext())) {
7928+
auto nominal = dyn_cast<NominalTypeDecl>(member->getDeclContext());
7929+
if (!nominal) return;
7930+
7931+
member = nominal;
7932+
if (member->hasClangNode()) return;
7933+
}
7934+
7935+
if (member->getDeclContext() != ext) return;
79267936
ext->addMember(member);
79277937

79287938
for (auto alternate : getAlternateDecls(member)) {

lib/IDE/ModuleInterfacePrinting.cpp

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -220,28 +220,49 @@ swift::ide::collectModuleGroups(ModuleDecl *M, std::vector<StringRef> &Scratch)
220220
return llvm::makeArrayRef(Scratch);
221221
}
222222

223-
/// Determine whether the given extension has a Clang node that
224-
/// created it (vs. being a Swift extension).
225-
static bool extensionHasClangNode(ExtensionDecl *ext) {
226-
// If it has a Clang node (directly),
227-
if (ext->hasClangNode()) return true;
223+
/// Retrieve the effective Clang node for the given declaration, which
224+
/// copes with the odd case of imported Error enums.
225+
static ClangNode getEffectiveClangNode(const Decl *decl) {
226+
// Directly...
227+
if (auto clangNode = decl->getClangNode())
228+
return clangNode;
229+
230+
// Or via the nested "Code" enum.
231+
if (auto nominal =
232+
const_cast<NominalTypeDecl *>(dyn_cast<NominalTypeDecl>(decl))) {
233+
auto &ctx = nominal->getASTContext();
234+
for (auto code : nominal->lookupDirect(ctx.Id_Code,
235+
/*ignoreNewExtensions=*/true)) {
236+
if (auto clangDecl = code->getClangDecl())
237+
return clangDecl;
238+
}
239+
}
228240

229-
// If it has a global imported as a member.
230-
auto members = ext->getMembers();
231-
if (members.empty()) return false;
232-
return members.front()->hasClangNode();
241+
return ClangNode();
233242
}
234243

235244
/// Retrieve the Clang node for the given extension, if it has one.
236-
/// created it (vs. being a Swift extension).
237245
static ClangNode extensionGetClangNode(ExtensionDecl *ext) {
238246
// If it has a Clang node (directly),
239247
if (ext->hasClangNode()) return ext->getClangNode();
240248

241-
// If it has a global imported as a member.
242-
auto members = ext->getMembers();
243-
if (members.empty()) return ClangNode();
244-
return members.front()->getClangNode();
249+
// Check whether it was syntheszed into a module-scope context.
250+
if (!isa<ClangModuleUnit>(ext->getModuleScopeContext()))
251+
return ClangNode();
252+
253+
// It may have a global imported as a member.
254+
for (auto member : ext->getMembers()) {
255+
if (auto clangNode = getEffectiveClangNode(member))
256+
return clangNode;
257+
}
258+
259+
return ClangNode();
260+
}
261+
262+
/// Determine whether the given extension has a Clang node that
263+
/// created it (vs. being a Swift extension).
264+
static bool extensionHasClangNode(ExtensionDecl *ext) {
265+
return static_cast<bool>(extensionGetClangNode(ext));
245266
}
246267

247268
Optional<StringRef>
@@ -393,8 +414,8 @@ void swift::ide::printSubmoduleInterface(
393414
}
394415
};
395416

396-
if (D->hasClangNode()) {
397-
addToClangDecls(D, D->getClangNode());
417+
if (auto clangNode = getEffectiveClangNode(D)) {
418+
addToClangDecls(D, clangNode);
398419
continue;
399420
}
400421

@@ -739,8 +760,8 @@ void swift::ide::printHeaderInterface(
739760
std::sort(ClangDecls.begin(), ClangDecls.end(),
740761
[&](Decl *LHS, Decl *RHS) -> bool {
741762
return ClangSM.isBeforeInTranslationUnit(
742-
LHS->getClangNode().getLocation(),
743-
RHS->getClangNode().getLocation());
763+
getEffectiveClangNode(LHS).getLocation(),
764+
getEffectiveClangNode(RHS).getLocation());
744765
});
745766

746767
ASTPrinter *PrinterToUse = &Printer;
@@ -789,7 +810,7 @@ void ClangCommentPrinter::printDeclPre(const Decl *D,
789810
// single line.
790811
// FIXME: we should fix that, since it also affects struct members, etc.
791812
if (!isa<ParamDecl>(D)) {
792-
if (auto ClangN = D->getClangNode()) {
813+
if (auto ClangN = getEffectiveClangNode(D)) {
793814
printCommentsUntil(ClangN);
794815
if (shouldPrintNewLineBefore(ClangN)) {
795816
*this << "\n";
@@ -813,7 +834,7 @@ void ClangCommentPrinter::printDeclPost(const Decl *D,
813834
*this << " " << ASTPrinter::sanitizeUtf8(CommentText);
814835
}
815836
PendingComments.clear();
816-
if (auto ClangN = D->getClangNode())
837+
if (auto ClangN = getEffectiveClangNode(D))
817838
updateLastEntityLine(ClangN.getSourceRange().getEnd());
818839
}
819840

test/IDE/print_clang_decls.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@
123123
// FOUNDATION-NEXT: @available(*, unavailable, message: "Zone-based memory management is unavailable")
124124
// FOUNDATION-NEXT: NSSetZoneName(_ zone: NSZone, _ name: String)
125125

126+
// FOUNDATION-LABEL: struct FictionalServerError
127+
// FOUNDATION: enum Code
128+
// FOUNDATION: case meltedDown
129+
// FOUNDATION: static var meltedDown: FictionalServerError.Code
130+
131+
// FOUNDATION-LABEL: extension NSLaundromat {
132+
// FOUNDATION-NEXT: struct Error
133+
// FOUNDATION: enum Code
134+
// FOUNDATION: case tooMuchSoap
135+
// FOUNDATION: static var tooMuchSoap: NSLaundromat.Error.Code { get }
136+
126137
// CTYPESBITS-NOT: FooStruct1
127138
// CTYPESBITS: {{^}}typealias DWORD = Int32{{$}}
128139
// CTYPESBITS-NEXT: {{^}}var MY_INT: Int32 { get }{{$}}

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,3 +1100,13 @@ typedef enum __attribute__((ns_error_domain(FictionalServerErrorDomain))) Fictio
11001100
- (void)bleach:(Coat <Garment, Cotton> * _Nonnull)garment;
11011101
- (Coat <Garment> * _Nonnull)dry;
11021102
@end
1103+
1104+
@interface NSLaundromat : NSObject
1105+
@end
1106+
1107+
extern NSString * const NSLaundryErrorDomain;
1108+
1109+
typedef enum __attribute__((ns_error_domain(NSLaundryErrorDomain))) __attribute__((swift_name("NSLaundromat.Error"))) NSLaundryErrorCode {
1110+
NSLaundryErrorTooMuchSoap = 1,
1111+
NSLaundryErrorCatInWasher = 2
1112+
};

0 commit comments

Comments
 (0)