xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Frontend/ModuleDependencyCollector.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Collect the dependencies of a set of modules.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #include "clang/Basic/CharInfo.h"
147330f729Sjoerg #include "clang/Frontend/Utils.h"
157330f729Sjoerg #include "clang/Lex/Preprocessor.h"
167330f729Sjoerg #include "clang/Serialization/ASTReader.h"
177330f729Sjoerg #include "llvm/ADT/iterator_range.h"
187330f729Sjoerg #include "llvm/Config/llvm-config.h"
197330f729Sjoerg #include "llvm/Support/FileSystem.h"
207330f729Sjoerg #include "llvm/Support/Path.h"
217330f729Sjoerg #include "llvm/Support/raw_ostream.h"
227330f729Sjoerg 
237330f729Sjoerg using namespace clang;
247330f729Sjoerg 
257330f729Sjoerg namespace {
267330f729Sjoerg /// Private implementations for ModuleDependencyCollector
277330f729Sjoerg class ModuleDependencyListener : public ASTReaderListener {
287330f729Sjoerg   ModuleDependencyCollector &Collector;
297330f729Sjoerg public:
ModuleDependencyListener(ModuleDependencyCollector & Collector)307330f729Sjoerg   ModuleDependencyListener(ModuleDependencyCollector &Collector)
317330f729Sjoerg       : Collector(Collector) {}
needsInputFileVisitation()327330f729Sjoerg   bool needsInputFileVisitation() override { return true; }
needsSystemInputFileVisitation()337330f729Sjoerg   bool needsSystemInputFileVisitation() override { return true; }
visitInputFile(StringRef Filename,bool IsSystem,bool IsOverridden,bool IsExplicitModule)347330f729Sjoerg   bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
357330f729Sjoerg                       bool IsExplicitModule) override {
367330f729Sjoerg     Collector.addFile(Filename);
377330f729Sjoerg     return true;
387330f729Sjoerg   }
397330f729Sjoerg };
407330f729Sjoerg 
417330f729Sjoerg struct ModuleDependencyPPCallbacks : public PPCallbacks {
427330f729Sjoerg   ModuleDependencyCollector &Collector;
437330f729Sjoerg   SourceManager &SM;
ModuleDependencyPPCallbacks__anon38cbf7200111::ModuleDependencyPPCallbacks447330f729Sjoerg   ModuleDependencyPPCallbacks(ModuleDependencyCollector &Collector,
457330f729Sjoerg                               SourceManager &SM)
467330f729Sjoerg       : Collector(Collector), SM(SM) {}
477330f729Sjoerg 
InclusionDirective__anon38cbf7200111::ModuleDependencyPPCallbacks487330f729Sjoerg   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
497330f729Sjoerg                           StringRef FileName, bool IsAngled,
507330f729Sjoerg                           CharSourceRange FilenameRange, const FileEntry *File,
517330f729Sjoerg                           StringRef SearchPath, StringRef RelativePath,
527330f729Sjoerg                           const Module *Imported,
537330f729Sjoerg                           SrcMgr::CharacteristicKind FileType) override {
547330f729Sjoerg     if (!File)
557330f729Sjoerg       return;
567330f729Sjoerg     Collector.addFile(File->getName());
577330f729Sjoerg   }
587330f729Sjoerg };
597330f729Sjoerg 
607330f729Sjoerg struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
617330f729Sjoerg   ModuleDependencyCollector &Collector;
ModuleDependencyMMCallbacks__anon38cbf7200111::ModuleDependencyMMCallbacks627330f729Sjoerg   ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector)
637330f729Sjoerg       : Collector(Collector) {}
647330f729Sjoerg 
moduleMapAddHeader__anon38cbf7200111::ModuleDependencyMMCallbacks657330f729Sjoerg   void moduleMapAddHeader(StringRef HeaderPath) override {
667330f729Sjoerg     if (llvm::sys::path::is_absolute(HeaderPath))
677330f729Sjoerg       Collector.addFile(HeaderPath);
687330f729Sjoerg   }
moduleMapAddUmbrellaHeader__anon38cbf7200111::ModuleDependencyMMCallbacks697330f729Sjoerg   void moduleMapAddUmbrellaHeader(FileManager *FileMgr,
707330f729Sjoerg                                   const FileEntry *Header) override {
717330f729Sjoerg     StringRef HeaderFilename = Header->getName();
727330f729Sjoerg     moduleMapAddHeader(HeaderFilename);
737330f729Sjoerg     // The FileManager can find and cache the symbolic link for a framework
747330f729Sjoerg     // header before its real path, this means a module can have some of its
757330f729Sjoerg     // headers to use other paths. Although this is usually not a problem, it's
767330f729Sjoerg     // inconsistent, and not collecting the original path header leads to
777330f729Sjoerg     // umbrella clashes while rebuilding modules in the crash reproducer. For
787330f729Sjoerg     // example:
797330f729Sjoerg     //    ApplicationServices.framework/Frameworks/ImageIO.framework/ImageIO.h
807330f729Sjoerg     // instead of:
817330f729Sjoerg     //    ImageIO.framework/ImageIO.h
827330f729Sjoerg     //
837330f729Sjoerg     // FIXME: this shouldn't be necessary once we have FileName instances
847330f729Sjoerg     // around instead of FileEntry ones. For now, make sure we collect all
857330f729Sjoerg     // that we need for the reproducer to work correctly.
867330f729Sjoerg     StringRef UmbreallDirFromHeader =
877330f729Sjoerg         llvm::sys::path::parent_path(HeaderFilename);
887330f729Sjoerg     StringRef UmbrellaDir = Header->getDir()->getName();
897330f729Sjoerg     if (!UmbrellaDir.equals(UmbreallDirFromHeader)) {
907330f729Sjoerg       SmallString<128> AltHeaderFilename;
917330f729Sjoerg       llvm::sys::path::append(AltHeaderFilename, UmbrellaDir,
927330f729Sjoerg                               llvm::sys::path::filename(HeaderFilename));
937330f729Sjoerg       if (FileMgr->getFile(AltHeaderFilename))
947330f729Sjoerg         moduleMapAddHeader(AltHeaderFilename);
957330f729Sjoerg     }
967330f729Sjoerg   }
977330f729Sjoerg };
987330f729Sjoerg 
997330f729Sjoerg }
1007330f729Sjoerg 
attachToASTReader(ASTReader & R)1017330f729Sjoerg void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
1027330f729Sjoerg   R.addListener(std::make_unique<ModuleDependencyListener>(*this));
1037330f729Sjoerg }
1047330f729Sjoerg 
attachToPreprocessor(Preprocessor & PP)1057330f729Sjoerg void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {
1067330f729Sjoerg   PP.addPPCallbacks(std::make_unique<ModuleDependencyPPCallbacks>(
1077330f729Sjoerg       *this, PP.getSourceManager()));
1087330f729Sjoerg   PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
1097330f729Sjoerg       std::make_unique<ModuleDependencyMMCallbacks>(*this));
1107330f729Sjoerg }
1117330f729Sjoerg 
isCaseSensitivePath(StringRef Path)1127330f729Sjoerg static bool isCaseSensitivePath(StringRef Path) {
1137330f729Sjoerg   SmallString<256> TmpDest = Path, UpperDest, RealDest;
1147330f729Sjoerg   // Remove component traversals, links, etc.
1157330f729Sjoerg   if (llvm::sys::fs::real_path(Path, TmpDest))
1167330f729Sjoerg     return true; // Current default value in vfs.yaml
1177330f729Sjoerg   Path = TmpDest;
1187330f729Sjoerg 
1197330f729Sjoerg   // Change path to all upper case and ask for its real path, if the latter
1207330f729Sjoerg   // exists and is equal to Path, it's not case sensitive. Default to case
1217330f729Sjoerg   // sensitive in the absence of realpath, since this is what the VFSWriter
1227330f729Sjoerg   // already expects when sensitivity isn't setup.
1237330f729Sjoerg   for (auto &C : Path)
1247330f729Sjoerg     UpperDest.push_back(toUppercase(C));
1257330f729Sjoerg   if (!llvm::sys::fs::real_path(UpperDest, RealDest) && Path.equals(RealDest))
1267330f729Sjoerg     return false;
1277330f729Sjoerg   return true;
1287330f729Sjoerg }
1297330f729Sjoerg 
writeFileMap()1307330f729Sjoerg void ModuleDependencyCollector::writeFileMap() {
1317330f729Sjoerg   if (Seen.empty())
1327330f729Sjoerg     return;
1337330f729Sjoerg 
1347330f729Sjoerg   StringRef VFSDir = getDest();
1357330f729Sjoerg 
1367330f729Sjoerg   // Default to use relative overlay directories in the VFS yaml file. This
1377330f729Sjoerg   // allows crash reproducer scripts to work across machines.
1387330f729Sjoerg   VFSWriter.setOverlayDir(VFSDir);
1397330f729Sjoerg 
1407330f729Sjoerg   // Explicitly set case sensitivity for the YAML writer. For that, find out
1417330f729Sjoerg   // the sensitivity at the path where the headers all collected to.
1427330f729Sjoerg   VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir));
1437330f729Sjoerg 
1447330f729Sjoerg   // Do not rely on real path names when executing the crash reproducer scripts
1457330f729Sjoerg   // since we only want to actually use the files we have on the VFS cache.
1467330f729Sjoerg   VFSWriter.setUseExternalNames(false);
1477330f729Sjoerg 
1487330f729Sjoerg   std::error_code EC;
1497330f729Sjoerg   SmallString<256> YAMLPath = VFSDir;
1507330f729Sjoerg   llvm::sys::path::append(YAMLPath, "vfs.yaml");
151*e038c9c4Sjoerg   llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::OF_TextWithCRLF);
1527330f729Sjoerg   if (EC) {
1537330f729Sjoerg     HasErrors = true;
1547330f729Sjoerg     return;
1557330f729Sjoerg   }
1567330f729Sjoerg   VFSWriter.write(OS);
1577330f729Sjoerg }
1587330f729Sjoerg 
copyToRoot(StringRef Src,StringRef Dst)1597330f729Sjoerg std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,
1607330f729Sjoerg                                                       StringRef Dst) {
1617330f729Sjoerg   using namespace llvm::sys;
162*e038c9c4Sjoerg   llvm::FileCollector::PathCanonicalizer::PathStorage Paths =
163*e038c9c4Sjoerg       Canonicalizer.canonicalize(Src);
1647330f729Sjoerg 
1657330f729Sjoerg   SmallString<256> CacheDst = getDest();
1667330f729Sjoerg 
1677330f729Sjoerg   if (Dst.empty()) {
1687330f729Sjoerg     // The common case is to map the virtual path to the same path inside the
1697330f729Sjoerg     // cache.
170*e038c9c4Sjoerg     path::append(CacheDst, path::relative_path(Paths.CopyFrom));
1717330f729Sjoerg   } else {
1727330f729Sjoerg     // When collecting entries from input vfsoverlays, copy the external
1737330f729Sjoerg     // contents into the cache but still map from the source.
1747330f729Sjoerg     if (!fs::exists(Dst))
1757330f729Sjoerg       return std::error_code();
1767330f729Sjoerg     path::append(CacheDst, Dst);
177*e038c9c4Sjoerg     Paths.CopyFrom = Dst;
1787330f729Sjoerg   }
1797330f729Sjoerg 
1807330f729Sjoerg   // Copy the file into place.
1817330f729Sjoerg   if (std::error_code EC = fs::create_directories(path::parent_path(CacheDst),
1827330f729Sjoerg                                                   /*IgnoreExisting=*/true))
1837330f729Sjoerg     return EC;
184*e038c9c4Sjoerg   if (std::error_code EC = fs::copy_file(Paths.CopyFrom, CacheDst))
1857330f729Sjoerg     return EC;
1867330f729Sjoerg 
1877330f729Sjoerg   // Always map a canonical src path to its real path into the YAML, by doing
1887330f729Sjoerg   // this we map different virtual src paths to the same entry in the VFS
1897330f729Sjoerg   // overlay, which is a way to emulate symlink inside the VFS; this is also
1907330f729Sjoerg   // needed for correctness, not doing that can lead to module redefinition
1917330f729Sjoerg   // errors.
192*e038c9c4Sjoerg   addFileMapping(Paths.VirtualPath, CacheDst);
1937330f729Sjoerg   return std::error_code();
1947330f729Sjoerg }
1957330f729Sjoerg 
addFile(StringRef Filename,StringRef FileDst)1967330f729Sjoerg void ModuleDependencyCollector::addFile(StringRef Filename, StringRef FileDst) {
1977330f729Sjoerg   if (insertSeen(Filename))
1987330f729Sjoerg     if (copyToRoot(Filename, FileDst))
1997330f729Sjoerg       HasErrors = true;
2007330f729Sjoerg }
201