xref: /aosp_15_r20/external/clang/lib/Frontend/ModuleDependencyCollector.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // Collect the dependencies of a set of modules.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li 
14*67e74705SXin Li #include "clang/Basic/CharInfo.h"
15*67e74705SXin Li #include "clang/Frontend/Utils.h"
16*67e74705SXin Li #include "clang/Lex/Preprocessor.h"
17*67e74705SXin Li #include "clang/Serialization/ASTReader.h"
18*67e74705SXin Li #include "llvm/ADT/StringMap.h"
19*67e74705SXin Li #include "llvm/ADT/iterator_range.h"
20*67e74705SXin Li #include "llvm/Support/FileSystem.h"
21*67e74705SXin Li #include "llvm/Support/Path.h"
22*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
23*67e74705SXin Li 
24*67e74705SXin Li using namespace clang;
25*67e74705SXin Li 
26*67e74705SXin Li namespace {
27*67e74705SXin Li /// Private implementations for ModuleDependencyCollector
28*67e74705SXin Li class ModuleDependencyListener : public ASTReaderListener {
29*67e74705SXin Li   ModuleDependencyCollector &Collector;
30*67e74705SXin Li public:
ModuleDependencyListener(ModuleDependencyCollector & Collector)31*67e74705SXin Li   ModuleDependencyListener(ModuleDependencyCollector &Collector)
32*67e74705SXin Li       : Collector(Collector) {}
needsInputFileVisitation()33*67e74705SXin Li   bool needsInputFileVisitation() override { return true; }
needsSystemInputFileVisitation()34*67e74705SXin Li   bool needsSystemInputFileVisitation() override { return true; }
visitInputFile(StringRef Filename,bool IsSystem,bool IsOverridden,bool IsExplicitModule)35*67e74705SXin Li   bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
36*67e74705SXin Li                       bool IsExplicitModule) override {
37*67e74705SXin Li     Collector.addFile(Filename);
38*67e74705SXin Li     return true;
39*67e74705SXin Li   }
40*67e74705SXin Li };
41*67e74705SXin Li 
42*67e74705SXin Li struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
43*67e74705SXin Li   ModuleDependencyCollector &Collector;
ModuleDependencyMMCallbacks__anone6ea444d0111::ModuleDependencyMMCallbacks44*67e74705SXin Li   ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector)
45*67e74705SXin Li       : Collector(Collector) {}
46*67e74705SXin Li 
moduleMapAddHeader__anone6ea444d0111::ModuleDependencyMMCallbacks47*67e74705SXin Li   void moduleMapAddHeader(StringRef HeaderPath) override {
48*67e74705SXin Li     if (llvm::sys::path::is_absolute(HeaderPath))
49*67e74705SXin Li       Collector.addFile(HeaderPath);
50*67e74705SXin Li   }
moduleMapAddUmbrellaHeader__anone6ea444d0111::ModuleDependencyMMCallbacks51*67e74705SXin Li   void moduleMapAddUmbrellaHeader(FileManager *FileMgr,
52*67e74705SXin Li                                   const FileEntry *Header) override {
53*67e74705SXin Li     StringRef HeaderFilename = Header->getName();
54*67e74705SXin Li     moduleMapAddHeader(HeaderFilename);
55*67e74705SXin Li     // The FileManager can find and cache the symbolic link for a framework
56*67e74705SXin Li     // header before its real path, this means a module can have some of its
57*67e74705SXin Li     // headers to use other paths. Although this is usually not a problem, it's
58*67e74705SXin Li     // inconsistent, and not collecting the original path header leads to
59*67e74705SXin Li     // umbrella clashes while rebuilding modules in the crash reproducer. For
60*67e74705SXin Li     // example:
61*67e74705SXin Li     //    ApplicationServices.framework/Frameworks/ImageIO.framework/ImageIO.h
62*67e74705SXin Li     // instead of:
63*67e74705SXin Li     //    ImageIO.framework/ImageIO.h
64*67e74705SXin Li     //
65*67e74705SXin Li     // FIXME: this shouldn't be necessary once we have FileName instances
66*67e74705SXin Li     // around instead of FileEntry ones. For now, make sure we collect all
67*67e74705SXin Li     // that we need for the reproducer to work correctly.
68*67e74705SXin Li     StringRef UmbreallDirFromHeader =
69*67e74705SXin Li         llvm::sys::path::parent_path(HeaderFilename);
70*67e74705SXin Li     StringRef UmbrellaDir = Header->getDir()->getName();
71*67e74705SXin Li     if (!UmbrellaDir.equals(UmbreallDirFromHeader)) {
72*67e74705SXin Li       SmallString<128> AltHeaderFilename;
73*67e74705SXin Li       llvm::sys::path::append(AltHeaderFilename, UmbrellaDir,
74*67e74705SXin Li                               llvm::sys::path::filename(HeaderFilename));
75*67e74705SXin Li       if (FileMgr->getFile(AltHeaderFilename))
76*67e74705SXin Li         moduleMapAddHeader(AltHeaderFilename);
77*67e74705SXin Li     }
78*67e74705SXin Li   }
79*67e74705SXin Li };
80*67e74705SXin Li 
81*67e74705SXin Li }
82*67e74705SXin Li 
83*67e74705SXin Li // TODO: move this to Support/Path.h and check for HAVE_REALPATH?
real_path(StringRef SrcPath,SmallVectorImpl<char> & RealPath)84*67e74705SXin Li static bool real_path(StringRef SrcPath, SmallVectorImpl<char> &RealPath) {
85*67e74705SXin Li #ifdef LLVM_ON_UNIX
86*67e74705SXin Li   char CanonicalPath[PATH_MAX];
87*67e74705SXin Li 
88*67e74705SXin Li   // TODO: emit a warning in case this fails...?
89*67e74705SXin Li   if (!realpath(SrcPath.str().c_str(), CanonicalPath))
90*67e74705SXin Li     return false;
91*67e74705SXin Li 
92*67e74705SXin Li   SmallString<256> RPath(CanonicalPath);
93*67e74705SXin Li   RealPath.swap(RPath);
94*67e74705SXin Li   return true;
95*67e74705SXin Li #else
96*67e74705SXin Li   // FIXME: Add support for systems without realpath.
97*67e74705SXin Li   return false;
98*67e74705SXin Li #endif
99*67e74705SXin Li }
100*67e74705SXin Li 
attachToASTReader(ASTReader & R)101*67e74705SXin Li void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
102*67e74705SXin Li   R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
103*67e74705SXin Li }
104*67e74705SXin Li 
attachToPreprocessor(Preprocessor & PP)105*67e74705SXin Li void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {
106*67e74705SXin Li   PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
107*67e74705SXin Li       llvm::make_unique<ModuleDependencyMMCallbacks>(*this));
108*67e74705SXin Li }
109*67e74705SXin Li 
isCaseSensitivePath(StringRef Path)110*67e74705SXin Li static bool isCaseSensitivePath(StringRef Path) {
111*67e74705SXin Li   SmallString<256> TmpDest = Path, UpperDest, RealDest;
112*67e74705SXin Li   // Remove component traversals, links, etc.
113*67e74705SXin Li   if (!real_path(Path, TmpDest))
114*67e74705SXin Li     return true; // Current default value in vfs.yaml
115*67e74705SXin Li   Path = TmpDest;
116*67e74705SXin Li 
117*67e74705SXin Li   // Change path to all upper case and ask for its real path, if the latter
118*67e74705SXin Li   // exists and is equal to Path, it's not case sensitive. Default to case
119*67e74705SXin Li   // sensitive in the absense of realpath, since this is what the VFSWriter
120*67e74705SXin Li   // already expects when sensitivity isn't setup.
121*67e74705SXin Li   for (auto &C : Path)
122*67e74705SXin Li     UpperDest.push_back(toUppercase(C));
123*67e74705SXin Li   if (real_path(UpperDest, RealDest) && Path.equals(RealDest))
124*67e74705SXin Li     return false;
125*67e74705SXin Li   return true;
126*67e74705SXin Li }
127*67e74705SXin Li 
writeFileMap()128*67e74705SXin Li void ModuleDependencyCollector::writeFileMap() {
129*67e74705SXin Li   if (Seen.empty())
130*67e74705SXin Li     return;
131*67e74705SXin Li 
132*67e74705SXin Li   StringRef VFSDir = getDest();
133*67e74705SXin Li 
134*67e74705SXin Li   // Default to use relative overlay directories in the VFS yaml file. This
135*67e74705SXin Li   // allows crash reproducer scripts to work across machines.
136*67e74705SXin Li   VFSWriter.setOverlayDir(VFSDir);
137*67e74705SXin Li 
138*67e74705SXin Li   // Explicitly set case sensitivity for the YAML writer. For that, find out
139*67e74705SXin Li   // the sensitivity at the path where the headers all collected to.
140*67e74705SXin Li   VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir));
141*67e74705SXin Li 
142*67e74705SXin Li   // Do not rely on real path names when executing the crash reproducer scripts
143*67e74705SXin Li   // since we only want to actually use the files we have on the VFS cache.
144*67e74705SXin Li   VFSWriter.setUseExternalNames(false);
145*67e74705SXin Li 
146*67e74705SXin Li   std::error_code EC;
147*67e74705SXin Li   SmallString<256> YAMLPath = VFSDir;
148*67e74705SXin Li   llvm::sys::path::append(YAMLPath, "vfs.yaml");
149*67e74705SXin Li   llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::F_Text);
150*67e74705SXin Li   if (EC) {
151*67e74705SXin Li     HasErrors = true;
152*67e74705SXin Li     return;
153*67e74705SXin Li   }
154*67e74705SXin Li   VFSWriter.write(OS);
155*67e74705SXin Li }
156*67e74705SXin Li 
getRealPath(StringRef SrcPath,SmallVectorImpl<char> & Result)157*67e74705SXin Li bool ModuleDependencyCollector::getRealPath(StringRef SrcPath,
158*67e74705SXin Li                                             SmallVectorImpl<char> &Result) {
159*67e74705SXin Li   using namespace llvm::sys;
160*67e74705SXin Li   SmallString<256> RealPath;
161*67e74705SXin Li   StringRef FileName = path::filename(SrcPath);
162*67e74705SXin Li   std::string Dir = path::parent_path(SrcPath).str();
163*67e74705SXin Li   auto DirWithSymLink = SymLinkMap.find(Dir);
164*67e74705SXin Li 
165*67e74705SXin Li   // Use real_path to fix any symbolic link component present in a path.
166*67e74705SXin Li   // Computing the real path is expensive, cache the search through the
167*67e74705SXin Li   // parent path directory.
168*67e74705SXin Li   if (DirWithSymLink == SymLinkMap.end()) {
169*67e74705SXin Li     if (!real_path(Dir, RealPath))
170*67e74705SXin Li       return false;
171*67e74705SXin Li     SymLinkMap[Dir] = RealPath.str();
172*67e74705SXin Li   } else {
173*67e74705SXin Li     RealPath = DirWithSymLink->second;
174*67e74705SXin Li   }
175*67e74705SXin Li 
176*67e74705SXin Li   path::append(RealPath, FileName);
177*67e74705SXin Li   Result.swap(RealPath);
178*67e74705SXin Li   return true;
179*67e74705SXin Li }
180*67e74705SXin Li 
copyToRoot(StringRef Src)181*67e74705SXin Li std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src) {
182*67e74705SXin Li   using namespace llvm::sys;
183*67e74705SXin Li 
184*67e74705SXin Li   // We need an absolute src path to append to the root.
185*67e74705SXin Li   SmallString<256> AbsoluteSrc = Src;
186*67e74705SXin Li   fs::make_absolute(AbsoluteSrc);
187*67e74705SXin Li   // Canonicalize src to a native path to avoid mixed separator styles.
188*67e74705SXin Li   path::native(AbsoluteSrc);
189*67e74705SXin Li   // Remove redundant leading "./" pieces and consecutive separators.
190*67e74705SXin Li   AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc);
191*67e74705SXin Li 
192*67e74705SXin Li   // Canonicalize the source path by removing "..", "." components.
193*67e74705SXin Li   SmallString<256> CanonicalPath = AbsoluteSrc;
194*67e74705SXin Li   path::remove_dots(CanonicalPath, /*remove_dot_dot=*/true);
195*67e74705SXin Li 
196*67e74705SXin Li   // If a ".." component is present after a symlink component, remove_dots may
197*67e74705SXin Li   // lead to the wrong real destination path. Let the source be canonicalized
198*67e74705SXin Li   // like that but make sure we always use the real path for the destination.
199*67e74705SXin Li   SmallString<256> RealPath;
200*67e74705SXin Li   if (!getRealPath(AbsoluteSrc, RealPath))
201*67e74705SXin Li     RealPath = CanonicalPath;
202*67e74705SXin Li   SmallString<256> Dest = getDest();
203*67e74705SXin Li   path::append(Dest, path::relative_path(RealPath));
204*67e74705SXin Li 
205*67e74705SXin Li   // Copy the file into place.
206*67e74705SXin Li   if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
207*67e74705SXin Li                                                    /*IgnoreExisting=*/true))
208*67e74705SXin Li     return EC;
209*67e74705SXin Li   if (std::error_code EC = fs::copy_file(RealPath, Dest))
210*67e74705SXin Li     return EC;
211*67e74705SXin Li 
212*67e74705SXin Li   // Always map a canonical src path to its real path into the YAML, by doing
213*67e74705SXin Li   // this we map different virtual src paths to the same entry in the VFS
214*67e74705SXin Li   // overlay, which is a way to emulate symlink inside the VFS; this is also
215*67e74705SXin Li   // needed for correctness, not doing that can lead to module redifinition
216*67e74705SXin Li   // errors.
217*67e74705SXin Li   addFileMapping(CanonicalPath, Dest);
218*67e74705SXin Li   return std::error_code();
219*67e74705SXin Li }
220*67e74705SXin Li 
addFile(StringRef Filename)221*67e74705SXin Li void ModuleDependencyCollector::addFile(StringRef Filename) {
222*67e74705SXin Li   if (insertSeen(Filename))
223*67e74705SXin Li     if (copyToRoot(Filename))
224*67e74705SXin Li       HasErrors = true;
225*67e74705SXin Li }
226