Skip to content

Commit e91580b

Browse files
committed
TBDGen: Teach APIGenRecorder to emit API descriptors during -emit-module.
Make the changes to APIGenRecorder that are necessary to make it capable of emitting API descriptors during -emit-module jobs. The output in this mode differs from the output when run on an existing module in a couple of important ways: - The value for the `file` key in the descriptor JSON is now the path to the source file that defines the declaration responsible for the symbol. In `swift-api-extract` mode, the value for this key is the path to the module or swiftinterface which is unavailable during an -emit-module job since the module is usually not being emitted to its final installed location. - Some additional symbols may be included in the API descriptor JSON because more of the AST is available when emitting the module. Resolves rdar://110916764
1 parent e1f2e25 commit e91580b

File tree

8 files changed

+283
-139
lines changed

8 files changed

+283
-139
lines changed

include/swift/AST/DiagnosticsFrontend.def

+4
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ ERROR(tbd_not_supported_with_cmo,none,
315315
"Test-Based InstallAPI (TBD) is not support with cross-module-optimization",
316316
())
317317

318+
WARNING(api_descriptor_only_supported_in_whole_module,none,
319+
"API descriptor generation is only supported when the whole module can be seen",
320+
())
321+
318322
ERROR(previous_installname_map_missing,none,
319323
"cannot open previous install name map from %0",
320324
(StringRef))

lib/IRGen/TBDGen.cpp

+37-15
Original file line numberDiff line numberDiff line change
@@ -664,8 +664,13 @@ class APIGenRecorder final : public APIRecorder {
664664
public:
665665
APIGenRecorder(apigen::API &api, ModuleDecl *module)
666666
: api(api), module(module) {
667-
const auto &MainFile = module->getMainFile(FileUnitKind::SerializedAST);
668-
moduleLoc = apigen::APILoc(MainFile.getModuleDefiningPath().str(), 0, 0);
667+
// If we're working with a serialized module, make the default location
668+
// for symbols the path to the binary module.
669+
if (FileUnit *MainFile = module->getFiles().front()) {
670+
if (MainFile->getKind() == FileUnitKind::SerializedAST)
671+
defaultLoc =
672+
apigen::APILoc(MainFile->getModuleDefiningPath().str(), 0, 0);
673+
}
669674
}
670675
~APIGenRecorder() {}
671676

@@ -682,7 +687,7 @@ class APIGenRecorder final : public APIRecorder {
682687
access = apigen::APIAccess::Private;
683688
}
684689

685-
api.addSymbol(symbol, moduleLoc, apigen::APILinkage::Exported,
690+
api.addSymbol(symbol, getAPILocForDecl(decl), apigen::APILinkage::Exported,
686691
apigen::APIFlags::None, access, availability);
687692
}
688693

@@ -700,12 +705,12 @@ class APIGenRecorder final : public APIRecorder {
700705
apigen::APIAvailability availability;
701706
bool isInstanceMethod = true;
702707
auto access = apigen::APIAccess::Public;
703-
if (method.hasDecl()) {
704-
availability = getAvailability(method.getDecl());
705-
if (method.getDecl()->getDescriptiveKind() ==
706-
DescriptiveDeclKind::ClassMethod)
708+
auto decl = method.hasDecl() ? method.getDecl() : nullptr;
709+
if (decl) {
710+
availability = getAvailability(decl);
711+
if (decl->getDescriptiveKind() == DescriptiveDeclKind::ClassMethod)
707712
isInstanceMethod = false;
708-
if (isSPI(method.getDecl()))
713+
if (isSPI(decl))
709714
access = apigen::APIAccess::Private;
710715
}
711716

@@ -716,11 +721,27 @@ class APIGenRecorder final : public APIRecorder {
716721
record = addOrGetObjCCategory(ext);
717722

718723
if (record)
719-
api.addObjCMethod(record, name, moduleLoc, access, isInstanceMethod,
720-
false, availability);
724+
api.addObjCMethod(record, name, getAPILocForDecl(decl), access,
725+
isInstanceMethod, false, availability);
721726
}
722727

723728
private:
729+
apigen::APILoc getAPILocForDecl(const Decl *decl) {
730+
if (!decl)
731+
return defaultLoc;
732+
733+
SourceLoc loc = decl->getLoc();
734+
if (!loc.isValid())
735+
return defaultLoc;
736+
737+
auto &SM = decl->getASTContext().SourceMgr;
738+
unsigned line, col;
739+
std::tie(line, col) = SM.getPresumedLineAndColumnForLoc(loc);
740+
auto displayName = SM.getDisplayNameForLoc(loc);
741+
742+
return apigen::APILoc(std::string(displayName), line, col);
743+
}
744+
724745
/// Follow the naming schema that IRGen uses for Categories (see
725746
/// ClassDataBuilder).
726747
using CategoryNameKey = std::pair<const ClassDecl *, const ModuleDecl *>;
@@ -776,8 +797,8 @@ class APIGenRecorder final : public APIRecorder {
776797
decl->getFormalAccess() == AccessLevel::Public && decl->isObjC()
777798
? apigen::APILinkage::Exported
778799
: apigen::APILinkage::Internal;
779-
auto cls = api.addObjCClass(name, linkage, moduleLoc, access, availability,
780-
superCls);
800+
auto cls = api.addObjCClass(name, linkage, getAPILocForDecl(decl), access,
801+
availability, superCls);
781802
classMap.try_emplace(decl, cls);
782803
return cls;
783804
}
@@ -809,15 +830,16 @@ class APIGenRecorder final : public APIRecorder {
809830
decl->getMaxAccessLevel() == AccessLevel::Public
810831
? apigen::APILinkage::Exported
811832
: apigen::APILinkage::Internal;
812-
auto category = api.addObjCCategory(nameBuffer, linkage, moduleLoc, access,
813-
availability, interface);
833+
auto category =
834+
api.addObjCCategory(nameBuffer, linkage, getAPILocForDecl(decl), access,
835+
availability, interface);
814836
categoryMap.try_emplace(decl, category);
815837
return category;
816838
}
817839

818840
apigen::API &api;
819841
ModuleDecl *module;
820-
apigen::APILoc moduleLoc;
842+
apigen::APILoc defaultLoc;
821843

822844
llvm::DenseMap<const ClassDecl*, apigen::ObjCInterfaceRecord*> classMap;
823845
llvm::DenseMap<const ExtensionDecl *, apigen::ObjCCategoryRecord *>

0 commit comments

Comments
 (0)