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 
22 using namespace clang;
23 
24 namespace {
25 /// Private implementation for ModuleDependencyCollector
26 class ModuleDependencyListener : public ASTReaderListener {
27   ModuleDependencyCollector &Collector;
28 
29   std::error_code copyToRoot(StringRef Src);
30 public:
ModuleDependencyListener(ModuleDependencyCollector & Collector)31   ModuleDependencyListener(ModuleDependencyCollector &Collector)
32       : Collector(Collector) {}
needsInputFileVisitation()33   bool needsInputFileVisitation() override { return true; }
needsSystemInputFileVisitation()34   bool needsSystemInputFileVisitation() override { return true; }
35   bool visitInputFile(StringRef Filename, bool IsSystem,
36                       bool IsOverridden) override;
37 };
38 }
39 
attachToASTReader(ASTReader & R)40 void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
41   R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
42 }
43 
writeFileMap()44 void 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 
copyToRoot(StringRef Src)60 std::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 
visitInputFile(StringRef Filename,bool IsSystem,bool IsOverridden)87 bool 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