Skip to content

Commit da26ac3

Browse files
committed
[clang][Modules] Adding C-API for Negative Stat Caching Diagnostics (llvm#10524)
llvm#135703 added a C++ API to the shared cached to diagnose invalid negatively stat cached paths. This PR adds a C API so an external system can take advantage of the diagnostics. rdar://149147920 (cherry picked from commit b7aa45c)
1 parent 5c9c278 commit da26ac3

File tree

6 files changed

+106
-54
lines changed

6 files changed

+106
-54
lines changed

clang/include/clang-c/Dependencies.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ const char *clang_experimental_DepGraph_getTUContextHash(CXDepGraph);
735735
CINDEX_LINKAGE
736736
CXDiagnosticSet clang_experimental_DepGraph_getDiagnostics(CXDepGraph);
737737

738+
CINDEX_LINKAGE
739+
CXCStringArray
740+
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths(
741+
CXDependencyScannerService);
742+
738743
/**
739744
* @}
740745
*/

clang/test/ClangScanDeps/error-c-api.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
// CHECK: error: failed to get dependencies
66
// CHECK-NEXT: 'missing.h' file not found
7+
// CHECK-NEXT: number of invalid negatively stat cached paths: 0

clang/tools/c-index-test/core_main.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,14 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
894894
clang_disposeString(Spelling);
895895
clang_disposeDiagnostic(Diag);
896896
}
897+
898+
CXCStringArray InvalidNegativeStatCachedPaths =
899+
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths(
900+
Service);
901+
902+
llvm::errs() << "note: number of invalid negatively stat cached paths: "
903+
<< InvalidNegativeStatCachedPaths.Count << "\n";
904+
897905
return 1;
898906
}
899907

clang/tools/libclang/CDependencies.cpp

Lines changed: 86 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,57 @@ struct DependencyScannerServiceOptions {
4141

4242
ScanningOutputFormat getFormat() const;
4343
};
44+
45+
struct CStringsManager {
46+
SmallVector<std::unique_ptr<std::vector<const char *>>> OwnedCStr;
47+
SmallVector<std::unique_ptr<std::vector<std::string>>> OwnedStdStr;
48+
49+
/// Doesn't own the string contents.
50+
CXCStringArray createCStringsRef(ArrayRef<std::string> Strings) {
51+
OwnedCStr.push_back(std::make_unique<std::vector<const char *>>());
52+
std::vector<const char *> &CStrings = *OwnedCStr.back();
53+
CStrings.reserve(Strings.size());
54+
for (const auto &String : Strings)
55+
CStrings.push_back(String.c_str());
56+
return {CStrings.data(), CStrings.size()};
57+
}
58+
59+
/// Doesn't own the string contents.
60+
CXCStringArray createCStringsRef(const llvm::StringSet<> &StringsUnordered) {
61+
std::vector<StringRef> Strings;
62+
63+
for (auto SI = StringsUnordered.begin(), SE = StringsUnordered.end();
64+
SI != SE; ++SI)
65+
Strings.push_back(SI->getKey());
66+
67+
llvm::sort(Strings);
68+
69+
OwnedCStr.push_back(std::make_unique<std::vector<const char *>>());
70+
std::vector<const char *> &CStrings = *OwnedCStr.back();
71+
CStrings.reserve(Strings.size());
72+
for (const auto &String : Strings)
73+
CStrings.push_back(String.data());
74+
return {CStrings.data(), CStrings.size()};
75+
}
76+
77+
/// Gets ownership of string contents.
78+
CXCStringArray createCStringsOwned(std::vector<std::string> &&Strings) {
79+
OwnedStdStr.push_back(
80+
std::make_unique<std::vector<std::string>>(std::move(Strings)));
81+
return createCStringsRef(*OwnedStdStr.back());
82+
}
83+
};
84+
85+
struct DependencyScannerService {
86+
DependencyScanningService Service;
87+
CStringsManager StrMgr{};
88+
};
4489
} // end anonymous namespace
4590

4691
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerServiceOptions,
4792
CXDependencyScannerServiceOptions)
4893

49-
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningService,
94+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerService,
5095
CXDependencyScannerService)
5196
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningWorker,
5297
CXDependencyScannerWorker)
@@ -142,9 +187,9 @@ clang_experimental_DependencyScannerService_create_v0(CXDependencyMode Format) {
142187
// FIXME: Pass default CASOpts and nullptr as CachingOnDiskFileSystem now.
143188
CASOptions CASOpts;
144189
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> FS;
145-
return wrap(new DependencyScanningService(
190+
return wrap(new DependencyScannerService{DependencyScanningService(
146191
ScanningMode::DependencyDirectivesScan, unwrap(Format), CASOpts,
147-
/*CAS=*/nullptr, /*ActionCache=*/nullptr, FS));
192+
/*CAS=*/nullptr, /*ActionCache=*/nullptr, FS)});
148193
}
149194

150195
ScanningOutputFormat DependencyScannerServiceOptions::getFormat() const {
@@ -180,10 +225,10 @@ clang_experimental_DependencyScannerService_create_v1(
180225
FS = llvm::cantFail(
181226
llvm::cas::createCachingOnDiskFileSystem(CAS));
182227
}
183-
return wrap(new DependencyScanningService(
228+
return wrap(new DependencyScannerService{DependencyScanningService(
184229
ScanningMode::DependencyDirectivesScan, Format, unwrap(Opts)->CASOpts,
185230
std::move(CAS), std::move(Cache), std::move(FS),
186-
unwrap(Opts)->OptimizeArgs));
231+
unwrap(Opts)->OptimizeArgs)});
187232
}
188233

189234
void clang_experimental_DependencyScannerService_dispose_v0(
@@ -213,17 +258,17 @@ void clang_experimental_FileDependenciesList_dispose(
213258
}
214259

215260
CXDependencyScannerWorker clang_experimental_DependencyScannerWorker_create_v0(
216-
CXDependencyScannerService Service) {
217-
ScanningOutputFormat Format = unwrap(Service)->getFormat();
261+
CXDependencyScannerService S) {
262+
ScanningOutputFormat Format = unwrap(S)->Service.getFormat();
218263
bool IsIncludeTreeOutput = Format == ScanningOutputFormat::IncludeTree ||
219264
Format == ScanningOutputFormat::FullIncludeTree;
220265
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
221266
llvm::vfs::createPhysicalFileSystem();
222267
if (IsIncludeTreeOutput)
223-
FS = llvm::cas::createCASProvidingFileSystem(unwrap(Service)->getCAS(),
268+
FS = llvm::cas::createCASProvidingFileSystem(unwrap(S)->Service.getCAS(),
224269
std::move(FS));
225270

226-
return wrap(new DependencyScanningWorker(*unwrap(Service), FS));
271+
return wrap(new DependencyScanningWorker(unwrap(S)->Service, FS));
227272
}
228273

229274
void clang_experimental_DependencyScannerWorker_dispose_v0(
@@ -432,46 +477,6 @@ struct DependencyScannerWorkerScanSettings {
432477
MLO;
433478
};
434479

435-
struct CStringsManager {
436-
SmallVector<std::unique_ptr<std::vector<const char *>>> OwnedCStr;
437-
SmallVector<std::unique_ptr<std::vector<std::string>>> OwnedStdStr;
438-
439-
/// Doesn't own the string contents.
440-
CXCStringArray createCStringsRef(ArrayRef<std::string> Strings) {
441-
OwnedCStr.push_back(std::make_unique<std::vector<const char *>>());
442-
std::vector<const char *> &CStrings = *OwnedCStr.back();
443-
CStrings.reserve(Strings.size());
444-
for (const auto &String : Strings)
445-
CStrings.push_back(String.c_str());
446-
return {CStrings.data(), CStrings.size()};
447-
}
448-
449-
/// Doesn't own the string contents.
450-
CXCStringArray createCStringsRef(const llvm::StringSet<> &StringsUnordered) {
451-
std::vector<StringRef> Strings;
452-
453-
for (auto SI = StringsUnordered.begin(), SE = StringsUnordered.end();
454-
SI != SE; ++SI)
455-
Strings.push_back(SI->getKey());
456-
457-
llvm::sort(Strings);
458-
459-
OwnedCStr.push_back(std::make_unique<std::vector<const char *>>());
460-
std::vector<const char *> &CStrings = *OwnedCStr.back();
461-
CStrings.reserve(Strings.size());
462-
for (const auto &String : Strings)
463-
CStrings.push_back(String.data());
464-
return {CStrings.data(), CStrings.size()};
465-
}
466-
467-
/// Gets ownership of string contents.
468-
CXCStringArray createCStringsOwned(std::vector<std::string> &&Strings) {
469-
OwnedStdStr.push_back(
470-
std::make_unique<std::vector<std::string>>(std::move(Strings)));
471-
return createCStringsRef(*OwnedStdStr.back());
472-
}
473-
};
474-
475480
struct DependencyGraph {
476481
TranslationUnitDeps TUDeps;
477482
SmallString<256> SerialDiagBuf;
@@ -731,6 +736,38 @@ CXDiagnosticSet clang_experimental_DepGraph_getDiagnostics(CXDepGraph Graph) {
731736
return unwrap(Graph)->getDiagnosticSet();
732737
}
733738

739+
CXCStringArray
740+
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths(
741+
CXDependencyScannerService S) {
742+
DependencyScanningService &Service = unwrap(S)->Service;
743+
CStringsManager &StrMgr = unwrap(S)->StrMgr;
744+
745+
// FIXME: CAS currently does not use the shared cache, and cannot produce
746+
// the same diagnostics. We should add such a diagnostics to CAS as well.
747+
if (Service.useCASFS())
748+
return {nullptr, 0};
749+
750+
DependencyScanningFilesystemSharedCache &SharedCache =
751+
Service.getSharedCache();
752+
753+
// Note that it is critical that this FS is the same as the default virtual
754+
// file system we pass to the DependencyScanningWorkers.
755+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
756+
llvm::vfs::createPhysicalFileSystem();
757+
758+
auto InvaidNegStatCachedPaths =
759+
SharedCache.getInvalidNegativeStatCachedPaths(*FS);
760+
761+
// FIXME: This code here creates copies of strings from
762+
// InvaidNegStatCachedPaths. It is acceptable because this C-API is expected
763+
// to be called only at the end of a CXDependencyScannerService's lifetime.
764+
// In other words, it is called very infrequently. We can change
765+
// CStringsManager's interface to accommodate handling arbitrary StringRefs
766+
// (which may not be null terminated) if we want to avoid copying.
767+
return StrMgr.createCStringsOwned(
768+
{InvaidNegStatCachedPaths.begin(), InvaidNegStatCachedPaths.end()});
769+
}
770+
734771
static std::string
735772
lookupModuleOutput(const ModuleDeps &MD, ModuleOutputKind MOK, void *MLOContext,
736773
std::variant<CXModuleLookupOutputCallback *,

clang/tools/libclang/CXString.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,13 @@ CXStringSet *createSet(const std::vector<std::string> &Strings) {
130130

131131
CXStringSet *createSet(const llvm::StringSet<> &StringsUnordered) {
132132
std::vector<StringRef> Strings;
133-
134-
for (auto SI = StringsUnordered.begin(),
135-
SE = StringsUnordered.end(); SI != SE; ++SI)
133+
134+
for (auto SI = StringsUnordered.begin(), SE = StringsUnordered.end();
135+
SI != SE; ++SI)
136136
Strings.push_back(SI->getKey());
137-
137+
138138
llvm::sort(Strings);
139-
139+
140140
CXStringSet *Set = new CXStringSet;
141141
Set->Count = Strings.size();
142142
Set->Strings = new CXString[Set->Count];

clang/tools/libclang/libclang.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ LLVM_21 {
575575
clang_experimental_DependencyScannerServiceOptions_setCWDOptimization;
576576
clang_experimental_DepGraphModule_isCWDIgnored;
577577
clang_experimental_DepGraphModule_isInStableDirs;
578+
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths;
578579
};
579580

580581
# Example of how to add a new symbol version entry. If you do add a new symbol

0 commit comments

Comments
 (0)