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/Frontend/Utils.h"
15#include "clang/Serialization/ASTReader.h"
16#include "llvm/ADT/StringSet.h"
17#include "llvm/ADT/iterator_range.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 implementation for ModuleDependencyCollector
26class ModuleDependencyListener : public ASTReaderListener {
27  ModuleDependencyCollector &Collector;
28
29  std::error_code copyToRoot(StringRef Src);
30public:
31  ModuleDependencyListener(ModuleDependencyCollector &Collector)
32      : Collector(Collector) {}
33  bool needsInputFileVisitation() override { return true; }
34  bool needsSystemInputFileVisitation() override { return true; }
35  bool visitInputFile(StringRef Filename, bool IsSystem,
36                      bool IsOverridden) override;
37};
38}
39
40void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
41  R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
42}
43
44void ModuleDependencyCollector::writeFileMap() {
45  if (Seen.empty())
46    return;
47
48  SmallString<256> Dest = getDest();
49  llvm::sys::path::append(Dest, "vfs.yaml");
50
51  std::error_code EC;
52  llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text);
53  if (EC) {
54    setHasErrors();
55    return;
56  }
57  VFSWriter.write(OS);
58}
59
60std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
61  using namespace llvm::sys;
62
63  // We need an absolute path to append to the root.
64  SmallString<256> AbsoluteSrc = Src;
65  fs::make_absolute(AbsoluteSrc);
66  // Canonicalize to a native path to avoid mixed separator styles.
67  path::native(AbsoluteSrc);
68  // TODO: We probably need to handle .. as well as . in order to have valid
69  // input to the YAMLVFSWriter.
70  FileManager::removeDotPaths(AbsoluteSrc);
71
72  // Build the destination path.
73  SmallString<256> Dest = Collector.getDest();
74  path::append(Dest, path::relative_path(AbsoluteSrc));
75
76  // Copy the file into place.
77  if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
78                                                   /*IgnoreExisting=*/true))
79    return EC;
80  if (std::error_code EC = fs::copy_file(AbsoluteSrc, Dest))
81    return EC;
82  // Use the absolute path under the root for the file mapping.
83  Collector.addFileMapping(AbsoluteSrc, Dest);
84  return std::error_code();
85}
86
87bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem,
88                                              bool IsOverridden) {
89  if (Collector.insertSeen(Filename))
90    if (copyToRoot(Filename))
91      Collector.setHasErrors();
92  return true;
93}
94