Mercurial > hg > CbC > CbC_llvm
comparison clang/lib/Frontend/ModuleDependencyCollector.cpp @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | 2e18cbf3894f |
comparison
equal
deleted
inserted
replaced
147:c2174574ed3a | 150:1d019706d866 |
---|---|
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-exception | |
6 // | |
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/ADT/iterator_range.h" | |
18 #include "llvm/Config/llvm-config.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; | |
43 SourceManager &SM; | |
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, | |
53 SrcMgr::CharacteristicKind FileType) override { | |
54 if (!File) | |
55 return; | |
56 Collector.addFile(File->getName()); | |
57 } | |
58 }; | |
59 | |
60 struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks { | |
61 ModuleDependencyCollector &Collector; | |
62 ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector) | |
63 : Collector(Collector) {} | |
64 | |
65 void moduleMapAddHeader(StringRef HeaderPath) override { | |
66 if (llvm::sys::path::is_absolute(HeaderPath)) | |
67 Collector.addFile(HeaderPath); | |
68 } | |
69 void moduleMapAddUmbrellaHeader(FileManager *FileMgr, | |
70 const FileEntry *Header) override { | |
71 StringRef HeaderFilename = Header->getName(); | |
72 moduleMapAddHeader(HeaderFilename); | |
73 // The FileManager can find and cache the symbolic link for a framework | |
74 // header before its real path, this means a module can have some of its | |
75 // headers to use other paths. Although this is usually not a problem, it's | |
76 // inconsistent, and not collecting the original path header leads to | |
77 // umbrella clashes while rebuilding modules in the crash reproducer. For | |
78 // example: | |
79 // ApplicationServices.framework/Frameworks/ImageIO.framework/ImageIO.h | |
80 // instead of: | |
81 // ImageIO.framework/ImageIO.h | |
82 // | |
83 // FIXME: this shouldn't be necessary once we have FileName instances | |
84 // around instead of FileEntry ones. For now, make sure we collect all | |
85 // that we need for the reproducer to work correctly. | |
86 StringRef UmbreallDirFromHeader = | |
87 llvm::sys::path::parent_path(HeaderFilename); | |
88 StringRef UmbrellaDir = Header->getDir()->getName(); | |
89 if (!UmbrellaDir.equals(UmbreallDirFromHeader)) { | |
90 SmallString<128> AltHeaderFilename; | |
91 llvm::sys::path::append(AltHeaderFilename, UmbrellaDir, | |
92 llvm::sys::path::filename(HeaderFilename)); | |
93 if (FileMgr->getFile(AltHeaderFilename)) | |
94 moduleMapAddHeader(AltHeaderFilename); | |
95 } | |
96 } | |
97 }; | |
98 | |
99 } | |
100 | |
101 void ModuleDependencyCollector::attachToASTReader(ASTReader &R) { | |
102 R.addListener(std::make_unique<ModuleDependencyListener>(*this)); | |
103 } | |
104 | |
105 void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) { | |
106 PP.addPPCallbacks(std::make_unique<ModuleDependencyPPCallbacks>( | |
107 *this, PP.getSourceManager())); | |
108 PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks( | |
109 std::make_unique<ModuleDependencyMMCallbacks>(*this)); | |
110 } | |
111 | |
112 static bool isCaseSensitivePath(StringRef Path) { | |
113 SmallString<256> TmpDest = Path, UpperDest, RealDest; | |
114 // Remove component traversals, links, etc. | |
115 if (llvm::sys::fs::real_path(Path, TmpDest)) | |
116 return true; // Current default value in vfs.yaml | |
117 Path = TmpDest; | |
118 | |
119 // Change path to all upper case and ask for its real path, if the latter | |
120 // exists and is equal to Path, it's not case sensitive. Default to case | |
121 // sensitive in the absence of realpath, since this is what the VFSWriter | |
122 // already expects when sensitivity isn't setup. | |
123 for (auto &C : Path) | |
124 UpperDest.push_back(toUppercase(C)); | |
125 if (!llvm::sys::fs::real_path(UpperDest, RealDest) && Path.equals(RealDest)) | |
126 return false; | |
127 return true; | |
128 } | |
129 | |
130 void ModuleDependencyCollector::writeFileMap() { | |
131 if (Seen.empty()) | |
132 return; | |
133 | |
134 StringRef VFSDir = getDest(); | |
135 | |
136 // Default to use relative overlay directories in the VFS yaml file. This | |
137 // allows crash reproducer scripts to work across machines. | |
138 VFSWriter.setOverlayDir(VFSDir); | |
139 | |
140 // Explicitly set case sensitivity for the YAML writer. For that, find out | |
141 // the sensitivity at the path where the headers all collected to. | |
142 VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir)); | |
143 | |
144 // Do not rely on real path names when executing the crash reproducer scripts | |
145 // since we only want to actually use the files we have on the VFS cache. | |
146 VFSWriter.setUseExternalNames(false); | |
147 | |
148 std::error_code EC; | |
149 SmallString<256> YAMLPath = VFSDir; | |
150 llvm::sys::path::append(YAMLPath, "vfs.yaml"); | |
151 llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::OF_Text); | |
152 if (EC) { | |
153 HasErrors = true; | |
154 return; | |
155 } | |
156 VFSWriter.write(OS); | |
157 } | |
158 | |
159 bool ModuleDependencyCollector::getRealPath(StringRef SrcPath, | |
160 SmallVectorImpl<char> &Result) { | |
161 using namespace llvm::sys; | |
162 SmallString<256> RealPath; | |
163 StringRef FileName = path::filename(SrcPath); | |
164 std::string Dir = path::parent_path(SrcPath).str(); | |
165 auto DirWithSymLink = SymLinkMap.find(Dir); | |
166 | |
167 // Use real_path to fix any symbolic link component present in a path. | |
168 // Computing the real path is expensive, cache the search through the | |
169 // parent path directory. | |
170 if (DirWithSymLink == SymLinkMap.end()) { | |
171 if (llvm::sys::fs::real_path(Dir, RealPath)) | |
172 return false; | |
173 SymLinkMap[Dir] = std::string(RealPath.str()); | |
174 } else { | |
175 RealPath = DirWithSymLink->second; | |
176 } | |
177 | |
178 path::append(RealPath, FileName); | |
179 Result.swap(RealPath); | |
180 return true; | |
181 } | |
182 | |
183 std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src, | |
184 StringRef Dst) { | |
185 using namespace llvm::sys; | |
186 | |
187 // We need an absolute src path to append to the root. | |
188 SmallString<256> AbsoluteSrc = Src; | |
189 fs::make_absolute(AbsoluteSrc); | |
190 // Canonicalize src to a native path to avoid mixed separator styles. | |
191 path::native(AbsoluteSrc); | |
192 // Remove redundant leading "./" pieces and consecutive separators. | |
193 AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc); | |
194 | |
195 // Canonicalize the source path by removing "..", "." components. | |
196 SmallString<256> VirtualPath = AbsoluteSrc; | |
197 path::remove_dots(VirtualPath, /*remove_dot_dot=*/true); | |
198 | |
199 // If a ".." component is present after a symlink component, remove_dots may | |
200 // lead to the wrong real destination path. Let the source be canonicalized | |
201 // like that but make sure we always use the real path for the destination. | |
202 SmallString<256> CopyFrom; | |
203 if (!getRealPath(AbsoluteSrc, CopyFrom)) | |
204 CopyFrom = VirtualPath; | |
205 SmallString<256> CacheDst = getDest(); | |
206 | |
207 if (Dst.empty()) { | |
208 // The common case is to map the virtual path to the same path inside the | |
209 // cache. | |
210 path::append(CacheDst, path::relative_path(CopyFrom)); | |
211 } else { | |
212 // When collecting entries from input vfsoverlays, copy the external | |
213 // contents into the cache but still map from the source. | |
214 if (!fs::exists(Dst)) | |
215 return std::error_code(); | |
216 path::append(CacheDst, Dst); | |
217 CopyFrom = Dst; | |
218 } | |
219 | |
220 // Copy the file into place. | |
221 if (std::error_code EC = fs::create_directories(path::parent_path(CacheDst), | |
222 /*IgnoreExisting=*/true)) | |
223 return EC; | |
224 if (std::error_code EC = fs::copy_file(CopyFrom, CacheDst)) | |
225 return EC; | |
226 | |
227 // Always map a canonical src path to its real path into the YAML, by doing | |
228 // this we map different virtual src paths to the same entry in the VFS | |
229 // overlay, which is a way to emulate symlink inside the VFS; this is also | |
230 // needed for correctness, not doing that can lead to module redefinition | |
231 // errors. | |
232 addFileMapping(VirtualPath, CacheDst); | |
233 return std::error_code(); | |
234 } | |
235 | |
236 void ModuleDependencyCollector::addFile(StringRef Filename, StringRef FileDst) { | |
237 if (insertSeen(Filename)) | |
238 if (copyToRoot(Filename, FileDst)) | |
239 HasErrors = true; | |
240 } |