21 #include "clang/Basic/LangOptions.h"
22 #include "clang/Frontend/CompilerInvocation.h"
23 #include "clang/Lex/PreprocessorOptions.h"
24 #include "llvm/ADT/IntrusiveRefCntPtr.h"
25 #include "llvm/ADT/None.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/Path.h"
36 Lang langFromOpts(
const LangOptions &LO) {
return LO.CPlusPlus ? CXX :
C; }
37 llvm::StringLiteral mandatoryHeader(Lang L) {
44 llvm_unreachable(
"unhandled Lang");
50 return LangStandard::lang_cxx2b;
52 return LangStandard::lang_cxx20;
54 return LangStandard::lang_cxx17;
56 return LangStandard::lang_cxx14;
58 return LangStandard::lang_cxx11;
59 return LangStandard::lang_cxx98;
62 return LangStandard::lang_c2x;
65 return LangStandard::lang_c17;
66 return LangStandard::lang_c99;
69 std::string buildUmbrella(llvm::StringLiteral Mandatory,
70 std::vector<llvm::StringLiteral> Headers) {
72 llvm::raw_string_ostream
OS(Result);
78 "#if !__has_include(<{0}>)\n"
79 "#error Mandatory header <{0}> not found in standard library!\n"
83 llvm::sort(Headers.begin(), Headers.end());
84 auto Last = std::unique(Headers.begin(), Headers.end());
85 for (
auto Header = Headers.begin(); Header != Last; ++Header) {
86 OS << llvm::formatv(
"#if __has_include({0})\n"
102 Lang L = langFromOpts(LO);
105 static std::string *UmbrellaCXX =
106 new std::string(buildUmbrella(mandatoryHeader(L), {
107 #define SYMBOL(Name, NameSpace, Header) #Header,
108 #include "clang/Tooling/Inclusions/StdSymbolMap.inc"
113 static std::string *UmbrellaC =
114 new std::string(buildUmbrella(mandatoryHeader(L), {
115 #define SYMBOL(Name, NameSpace, Header) #Header,
116 #include "clang/Tooling/Inclusions/CSymbolMap.inc"
121 llvm_unreachable(
"invalid Lang in langFromOpts");
139 SymbolSlab filter(SymbolSlab Slab,
const StdLibLocation &
Loc) {
142 static auto &StandardHeaders = *[] {
143 auto *Set =
new llvm::DenseSet<llvm::StringRef>();
144 for (llvm::StringRef Header : {
145 #define SYMBOL(Name, NameSpace, Header) #Header,
146 #include "clang/Tooling/Inclusions/CSymbolMap.inc"
147 #include "clang/Tooling/Inclusions/StdSymbolMap.inc"
156 llvm::SmallVector<std::string> StdLibURIPrefixes;
157 for (
const auto &
Path :
Loc.Paths) {
159 if (StdLibURIPrefixes.back().back() !=
'/')
160 StdLibURIPrefixes.back().push_back(
'/');
165 llvm::DenseMap<const char *, bool> GoodHeader;
166 for (
const Symbol &S : Slab) {
167 if (!S.IncludeHeaders.empty() &&
168 StandardHeaders.contains(S.IncludeHeaders.front().IncludeHeader)) {
169 GoodHeader[S.CanonicalDeclaration.FileURI] =
true;
170 GoodHeader[S.Definition.FileURI] =
true;
173 for (
const char *URI :
174 {S.CanonicalDeclaration.FileURI, S.Definition.FileURI}) {
175 auto R = GoodHeader.try_emplace(URI,
false);
177 R.first->second = llvm::any_of(
179 [&, URIStr(llvm::StringRef(URI))](
const std::string &Prefix) {
180 return URIStr.startswith(Prefix);
186 for (
const auto &Good : GoodHeader)
187 if (Good.second && *Good.first)
188 dlog(
"Stdlib header: {0}", Good.first);
191 auto IsGoodHeader = [&](
const char *
C) {
return *
C && GoodHeader.lookup(
C); };
193 for (
const Symbol &S : Slab) {
194 if (!(IsGoodHeader(S.CanonicalDeclaration.FileURI) ||
195 IsGoodHeader(S.Definition.FileURI))) {
196 dlog(
"Ignoring wrong-header symbol {0}{1} in {2}", S.Scope, S.Name,
197 S.CanonicalDeclaration.FileURI);
203 return std::move(Result).build();
209 std::unique_ptr<CompilerInvocation>
CI,
212 if (
CI->getFrontendOpts().Inputs.size() != 1 ||
213 !
CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
214 elog(
"Indexing standard library failed: bad CompilerInvocation");
215 assert(
false &&
"indexing stdlib with a dubious CompilerInvocation!");
218 const FrontendInputFile &Input =
CI->getFrontendOpts().Inputs.front();
221 log(
"Indexing {0} standard library in the context of {1}",
222 LangStandard::getLangStandardForKind(LangStd).
getName(), Input.getFile());
227 CI->getPreprocessorOpts().clearRemappedFiles();
229 std::move(
CI),
nullptr,
230 llvm::MemoryBuffer::getMemBuffer(HeaderSources, Input.getFile()),
233 elog(
"Standard Library Index: Couldn't build compiler instance");
250 IndexOpts, [&](
SymbolSlab S) { Symbols = std::move(S); },
nullptr,
254 elog(
"Standard Library Index: BeginSourceFile() failed");
258 if (llvm::Error Err =
Action->Execute()) {
259 elog(
"Standard Library Index: Execute failed: {0}", std::move(Err));
265 unsigned SymbolsBeforeFilter = Symbols.size();
266 Symbols = filter(std::move(Symbols),
Loc);
267 bool Errors =
Clang->hasDiagnostics() &&
268 Clang->getDiagnostics().hasUncompilableErrorOccurred();
269 log(
"Indexed {0} standard library{3}: {1} symbols, {2} filtered",
270 LangStandard::getLangStandardForKind(LangStd).
getName(), Symbols.size(),
271 SymbolsBeforeFilter - Symbols.size(),
272 Errors ?
" (incomplete due to errors)" :
"");
285 return standardFromOpts(LO) >=
286 Best[langFromOpts(LO)].load(std::memory_order_acquire);
290 const HeaderSearch &HS) {
291 Lang L = langFromOpts(LO);
292 int OldVersion = Best[L].load(std::memory_order_acquire);
293 int NewVersion = standardFromOpts(LO);
294 dlog(
"Index stdlib? {0}",
295 LangStandard::getLangStandardForKind(standardFromOpts(LO)).
getName());
298 dlog(
"No: disabled in config");
302 if (NewVersion <= OldVersion) {
303 dlog(
"No: have {0}, {1}>={2}",
304 LangStandard::getLangStandardForKind(
307 OldVersion, NewVersion);
315 llvm::StringLiteral ProbeHeader = mandatoryHeader(L);
316 llvm::SmallString<256>
Path;
317 llvm::SmallVector<std::string> SearchPaths;
318 auto RecordHeaderPath = [&](llvm::StringRef HeaderPath) {
319 llvm::StringRef DirPath = llvm::sys::path::parent_path(HeaderPath);
320 if (!HS.getFileMgr().getVirtualFileSystem().getRealPath(DirPath,
Path))
321 SearchPaths.emplace_back(
Path);
323 for (
const auto &DL :
324 llvm::make_range(HS.search_dir_begin(), HS.search_dir_end())) {
325 switch (DL.getLookupType()) {
326 case DirectoryLookup::LT_NormalDir: {
327 Path = DL.getDir()->getName();
328 llvm::sys::path::append(
Path, ProbeHeader);
329 llvm::vfs::Status Stat;
330 if (!HS.getFileMgr().getNoncachedStatValue(
Path, Stat) &&
331 Stat.isRegularFile())
332 RecordHeaderPath(
Path);
335 case DirectoryLookup::LT_Framework:
338 case DirectoryLookup::LT_HeaderMap:
340 DL.getHeaderMap()->lookupFilename(ProbeHeader,
Path);
346 if (SearchPaths.empty())
349 dlog(
"Found standard library in {0}",
llvm::join(SearchPaths,
", "));
351 while (!Best[L].compare_exchange_weak(OldVersion, NewVersion,
352 std::memory_order_acq_rel))
353 if (OldVersion >= NewVersion) {
354 dlog(
"No: lost the race");
358 dlog(
"Yes, index stdlib!");