Skip to content

Commit 65d819e

Browse files
authored
[ClangImporter] Use TextAPI apis for capturing current-version (#67204)
Use LLVM apis for understanding TBD files instead of parsing the yaml directly. This prevents breaking the compiler when TBD-v5 exists which is in json.
1 parent dc92742 commit 65d819e

File tree

6 files changed

+39
-50
lines changed

6 files changed

+39
-50
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@
7777
#include "llvm/Support/Path.h"
7878
#include "llvm/Support/VirtualFileSystem.h"
7979
#include "llvm/Support/VirtualOutputBackend.h"
80-
#include "llvm/Support/YAMLParser.h"
80+
#include "llvm/TextAPI/InterfaceFile.h"
81+
#include "llvm/TextAPI/TextAPIReader.h"
8182
#include <algorithm>
8283
#include <memory>
8384
#include <string>
@@ -1934,9 +1935,29 @@ bool ClangImporter::isModuleImported(const clang::Module *M) {
19341935
return M->NameVisibility == clang::Module::NameVisibilityKind::AllVisible;
19351936
}
19361937

1937-
static std::string getScalaNodeText(llvm::yaml::Node *N) {
1938-
SmallString<32> Buffer;
1939-
return cast<llvm::yaml::ScalarNode>(N)->getValue(Buffer).str();
1938+
static llvm::VersionTuple getCurrentVersionFromTBD(StringRef path,
1939+
StringRef moduleName) {
1940+
std::string fwName = (moduleName + ".framework").str();
1941+
auto pos = path.find(fwName);
1942+
if (pos == StringRef::npos)
1943+
return {};
1944+
llvm::SmallString<256> buffer(path.substr(0, pos + fwName.size()));
1945+
llvm::sys::path::append(buffer, moduleName + ".tbd");
1946+
auto tbdPath = buffer.str();
1947+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> tbdBufOrErr =
1948+
llvm::MemoryBuffer::getFile(tbdPath);
1949+
// .tbd file doesn't exist, exit.
1950+
if (!tbdBufOrErr)
1951+
return {};
1952+
auto tbdFileOrErr =
1953+
llvm::MachO::TextAPIReader::get(tbdBufOrErr.get()->getMemBufferRef());
1954+
if (auto err = tbdFileOrErr.takeError()) {
1955+
consumeError(std::move(err));
1956+
return {};
1957+
}
1958+
auto tbdCV = (*tbdFileOrErr)->getCurrentVersion();
1959+
return llvm::VersionTuple(tbdCV.getMajor(), tbdCV.getMinor(),
1960+
tbdCV.getSubminor());
19401961
}
19411962

19421963
bool ClangImporter::canImportModule(ImportPath::Module modulePath,
@@ -1988,49 +2009,13 @@ bool ClangImporter::canImportModule(ImportPath::Module modulePath,
19882009
return true;
19892010

19902011
assert(available);
1991-
llvm::VersionTuple currentVersion;
19922012
StringRef path = getClangASTContext().getSourceManager()
19932013
.getFilename(clangModule->DefinitionLoc);
2014+
19942015
// Look for the .tbd file inside .framework dir to get the project version
19952016
// number.
1996-
std::string fwName = (llvm::Twine(topModule.Item.str()) + ".framework").str();
1997-
auto pos = path.find(fwName);
1998-
while (pos != StringRef::npos) {
1999-
llvm::SmallString<256> buffer(path.substr(0, pos + fwName.size()));
2000-
llvm::sys::path::append(buffer, llvm::Twine(topModule.Item.str()) + ".tbd");
2001-
auto tbdPath = buffer.str();
2002-
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> tbdBufOrErr =
2003-
llvm::MemoryBuffer::getFile(tbdPath);
2004-
// .tbd file doesn't exist, break.
2005-
if (!tbdBufOrErr) {
2006-
break;
2007-
}
2008-
StringRef tbdBuffer = tbdBufOrErr->get()->getBuffer();
2009-
2010-
// Use a new source manager instead of the one from ASTContext because we
2011-
// don't want the Json file to be persistent.
2012-
SourceManager SM;
2013-
llvm::yaml::Stream Stream(llvm::MemoryBufferRef(tbdBuffer, tbdPath),
2014-
SM.getLLVMSourceMgr());
2015-
auto DI = Stream.begin();
2016-
assert(DI != Stream.end() && "Failed to read a document");
2017-
llvm::yaml::Node *N = DI->getRoot();
2018-
assert(N && "Failed to find a root");
2019-
auto *pairs = dyn_cast_or_null<llvm::yaml::MappingNode>(N);
2020-
if (!pairs)
2021-
break;
2022-
for (auto &keyValue: *pairs) {
2023-
auto key = getScalaNodeText(keyValue.getKey());
2024-
// Look for field "current-version" in the .tbd file.
2025-
if (key == "current-version") {
2026-
auto ver = getScalaNodeText(keyValue.getValue());
2027-
currentVersion.tryParse(ver);
2028-
break;
2029-
}
2030-
}
2031-
break;
2032-
}
2033-
2017+
llvm::VersionTuple currentVersion =
2018+
getCurrentVersionFromTBD(path, topModule.Item.str());
20342019
versionInfo->setVersion(currentVersion,
20352020
ModuleVersionSourceKind::ClangModuleTBD);
20362021
return true;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
--- !tapi-tbd
2+
tbd-version: 4
3+
targets: [ arm64-macos, arm64-ios, arm64-watchos, arm64-tvos,
4+
arm64-ios-simulator, arm64-watchos-simulator, arm64-tvos-simulator ]
5+
flags: [ not_app_extension_safe ]
6+
install-name: '/System/Library/Frameworks/Simple.framework/Versions/A/Simple'
7+
current-version: 1830.100
8+
...

test/ClangImporter/can_import_underlying_version.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
// RUN: %empty-directory(%t/frameworks)
44

55
// RUN: cp -rf %S/Inputs/frameworks/Simple.framework %t/frameworks/
6-
7-
// RUN: echo "current-version: 1830.100" > %t/frameworks/Simple.framework/Simple.tbd
8-
96
// RUN: %target-typecheck-verify-swift -disable-implicit-concurrency-module-import -F %t/frameworks
107

118
import Simple

test/ClangImporter/can_import_underlying_version_ignores_swift_module_version.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// conditional, the version in the `.tbd` should be honored. When `_version`
1212
// is specified, the version from the `.swiftmodule` should be honored.
1313

14-
// RUN: echo "current-version: 3" > %t/frameworks/Simple.framework/Simple.tbd
14+
// RUN: sed -i -e "s/1830\.100/3/g" %t/frameworks/Simple.framework/Simple.tbd
1515
// RUN: echo "@_exported import Simple" > %t.overlay.swift
1616
// RUN: echo "public func additional() {}" >> %t.overlay.swift
1717

test/ClangImporter/can_import_underlying_version_tbd_missing_version.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
// RUN: %empty-directory(%t/frameworks)
44

55
// RUN: cp -rf %S/Inputs/frameworks/Simple.framework %t/frameworks/
6-
7-
// RUN: echo "" > %t/frameworks/Simple.framework/Simple.tbd
6+
// RUN: rm -rf %t/frameworks/Simple.framework/Simple.tbd
87
// RUN: %target-typecheck-verify-swift -disable-implicit-concurrency-module-import -F %t/frameworks
98

109
import Simple

test/ClangImporter/can_import_version_ignores_missing_tbd_version.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// should be no diagnostics and the version in the `.swiftmodule` should be
1313
// honored.
1414

15-
// RUN: echo "" > %t/frameworks/Simple.framework/Simple.tbd
15+
// RUN: rm -rf %t/frameworks/Simple.framework/Simple.tbd
1616
// RUN: echo "@_exported import Simple" > %t.overlay.swift
1717
// RUN: echo "public func additional() {}" >> %t.overlay.swift
1818

0 commit comments

Comments
 (0)