clang  6.0.0svn
ModuleDependencyCollector.cpp
Go to the documentation of this file.
1 //===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Collect the dependencies of a set of modules.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Basic/CharInfo.h"
15 #include "clang/Frontend/Utils.h"
16 #include "clang/Lex/Preprocessor.h"
18 #include "llvm/ADT/iterator_range.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 using namespace clang;
24 
25 namespace {
26 /// Private implementations for ModuleDependencyCollector
27 class ModuleDependencyListener : public ASTReaderListener {
28  ModuleDependencyCollector &Collector;
29 public:
30  ModuleDependencyListener(ModuleDependencyCollector &Collector)
31  : Collector(Collector) {}
32  bool needsInputFileVisitation() override { return true; }
33  bool needsSystemInputFileVisitation() override { return true; }
34  bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
35  bool IsExplicitModule) override {
36  Collector.addFile(Filename);
37  return true;
38  }
39 };
40 
41 struct ModuleDependencyPPCallbacks : public PPCallbacks {
42  ModuleDependencyCollector &Collector;
44  ModuleDependencyPPCallbacks(ModuleDependencyCollector &Collector,
45  SourceManager &SM)
46  : Collector(Collector), SM(SM) {}
47 
48  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
49  StringRef FileName, bool IsAngled,
50  CharSourceRange FilenameRange, const FileEntry *File,
51  StringRef SearchPath, StringRef RelativePath,
52  const Module *Imported) override {
53  if (!File)
54  return;
55  Collector.addFile(File->getName());
56  }
57 };
58 
59 struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
60  ModuleDependencyCollector &Collector;
61  ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector)
62  : Collector(Collector) {}
63 
64  void moduleMapAddHeader(StringRef HeaderPath) override {
65  if (llvm::sys::path::is_absolute(HeaderPath))
66  Collector.addFile(HeaderPath);
67  }
68  void moduleMapAddUmbrellaHeader(FileManager *FileMgr,
69  const FileEntry *Header) override {
70  StringRef HeaderFilename = Header->getName();
71  moduleMapAddHeader(HeaderFilename);
72  // The FileManager can find and cache the symbolic link for a framework
73  // header before its real path, this means a module can have some of its
74  // headers to use other paths. Although this is usually not a problem, it's
75  // inconsistent, and not collecting the original path header leads to
76  // umbrella clashes while rebuilding modules in the crash reproducer. For
77  // example:
78  // ApplicationServices.framework/Frameworks/ImageIO.framework/ImageIO.h
79  // instead of:
80  // ImageIO.framework/ImageIO.h
81  //
82  // FIXME: this shouldn't be necessary once we have FileName instances
83  // around instead of FileEntry ones. For now, make sure we collect all
84  // that we need for the reproducer to work correctly.
85  StringRef UmbreallDirFromHeader =
86  llvm::sys::path::parent_path(HeaderFilename);
87  StringRef UmbrellaDir = Header->getDir()->getName();
88  if (!UmbrellaDir.equals(UmbreallDirFromHeader)) {
89  SmallString<128> AltHeaderFilename;
90  llvm::sys::path::append(AltHeaderFilename, UmbrellaDir,
91  llvm::sys::path::filename(HeaderFilename));
92  if (FileMgr->getFile(AltHeaderFilename))
93  moduleMapAddHeader(AltHeaderFilename);
94  }
95  }
96 };
97 
98 }
99 
100 // TODO: move this to Support/Path.h and check for HAVE_REALPATH?
101 static bool real_path(StringRef SrcPath, SmallVectorImpl<char> &RealPath) {
102 #ifdef LLVM_ON_UNIX
103  char CanonicalPath[PATH_MAX];
104 
105  // TODO: emit a warning in case this fails...?
106  if (!realpath(SrcPath.str().c_str(), CanonicalPath))
107  return false;
108 
109  SmallString<256> RPath(CanonicalPath);
110  RealPath.swap(RPath);
111  return true;
112 #else
113  // FIXME: Add support for systems without realpath.
114  return false;
115 #endif
116 }
117 
119  R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
120 }
121 
123  PP.addPPCallbacks(llvm::make_unique<ModuleDependencyPPCallbacks>(
124  *this, PP.getSourceManager()));
126  llvm::make_unique<ModuleDependencyMMCallbacks>(*this));
127 }
128 
129 static bool isCaseSensitivePath(StringRef Path) {
130  SmallString<256> TmpDest = Path, UpperDest, RealDest;
131  // Remove component traversals, links, etc.
132  if (!real_path(Path, TmpDest))
133  return true; // Current default value in vfs.yaml
134  Path = TmpDest;
135 
136  // Change path to all upper case and ask for its real path, if the latter
137  // exists and is equal to Path, it's not case sensitive. Default to case
138  // sensitive in the absense of realpath, since this is what the VFSWriter
139  // already expects when sensitivity isn't setup.
140  for (auto &C : Path)
141  UpperDest.push_back(toUppercase(C));
142  if (real_path(UpperDest, RealDest) && Path.equals(RealDest))
143  return false;
144  return true;
145 }
146 
148  if (Seen.empty())
149  return;
150 
151  StringRef VFSDir = getDest();
152 
153  // Default to use relative overlay directories in the VFS yaml file. This
154  // allows crash reproducer scripts to work across machines.
155  VFSWriter.setOverlayDir(VFSDir);
156 
157  // Do not ignore non existent contents otherwise we might skip something
158  // that should have been collected here.
159  VFSWriter.setIgnoreNonExistentContents(false);
160 
161  // Explicitly set case sensitivity for the YAML writer. For that, find out
162  // the sensitivity at the path where the headers all collected to.
163  VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir));
164 
165  // Do not rely on real path names when executing the crash reproducer scripts
166  // since we only want to actually use the files we have on the VFS cache.
167  VFSWriter.setUseExternalNames(false);
168 
169  std::error_code EC;
170  SmallString<256> YAMLPath = VFSDir;
171  llvm::sys::path::append(YAMLPath, "vfs.yaml");
172  llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::F_Text);
173  if (EC) {
174  HasErrors = true;
175  return;
176  }
177  VFSWriter.write(OS);
178 }
179 
180 bool ModuleDependencyCollector::getRealPath(StringRef SrcPath,
182  using namespace llvm::sys;
183  SmallString<256> RealPath;
184  StringRef FileName = path::filename(SrcPath);
185  std::string Dir = path::parent_path(SrcPath).str();
186  auto DirWithSymLink = SymLinkMap.find(Dir);
187 
188  // Use real_path to fix any symbolic link component present in a path.
189  // Computing the real path is expensive, cache the search through the
190  // parent path directory.
191  if (DirWithSymLink == SymLinkMap.end()) {
192  if (!real_path(Dir, RealPath))
193  return false;
194  SymLinkMap[Dir] = RealPath.str();
195  } else {
196  RealPath = DirWithSymLink->second;
197  }
198 
199  path::append(RealPath, FileName);
200  Result.swap(RealPath);
201  return true;
202 }
203 
204 std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,
205  StringRef Dst) {
206  using namespace llvm::sys;
207 
208  // We need an absolute src path to append to the root.
209  SmallString<256> AbsoluteSrc = Src;
210  fs::make_absolute(AbsoluteSrc);
211  // Canonicalize src to a native path to avoid mixed separator styles.
212  path::native(AbsoluteSrc);
213  // Remove redundant leading "./" pieces and consecutive separators.
214  AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc);
215 
216  // Canonicalize the source path by removing "..", "." components.
217  SmallString<256> VirtualPath = AbsoluteSrc;
218  path::remove_dots(VirtualPath, /*remove_dot_dot=*/true);
219 
220  // If a ".." component is present after a symlink component, remove_dots may
221  // lead to the wrong real destination path. Let the source be canonicalized
222  // like that but make sure we always use the real path for the destination.
223  SmallString<256> CopyFrom;
224  if (!getRealPath(AbsoluteSrc, CopyFrom))
225  CopyFrom = VirtualPath;
226  SmallString<256> CacheDst = getDest();
227 
228  if (Dst.empty()) {
229  // The common case is to map the virtual path to the same path inside the
230  // cache.
231  path::append(CacheDst, path::relative_path(CopyFrom));
232  } else {
233  // When collecting entries from input vfsoverlays, copy the external
234  // contents into the cache but still map from the source.
235  if (!fs::exists(Dst))
236  return std::error_code();
237  path::append(CacheDst, Dst);
238  CopyFrom = Dst;
239  }
240 
241  // Copy the file into place.
242  if (std::error_code EC = fs::create_directories(path::parent_path(CacheDst),
243  /*IgnoreExisting=*/true))
244  return EC;
245  if (std::error_code EC = fs::copy_file(CopyFrom, CacheDst))
246  return EC;
247 
248  // Always map a canonical src path to its real path into the YAML, by doing
249  // this we map different virtual src paths to the same entry in the VFS
250  // overlay, which is a way to emulate symlink inside the VFS; this is also
251  // needed for correctness, not doing that can lead to module redefinition
252  // errors.
253  addFileMapping(VirtualPath, CacheDst);
254  return std::error_code();
255 }
256 
257 void ModuleDependencyCollector::addFile(StringRef Filename, StringRef FileDst) {
258  if (insertSeen(Filename))
259  if (copyToRoot(Filename, FileDst))
260  HasErrors = true;
261 }
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
void attachToASTReader(ASTReader &R) override
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:647
This interface provides a way to observe the actions of the preprocessor as it does its thing...
Definition: PPCallbacks.h:36
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
Describes a module or submodule.
Definition: Module.h:65
HeaderSearch & getHeaderSearchInfo() const
Definition: Preprocessor.h:817
void attachToPreprocessor(Preprocessor &PP) override
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
Definition: ModuleMap.h:372
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
StringRef Filename
Definition: Format.cpp:1345
void addFile(StringRef Filename, StringRef FileDst="")
Represents a character-granular source range.
Defines the clang::Preprocessor interface.
A mechanism to observe the actions of the module map parser as it reads module map files...
Definition: ModuleMap.h:46
Record the location of an inclusion directive, such as an #include or #import statement.
Collects the dependencies for imported modules into a directory.
Definition: Utils.h:122
The result type of a method or function.
const SourceManager & SM
Definition: Format.cpp:1337
SourceManager & getSourceManager() const
Definition: Preprocessor.h:815
const DirectoryEntry * getDir() const
Return the directory the file lives in.
Definition: FileManager.h:94
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
Definition: ASTReader.h:1560
Encodes a location in the source.
StringRef getName() const
Definition: FileManager.h:84
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:59
Dataflow Directional Tag Classes.
static bool isCaseSensitivePath(StringRef Path)
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:358
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:129
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
Definition: CharInfo.h:174
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Definition: Preprocessor.h:908
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:127
StringRef getName() const
Definition: FileManager.h:51
static bool real_path(StringRef SrcPath, SmallVectorImpl< char > &RealPath)