]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
r274961 through r275075
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Frontend / ModuleDependencyCollector.cpp
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/iterator_range.h"
17 #include "llvm/ADT/StringSet.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:
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
40 void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
41   R.addListener(new ModuleDependencyListener(*this));
42 }
43
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::string ErrorInfo;
52   llvm::raw_fd_ostream OS(Dest.c_str(), ErrorInfo, llvm::sys::fs::F_Text);
53   if (!ErrorInfo.empty()) {
54     setHasErrors();
55     return;
56   }
57   VFSWriter.write(OS);
58 }
59
60 /// Remove traversal (ie, . or ..) from the given absolute path.
61 static void removePathTraversal(SmallVectorImpl<char> &Path) {
62   using namespace llvm::sys;
63   SmallVector<StringRef, 16> ComponentStack;
64   StringRef P(Path.data(), Path.size());
65
66   // Skip the root path, then look for traversal in the components.
67   StringRef Rel = path::relative_path(P);
68   for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) {
69     if (C == ".")
70       continue;
71     if (C == "..") {
72       assert(ComponentStack.size() && "Path traverses out of parent");
73       ComponentStack.pop_back();
74     } else
75       ComponentStack.push_back(C);
76   }
77
78   // The stack is now the path without any directory traversal.
79   SmallString<256> Buffer = path::root_path(P);
80   for (StringRef C : ComponentStack)
81     path::append(Buffer, C);
82
83   // Put the result in Path.
84   Path.swap(Buffer);
85 }
86
87 std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
88   using namespace llvm::sys;
89
90   // We need an absolute path to append to the root.
91   SmallString<256> AbsoluteSrc = Src;
92   fs::make_absolute(AbsoluteSrc);
93   removePathTraversal(AbsoluteSrc);
94
95   // Build the destination path.
96   SmallString<256> Dest = Collector.getDest();
97   path::append(Dest, path::relative_path(AbsoluteSrc));
98
99   // Copy the file into place.
100   if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
101                                                    /*IgnoreExisting=*/true))
102     return EC;
103   if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str()))
104     return EC;
105   // Use the absolute path under the root for the file mapping.
106   Collector.addFileMapping(AbsoluteSrc.str(), Dest.str());
107   return std::error_code();
108 }
109
110 bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem,
111                                               bool IsOverridden) {
112   if (Collector.insertSeen(Filename))
113     if (copyToRoot(Filename))
114       Collector.setHasErrors();
115   return true;
116 }