From 4912f54bea8b9bef2d07edd3ae2e7cdb47d92ee6 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Thu, 21 May 2020 21:12:17 -0700 Subject: [PATCH] [IDE][InterfaceGen] Always print the top-level decl in header file generated interface. While the decls being printed for header file generated interfaces were mapped from the top-level clang decls in that file, the Swift decls they correspond to may not be top-level. E.g. top-level functions in the header file can be mapped to property accessors on the Swift side, which were being printed simply as "get" at the top level. This updates header interface generation to map each decl to its top-level decl before printing. Resolves rdar://problem/63409659 --- lib/IDE/ModuleInterfacePrinting.cpp | 18 +- test/SourceKit/InterfaceGen/Inputs/header3.h | 10 + test/SourceKit/InterfaceGen/gen_header.swift | 4 + .../gen_header.swift.header3.response | 328 ++++++++++++++++++ 4 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 test/SourceKit/InterfaceGen/Inputs/header3.h create mode 100644 test/SourceKit/InterfaceGen/gen_header.swift.header3.response diff --git a/lib/IDE/ModuleInterfacePrinting.cpp b/lib/IDE/ModuleInterfacePrinting.cpp index 2315576134277..8bccb61ed88cd 100644 --- a/lib/IDE/ModuleInterfacePrinting.cpp +++ b/lib/IDE/ModuleInterfacePrinting.cpp @@ -840,6 +840,16 @@ void swift::ide::printSwiftSourceInterface(SourceFile &File, File.print(Printer, Options); } +static Decl* getTopLevelDecl(Decl *D) { + while (!D->getDeclContext()->isModuleScopeContext()) { + auto *ParentD = D->getDeclContext()->getAsDecl(); + if (!ParentD) + break; + D = ParentD; + } + return D; +} + void swift::ide::printHeaderInterface( StringRef Filename, ASTContext &Ctx, @@ -858,10 +868,8 @@ void swift::ide::printHeaderInterface( SmallVector ClangDecls; llvm::SmallPtrSet SeenDecls; auto headerReceiver = [&](Decl *D) { - if (SeenDecls.count(D) == 0) { - SeenDecls.insert(D); + if (SeenDecls.insert(getTopLevelDecl(D)).second) ClangDecls.push_back(D); - } }; Importer.lookupDeclsFromHeader(Filename, headerFilter, headerReceiver); @@ -881,6 +889,10 @@ void swift::ide::printHeaderInterface( PrinterToUse = &RegularCommentPrinter; for (auto *D : ClangDecls) { + // Even though the corresponding clang decl should be top-level, its + // equivalent Swift decl may not be. E.g. a top-level function may be mapped + // to a property accessor in Swift. + D = getTopLevelDecl(D); ASTPrinter &Printer = *PrinterToUse; if (!AdjustedOptions.shouldPrint(D)) { Printer.callAvoidPrintDeclPost(D); diff --git a/test/SourceKit/InterfaceGen/Inputs/header3.h b/test/SourceKit/InterfaceGen/Inputs/header3.h new file mode 100644 index 0000000000000..8008adf5dcc2f --- /dev/null +++ b/test/SourceKit/InterfaceGen/Inputs/header3.h @@ -0,0 +1,10 @@ +#define CF_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#define CF_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type +#define NS_ENUM(_type, _name) CF_ENUM(_type, _name) +#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name) +#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name))) +#define NS_SWIFT_NAME(_name) CF_SWIFT_NAME(_name) + +typedef NS_ENUM(unsigned, SKFuelKind) { SKFuelKindH2, SKFuelKindCH4, SKFuelKindC12H26 }; +unsigned SKFuelKindIsCryogenic(SKFuelKind kind) NS_SWIFT_NAME(getter:SKFuelKind.isCryogenic(self:)); +unsigned SKFuelKindIsNotCryogenic(SKFuelKind kind) NS_SWIFT_NAME(getter:SKFuelKind.isNotCryogenic(self:)); diff --git a/test/SourceKit/InterfaceGen/gen_header.swift b/test/SourceKit/InterfaceGen/gen_header.swift index 1d25285167656..e6a675b051d74 100644 --- a/test/SourceKit/InterfaceGen/gen_header.swift +++ b/test/SourceKit/InterfaceGen/gen_header.swift @@ -21,3 +21,7 @@ // RUN: %sourcekitd-test -req=interface-gen -header %S/Inputs/header2.h -swift-version=5 -pass-version-as-string -- -fsyntax-only %t.m -I %S/Inputs > %t.header2.swift4.response // RUN: %FileCheck -input-file %t.header2.swift4.response %s -check-prefix=SWIFT4-STR // SWIFT4-STR: public func show_only_for_swift_4() + +// RUN: echo '#include "header3.h"' > %t.m +// RUN: %sourcekitd-test -req=interface-gen -header %S/Inputs/header3.h -swift-version=5 -- -fsyntax-only %t.m -I %S/Inputs > %t.header3.response +// RUN: %diff -u %s.header3.response %t.header3.response diff --git a/test/SourceKit/InterfaceGen/gen_header.swift.header3.response b/test/SourceKit/InterfaceGen/gen_header.swift.header3.response new file mode 100644 index 0000000000000..15b680fa6d966 --- /dev/null +++ b/test/SourceKit/InterfaceGen/gen_header.swift.header3.response @@ -0,0 +1,328 @@ + +public enum SKFuelKind : UInt32 { + + + case H2 = 0 + + case CH4 = 1 + + case C12H26 = 2 +} +extension SKFuelKind { + + public var isCryogenic: UInt32 { get } + + public var isNotCryogenic: UInt32 { get } +} + +[ + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 1, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 8, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 13, + key.length: 10 + }, + { + key.kind: source.lang.swift.syntaxtype.typeidentifier, + key.offset: 26, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 45, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 50, + key.length: 2 + }, + { + key.kind: source.lang.swift.syntaxtype.number, + key.offset: 55, + key.length: 1 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 62, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 67, + key.length: 3 + }, + { + key.kind: source.lang.swift.syntaxtype.number, + key.offset: 73, + key.length: 1 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 80, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 85, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.number, + key.offset: 94, + key.length: 1 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 98, + key.length: 9 + }, + { + key.kind: source.lang.swift.syntaxtype.typeidentifier, + key.offset: 108, + key.length: 10 + }, + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 126, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 133, + key.length: 3 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 137, + key.length: 11 + }, + { + key.kind: source.lang.swift.syntaxtype.typeidentifier, + key.offset: 150, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 159, + key.length: 3 + }, + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 170, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 177, + key.length: 3 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 181, + key.length: 14 + }, + { + key.kind: source.lang.swift.syntaxtype.typeidentifier, + key.offset: 197, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 206, + key.length: 3 + } +] +[ + { + key.kind: source.lang.swift.ref.struct, + key.offset: 26, + key.length: 6, + key.is_system: 1 + }, + { + key.kind: source.lang.swift.ref.enum, + key.offset: 108, + key.length: 10 + }, + { + key.kind: source.lang.swift.ref.struct, + key.offset: 150, + key.length: 6, + key.is_system: 1 + }, + { + key.kind: source.lang.swift.ref.struct, + key.offset: 197, + key.length: 6, + key.is_system: 1 + } +] +[ + { + key.kind: source.lang.swift.decl.enum, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "SKFuelKind", + key.offset: 8, + key.length: 89, + key.nameoffset: 13, + key.namelength: 10, + key.bodyoffset: 34, + key.bodylength: 62, + key.inheritedtypes: [ + { + key.name: "UInt32" + } + ], + key.attributes: [ + { + key.offset: 1, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.elements: [ + { + key.kind: source.lang.swift.structure.elem.typeref, + key.offset: 26, + key.length: 6 + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.decl.enumcase, + key.offset: 45, + key.length: 11, + key.nameoffset: 0, + key.namelength: 0, + key.substructure: [ + { + key.kind: source.lang.swift.decl.enumelement, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "H2", + key.offset: 50, + key.length: 6, + key.nameoffset: 50, + key.namelength: 2, + key.elements: [ + { + key.kind: source.lang.swift.structure.elem.init_expr, + key.offset: 55, + key.length: 1 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.enumcase, + key.offset: 62, + key.length: 12, + key.nameoffset: 0, + key.namelength: 0, + key.substructure: [ + { + key.kind: source.lang.swift.decl.enumelement, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "CH4", + key.offset: 67, + key.length: 7, + key.nameoffset: 67, + key.namelength: 3, + key.elements: [ + { + key.kind: source.lang.swift.structure.elem.init_expr, + key.offset: 73, + key.length: 1 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.enumcase, + key.offset: 80, + key.length: 15, + key.nameoffset: 0, + key.namelength: 0, + key.substructure: [ + { + key.kind: source.lang.swift.decl.enumelement, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "C12H26", + key.offset: 85, + key.length: 10, + key.nameoffset: 85, + key.namelength: 6, + key.elements: [ + { + key.kind: source.lang.swift.structure.elem.init_expr, + key.offset: 94, + key.length: 1 + } + ] + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "SKFuelKind", + key.offset: 98, + key.length: 115, + key.nameoffset: 108, + key.namelength: 10, + key.bodyoffset: 120, + key.bodylength: 92, + key.substructure: [ + { + key.kind: source.lang.swift.decl.var.instance, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "isCryogenic", + key.offset: 133, + key.length: 31, + key.typename: "UInt32", + key.nameoffset: 137, + key.namelength: 11, + key.bodyoffset: 158, + key.bodylength: 5, + key.attributes: [ + { + key.offset: 126, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ] + }, + { + key.kind: source.lang.swift.decl.var.instance, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "isNotCryogenic", + key.offset: 177, + key.length: 34, + key.typename: "UInt32", + key.nameoffset: 181, + key.namelength: 14, + key.bodyoffset: 205, + key.bodylength: 5, + key.attributes: [ + { + key.offset: 170, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ] + } + ] + } +]