Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Frontend/ModuleDependencyCollector.cpp
35232 views
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
FileManager &FileMgr;
30
public:
31
ModuleDependencyListener(ModuleDependencyCollector &Collector,
32
FileManager &FileMgr)
33
: Collector(Collector), FileMgr(FileMgr) {}
34
bool needsInputFileVisitation() override { return true; }
35
bool needsSystemInputFileVisitation() override { return true; }
36
bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
37
bool IsExplicitModule) override {
38
// Run this through the FileManager in order to respect 'use-external-name'
39
// in case we have a VFS overlay.
40
if (auto FE = FileMgr.getOptionalFileRef(Filename))
41
Filename = FE->getName();
42
Collector.addFile(Filename);
43
return true;
44
}
45
};
46
47
struct ModuleDependencyPPCallbacks : public PPCallbacks {
48
ModuleDependencyCollector &Collector;
49
SourceManager &SM;
50
ModuleDependencyPPCallbacks(ModuleDependencyCollector &Collector,
51
SourceManager &SM)
52
: Collector(Collector), SM(SM) {}
53
54
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
55
StringRef FileName, bool IsAngled,
56
CharSourceRange FilenameRange,
57
OptionalFileEntryRef File, StringRef SearchPath,
58
StringRef RelativePath, const Module *SuggestedModule,
59
bool ModuleImported,
60
SrcMgr::CharacteristicKind FileType) override {
61
if (!File)
62
return;
63
Collector.addFile(File->getName());
64
}
65
};
66
67
struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
68
ModuleDependencyCollector &Collector;
69
ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector)
70
: Collector(Collector) {}
71
72
void moduleMapAddHeader(StringRef HeaderPath) override {
73
if (llvm::sys::path::is_absolute(HeaderPath))
74
Collector.addFile(HeaderPath);
75
}
76
void moduleMapAddUmbrellaHeader(FileEntryRef Header) override {
77
moduleMapAddHeader(Header.getNameAsRequested());
78
}
79
};
80
81
} // namespace
82
83
void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
84
R.addListener(
85
std::make_unique<ModuleDependencyListener>(*this, R.getFileManager()));
86
}
87
88
void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {
89
PP.addPPCallbacks(std::make_unique<ModuleDependencyPPCallbacks>(
90
*this, PP.getSourceManager()));
91
PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
92
std::make_unique<ModuleDependencyMMCallbacks>(*this));
93
}
94
95
static bool isCaseSensitivePath(StringRef Path) {
96
SmallString<256> TmpDest = Path, UpperDest, RealDest;
97
// Remove component traversals, links, etc.
98
if (llvm::sys::fs::real_path(Path, TmpDest))
99
return true; // Current default value in vfs.yaml
100
Path = TmpDest;
101
102
// Change path to all upper case and ask for its real path, if the latter
103
// exists and is equal to Path, it's not case sensitive. Default to case
104
// sensitive in the absence of realpath, since this is what the VFSWriter
105
// already expects when sensitivity isn't setup.
106
for (auto &C : Path)
107
UpperDest.push_back(toUppercase(C));
108
if (!llvm::sys::fs::real_path(UpperDest, RealDest) && Path == RealDest)
109
return false;
110
return true;
111
}
112
113
void ModuleDependencyCollector::writeFileMap() {
114
if (Seen.empty())
115
return;
116
117
StringRef VFSDir = getDest();
118
119
// Default to use relative overlay directories in the VFS yaml file. This
120
// allows crash reproducer scripts to work across machines.
121
VFSWriter.setOverlayDir(VFSDir);
122
123
// Explicitly set case sensitivity for the YAML writer. For that, find out
124
// the sensitivity at the path where the headers all collected to.
125
VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir));
126
127
// Do not rely on real path names when executing the crash reproducer scripts
128
// since we only want to actually use the files we have on the VFS cache.
129
VFSWriter.setUseExternalNames(false);
130
131
std::error_code EC;
132
SmallString<256> YAMLPath = VFSDir;
133
llvm::sys::path::append(YAMLPath, "vfs.yaml");
134
llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::OF_TextWithCRLF);
135
if (EC) {
136
HasErrors = true;
137
return;
138
}
139
VFSWriter.write(OS);
140
}
141
142
std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,
143
StringRef Dst) {
144
using namespace llvm::sys;
145
llvm::FileCollector::PathCanonicalizer::PathStorage Paths =
146
Canonicalizer.canonicalize(Src);
147
148
SmallString<256> CacheDst = getDest();
149
150
if (Dst.empty()) {
151
// The common case is to map the virtual path to the same path inside the
152
// cache.
153
path::append(CacheDst, path::relative_path(Paths.CopyFrom));
154
} else {
155
// When collecting entries from input vfsoverlays, copy the external
156
// contents into the cache but still map from the source.
157
if (!fs::exists(Dst))
158
return std::error_code();
159
path::append(CacheDst, Dst);
160
Paths.CopyFrom = Dst;
161
}
162
163
// Copy the file into place.
164
if (std::error_code EC = fs::create_directories(path::parent_path(CacheDst),
165
/*IgnoreExisting=*/true))
166
return EC;
167
if (std::error_code EC = fs::copy_file(Paths.CopyFrom, CacheDst))
168
return EC;
169
170
// Always map a canonical src path to its real path into the YAML, by doing
171
// this we map different virtual src paths to the same entry in the VFS
172
// overlay, which is a way to emulate symlink inside the VFS; this is also
173
// needed for correctness, not doing that can lead to module redefinition
174
// errors.
175
addFileMapping(Paths.VirtualPath, CacheDst);
176
return std::error_code();
177
}
178
179
void ModuleDependencyCollector::addFile(StringRef Filename, StringRef FileDst) {
180
if (insertSeen(Filename))
181
if (copyToRoot(Filename, FileDst))
182
HasErrors = true;
183
}
184
185