brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.7 KiB · ff37065 Raw
184 lines · cpp
1//===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Collect the dependencies of a set of modules.10//11//===----------------------------------------------------------------------===//12 13#include "clang/Basic/CharInfo.h"14#include "clang/Frontend/Utils.h"15#include "clang/Lex/Preprocessor.h"16#include "clang/Serialization/ASTReader.h"17#include "llvm/Config/llvm-config.h"18#include "llvm/Support/FileSystem.h"19#include "llvm/Support/Path.h"20#include "llvm/Support/raw_ostream.h"21 22using namespace clang;23 24namespace {25/// Private implementations for ModuleDependencyCollector26class ModuleDependencyListener : public ASTReaderListener {27  ModuleDependencyCollector &Collector;28  FileManager &FileMgr;29public:30  ModuleDependencyListener(ModuleDependencyCollector &Collector,31                           FileManager &FileMgr)32      : Collector(Collector), FileMgr(FileMgr) {}33  bool needsInputFileVisitation() override { return true; }34  bool needsSystemInputFileVisitation() override { return true; }35  bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,36                      bool IsExplicitModule) override {37    // Run this through the FileManager in order to respect 'use-external-name'38    // in case we have a VFS overlay.39    if (auto FE = FileMgr.getOptionalFileRef(Filename))40      Filename = FE->getName();41    Collector.addFile(Filename);42    return true;43  }44};45 46struct ModuleDependencyPPCallbacks : public PPCallbacks {47  ModuleDependencyCollector &Collector;48  SourceManager &SM;49  ModuleDependencyPPCallbacks(ModuleDependencyCollector &Collector,50                              SourceManager &SM)51      : Collector(Collector), SM(SM) {}52 53  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,54                          StringRef FileName, bool IsAngled,55                          CharSourceRange FilenameRange,56                          OptionalFileEntryRef File, StringRef SearchPath,57                          StringRef RelativePath, const Module *SuggestedModule,58                          bool ModuleImported,59                          SrcMgr::CharacteristicKind FileType) override {60    if (!File)61      return;62    Collector.addFile(File->getName());63  }64};65 66struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {67  ModuleDependencyCollector &Collector;68  ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector)69      : Collector(Collector) {}70 71  void moduleMapAddHeader(StringRef HeaderPath) override {72    if (llvm::sys::path::is_absolute(HeaderPath))73      Collector.addFile(HeaderPath);74  }75  void moduleMapAddUmbrellaHeader(FileEntryRef Header) override {76    moduleMapAddHeader(Header.getNameAsRequested());77  }78};79 80} // namespace81 82void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {83  R.addListener(84      std::make_unique<ModuleDependencyListener>(*this, R.getFileManager()));85}86 87void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {88  PP.addPPCallbacks(std::make_unique<ModuleDependencyPPCallbacks>(89      *this, PP.getSourceManager()));90  PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(91      std::make_unique<ModuleDependencyMMCallbacks>(*this));92}93 94static bool isCaseSensitivePath(llvm::vfs::FileSystem &VFS, StringRef Path) {95  SmallString<256> TmpDest = Path, UpperDest, RealDest;96  // Remove component traversals, links, etc.97  if (VFS.getRealPath(Path, TmpDest))98    return true; // Current default value in vfs.yaml99  Path = TmpDest;100 101  // Change path to all upper case and ask for its real path, if the latter102  // exists and is equal to Path, it's not case sensitive. Default to case103  // sensitive in the absence of realpath, since this is what the VFSWriter104  // already expects when sensitivity isn't setup.105  for (auto &C : Path)106    UpperDest.push_back(toUppercase(C));107  if (!VFS.getRealPath(UpperDest, RealDest) && Path == RealDest)108    return false;109  return true;110}111 112void ModuleDependencyCollector::writeFileMap() {113  if (Seen.empty())114    return;115 116  StringRef VFSDir = getDest();117 118  // Default to use relative overlay directories in the VFS yaml file. This119  // allows crash reproducer scripts to work across machines.120  VFSWriter.setOverlayDir(VFSDir);121 122  // Explicitly set case sensitivity for the YAML writer. For that, find out123  // the sensitivity at the path where the headers all collected to.124  VFSWriter.setCaseSensitivity(125      isCaseSensitivePath(Canonicalizer.getFileSystem(), VFSDir));126 127  // Do not rely on real path names when executing the crash reproducer scripts128  // since we only want to actually use the files we have on the VFS cache.129  VFSWriter.setUseExternalNames(false);130 131  std::error_code EC;132  SmallString<256> YAMLPath = VFSDir;133  llvm::sys::path::append(YAMLPath, "vfs.yaml");134  llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::OF_TextWithCRLF);135  if (EC) {136    HasErrors = true;137    return;138  }139  VFSWriter.write(OS);140}141 142std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,143                                                      StringRef Dst) {144  using namespace llvm::sys;145  llvm::FileCollector::PathCanonicalizer::PathStorage Paths =146      Canonicalizer.canonicalize(Src);147 148  SmallString<256> CacheDst = getDest();149 150  if (Dst.empty()) {151    // The common case is to map the virtual path to the same path inside the152    // cache.153    path::append(CacheDst, path::relative_path(Paths.CopyFrom));154  } else {155    // When collecting entries from input vfsoverlays, copy the external156    // contents into the cache but still map from the source.157    if (!Canonicalizer.getFileSystem().exists(Dst))158      return std::error_code();159    path::append(CacheDst, Dst);160    Paths.CopyFrom = Dst;161  }162 163  // Copy the file into place.164  if (std::error_code EC = fs::create_directories(path::parent_path(CacheDst),165                                                  /*IgnoreExisting=*/true))166    return EC;167  if (std::error_code EC = fs::copy_file(Paths.CopyFrom, CacheDst))168    return EC;169 170  // Always map a canonical src path to its real path into the YAML, by doing171  // this we map different virtual src paths to the same entry in the VFS172  // overlay, which is a way to emulate symlink inside the VFS; this is also173  // needed for correctness, not doing that can lead to module redefinition174  // errors.175  addFileMapping(Paths.VirtualPath, CacheDst);176  return std::error_code();177}178 179void ModuleDependencyCollector::addFile(StringRef Filename, StringRef FileDst) {180  if (insertSeen(Filename))181    if (copyToRoot(Filename, FileDst))182      HasErrors = true;183}184