65
65
#include " llvm/Support/FileCollector.h"
66
66
#include " llvm/Support/Memory.h"
67
67
#include " llvm/Support/Path.h"
68
+ #include " llvm/Support/YAMLTraits.h"
69
+ #include " llvm/Support/YAMLParser.h"
68
70
#include < algorithm>
69
71
#include < memory>
70
72
@@ -1731,6 +1733,11 @@ bool ClangImporter::isModuleImported(const clang::Module *M) {
1731
1733
return M->NameVisibility == clang::Module::NameVisibilityKind::AllVisible;
1732
1734
}
1733
1735
1736
+ static std::string getScalaNodeText (llvm::yaml::Node *N) {
1737
+ SmallString<32 > Buffer;
1738
+ return cast<llvm::yaml::ScalarNode>(N)->getValue (Buffer).str ();
1739
+ }
1740
+
1734
1741
bool ClangImporter::canImportModule (ImportPath::Element moduleID,
1735
1742
llvm::VersionTuple version,
1736
1743
bool underlyingVersion) {
@@ -1748,7 +1755,66 @@ bool ClangImporter::canImportModule(ImportPath::Element moduleID,
1748
1755
clang::Module::UnresolvedHeaderDirective mh;
1749
1756
clang::Module *m;
1750
1757
auto &ctx = Impl.getClangASTContext ();
1751
- return clangModule->isAvailable (ctx.getLangOpts (), getTargetInfo (), r, mh, m);
1758
+ auto available = clangModule->isAvailable (ctx.getLangOpts (), getTargetInfo (),
1759
+ r, mh, m);
1760
+ if (!available)
1761
+ return false ;
1762
+ if (version.empty ())
1763
+ return true ;
1764
+ assert (available);
1765
+ assert (!version.empty ());
1766
+ llvm::VersionTuple currentVersion;
1767
+ StringRef path = getClangASTContext ().getSourceManager ()
1768
+ .getFilename (clangModule->DefinitionLoc );
1769
+ // Look for the .tbd file inside .framework dir to get the project version
1770
+ // number.
1771
+ std::string fwName = (llvm::Twine (moduleID.Item .str ()) + " .framework" ).str ();
1772
+ auto pos = path.find (fwName);
1773
+ while (pos != StringRef::npos) {
1774
+ llvm::SmallString<256 > buffer (path.substr (0 , pos + fwName.size ()));
1775
+ llvm::sys::path::append (buffer, llvm::Twine (moduleID.Item .str ()) + " .tbd" );
1776
+ auto tbdPath = buffer.str ();
1777
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> tbdBufOrErr =
1778
+ llvm::MemoryBuffer::getFile (tbdPath);
1779
+ // .tbd file doesn't exist, break.
1780
+ if (!tbdBufOrErr) {
1781
+ break ;
1782
+ }
1783
+ StringRef tbdBuffer = tbdBufOrErr->get ()->getBuffer ();
1784
+
1785
+ // Use a new source manager instead of the one from ASTContext because we
1786
+ // don't want the Json file to be persistent.
1787
+ SourceManager SM;
1788
+ llvm::yaml::Stream Stream (llvm::MemoryBufferRef (tbdBuffer, tbdPath),
1789
+ SM.getLLVMSourceMgr ());
1790
+ auto DI = Stream.begin ();
1791
+ assert (DI != Stream.end () && " Failed to read a document" );
1792
+ llvm::yaml::Node *N = DI->getRoot ();
1793
+ assert (N && " Failed to find a root" );
1794
+ auto *pairs = dyn_cast_or_null<llvm::yaml::MappingNode>(N);
1795
+ if (!pairs)
1796
+ break ;
1797
+ for (auto &keyValue: *pairs) {
1798
+ auto key = getScalaNodeText (keyValue.getKey ());
1799
+ // Look for field "current-version" in the .tbd file.
1800
+ if (key == " current-version" ) {
1801
+ auto ver = getScalaNodeText (keyValue.getValue ());
1802
+ currentVersion.tryParse (ver);
1803
+ break ;
1804
+ }
1805
+ }
1806
+ break ;
1807
+ }
1808
+ // Diagnose unable to checking the current version.
1809
+ if (currentVersion.empty ()) {
1810
+ Impl.diagnose (moduleID.Loc , diag::cannot_find_project_version, " Clang" ,
1811
+ moduleID.Item .str ());
1812
+ return true ;
1813
+ }
1814
+ assert (!currentVersion.empty ());
1815
+ // Give a green light if the version on disk is greater or equal to the version
1816
+ // specified in the canImport condition.
1817
+ return currentVersion >= version;
1752
1818
}
1753
1819
1754
1820
ModuleDecl *ClangImporter::Implementation::loadModuleClang (
0 commit comments