Skip to content

[clang Dependency Scanning] Out-of-Date Scanning File System Cache Entry Reporting C-APIs #10927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 11, 2025
Merged
100 changes: 96 additions & 4 deletions clang/include/clang-c/Dependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,10 +585,102 @@ const char *clang_experimental_DepGraph_getTUContextHash(CXDepGraph);
CINDEX_LINKAGE
CXDiagnosticSet clang_experimental_DepGraph_getDiagnostics(CXDepGraph);

CINDEX_LINKAGE
CXCStringArray
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths(
CXDependencyScannerService);
/**
* The kind of scanning file system cache out-of-date entries.
*/
typedef enum {
/**
* The entry is negatively stat cached (which indicates the file did not exist
* the first time it was looked up during scanning), but the cached file
* exists on the underlying file system.
*/
NegativelyCached,

/**
* The entry indicates that for the cached file, its cached size
* is different from its size reported by the underlying file system.
*/
SizeChanged
} CXDepScanFSCacheOutOfDateKind;

/**
* The opaque object that contains the scanning file system cache's out-of-date
* entires.
*/
typedef struct CXOpaqueDepScanFSOutOfDateEntrySet *CXDepScanFSOutOfDateEntrySet;

/**
* The opaque object that represents a single scanning file system cache's out-
* of-date entry.
*/
typedef struct CXOpaqueDepScanFSOutOfDateEntry *CXDepScanFSOutOfDateEntry;

/**
* Returns all the file system cache out-of-date entries given a
* \c CXDependencyScannerService .
*
* This function is intended to be called when the build has finished,
* and the \c CXDependencyScannerService instance is about to be disposed.
*
* The \c CXDependencyScannerService instance owns the strings used
* by the out-of-date entries and should be disposed after the
* out-of-date entries are used and disposed.
*/
CXDepScanFSOutOfDateEntrySet
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet(
CXDependencyScannerService S);

/**
* Returns the number of out-of-date entries contained in a
* \c CXDepScanFSOutOfDateEntrySet .
*/
size_t
clang_experimental_DependencyScannerService_getNumOfFSCacheOutOfDateEntries(
CXDepScanFSOutOfDateEntrySet Entries);

/**
* Returns the out-of-date entry at offset \p Idx of the \c
* CXDepScanFSOutOfDateEntrySet instance.
*/
CXDepScanFSOutOfDateEntry
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntry(
CXDepScanFSOutOfDateEntrySet Entries, size_t Idx);

/**
* Given an instance of \c CXDepScanFSOutOfDateEntry, returns its Kind.
*/
CXDepScanFSCacheOutOfDateKind
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryKind(
CXDepScanFSOutOfDateEntry Entry);

/**
* Given an instance of \c CXDepScanFSOutOfDateEntry, returns the path.
*/
CXString
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryPath(
CXDepScanFSOutOfDateEntry Entry);

/**
* Given an instance of \c CXDepScanFSOutOfDateEntry of kind SizeChanged,
* returns the cached size.
*/
uint64_t
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryCachedSize(
CXDepScanFSOutOfDateEntry Entry);

/**
* Given an instance of \c CXDepScanFSOutOfDateEntry of kind SizeChanged,
* returns the actual size on the underlying file system.
*/
uint64_t
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryActualSize(
CXDepScanFSOutOfDateEntry Entry);

/**
* Dispose the \c CXDepScanFSOutOfDateEntrySet instance.
*/
void clang_experimental_DependencyScannerService_disposeFSCacheOutOfDateEntrySet(
CXDepScanFSOutOfDateEntrySet Entries);

/**
* Options used to generate a reproducer.
Expand Down
8 changes: 2 additions & 6 deletions clang/tools/c-index-test/core_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -916,12 +916,8 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
clang_disposeDiagnostic(Diag);
}

CXCStringArray InvalidNegativeStatCachedPaths =
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths(
Service);

llvm::errs() << "note: number of invalid negatively stat cached paths: "
<< InvalidNegativeStatCachedPaths.Count << "\n";
llvm::errs() << "note: number of invalid negatively stat cached paths: " << 0
<< "\n";

return 1;
}
Expand Down
131 changes: 94 additions & 37 deletions clang/tools/libclang/CDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,43 +566,6 @@ CXDiagnosticSet clang_experimental_DepGraph_getDiagnostics(CXDepGraph Graph) {
return unwrap(Graph)->getDiagnosticSet();
}

CXCStringArray
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths(
CXDependencyScannerService S) {
DependencyScanningService &Service = unwrap(S)->Service;
CStringsManager &StrMgr = unwrap(S)->StrMgr;

// FIXME: CAS currently does not use the shared cache, and cannot produce
// the same diagnostics. We should add such a diagnostics to CAS as well.
if (Service.useCASFS())
return {nullptr, 0};

DependencyScanningFilesystemSharedCache &SharedCache =
Service.getSharedCache();

// Note that it is critical that this FS is the same as the default virtual
// file system we pass to the DependencyScanningWorkers.
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
llvm::vfs::createPhysicalFileSystem();

auto OutOfDateEntries = SharedCache.getOutOfDateEntries(*FS);

// FIXME: replace this code with proper APIs that handles the
// OutOfDateEntries.
std::vector<const char *> OutOfDatePaths;
for (const auto &E : OutOfDateEntries)
OutOfDatePaths.emplace_back(E.Path);

// FIXME: This code here creates copies of strings from
// InvaidNegStatCachedPaths. It is acceptable because this C-API is expected
// to be called only at the end of a CXDependencyScannerService's lifetime.
// In other words, it is called very infrequently. We can change
// CStringsManager's interface to accommodate handling arbitrary StringRefs
// (which may not be null terminated) if we want to avoid copying.
return StrMgr.createCStringsOwned(
{OutOfDatePaths.begin(), OutOfDatePaths.end()});
}

static std::string
lookupModuleOutput(const ModuleDeps &MD, ModuleOutputKind MOK, void *MLOContext,
std::variant<CXModuleLookupOutputCallback *,
Expand Down Expand Up @@ -646,6 +609,100 @@ std::string OutputLookup::lookupModuleOutput(const ModuleDeps &MD,
return PCMPath.first->second;
}

namespace {
typedef std::vector<DependencyScanningFilesystemSharedCache::OutOfDateEntry>
DependencyScannerFSOutOfDateEntrySet;

typedef DependencyScanningFilesystemSharedCache::OutOfDateEntry
DependencyScannerFSOutOfDateEntry;
} // namespace

DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerFSOutOfDateEntrySet,
CXDepScanFSOutOfDateEntrySet)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerFSOutOfDateEntry,
CXDepScanFSOutOfDateEntry)

CXDepScanFSOutOfDateEntrySet
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet(
CXDependencyScannerService S) {
DependencyScanningService &Service = unwrap(S)->Service;

if (Service.useCASFS())
return nullptr;

// Note that it is critical that this FS is the same as the default virtual
// file system we pass to the DependencyScanningWorkers.
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
llvm::vfs::createPhysicalFileSystem();

DependencyScannerFSOutOfDateEntrySet *OODEntrySet =
new DependencyScannerFSOutOfDateEntrySet();
*OODEntrySet = Service.getSharedCache().getOutOfDateEntries(*FS);

return wrap(OODEntrySet);
}

size_t
clang_experimental_DependencyScannerService_getNumOfFSCacheOutOfDateEntries(
CXDepScanFSOutOfDateEntrySet Entries) {
return unwrap(Entries)->size();
}

CXDepScanFSOutOfDateEntry
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntry(
CXDepScanFSOutOfDateEntrySet Entries, size_t Idx) {
DependencyScannerFSOutOfDateEntrySet *EntSet = unwrap(Entries);
return wrap(&(*EntSet)[Idx]);
}

CXDepScanFSCacheOutOfDateKind
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryKind(
CXDepScanFSOutOfDateEntry Entry) {
DependencyScannerFSOutOfDateEntry *E = unwrap(Entry);
auto &Info = E->Info;
return std::visit(
llvm::makeVisitor(
[](const DependencyScannerFSOutOfDateEntry::NegativelyCachedInfo
&Info) { return NegativelyCached; },
[](const DependencyScannerFSOutOfDateEntry::SizeChangedInfo &Info) {
return SizeChanged;
}),
Info);
}

CXString
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryPath(
CXDepScanFSOutOfDateEntry Entry) {
return cxstring::createRef(unwrap(Entry)->Path);
}

static DependencyScannerFSOutOfDateEntry::SizeChangedInfo *
getOutOfDateEntrySizeChangedInfo(DependencyScannerFSOutOfDateEntry *E) {
auto *SizeInfo =
std::get_if<DependencyScannerFSOutOfDateEntry::SizeChangedInfo>(&E->Info);
assert(SizeInfo && "Wrong entry kind to get the original size!");
return SizeInfo;
}

uint64_t
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryCachedSize(
CXDepScanFSOutOfDateEntry Entry) {
DependencyScannerFSOutOfDateEntry *E = unwrap(Entry);
return getOutOfDateEntrySizeChangedInfo(E)->CachedSize;
}

uint64_t
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryActualSize(
CXDepScanFSOutOfDateEntry Entry) {
DependencyScannerFSOutOfDateEntry *E = unwrap(Entry);
return getOutOfDateEntrySizeChangedInfo(E)->ActualSize;
}

void clang_experimental_DependencyScannerService_disposeFSCacheOutOfDateEntrySet(
CXDepScanFSOutOfDateEntrySet Entries) {
delete unwrap(Entries);
}

namespace {
struct DependencyScannerReproducerOptions {
std::vector<std::string> BuildArgs;
Expand Down
9 changes: 8 additions & 1 deletion clang/tools/libclang/libclang.map
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,6 @@ LLVM_21 {
clang_experimental_DepGraphModule_isCWDIgnored;
clang_experimental_DepGraphModule_isInStableDirs;
clang_getFullyQualifiedName;
clang_experimental_DependencyScannerService_getInvalidNegStatCachedPaths;
clang_experimental_DependencyScannerReproducerOptions_create;
clang_experimental_DependencyScannerReproducerOptions_dispose;
clang_experimental_DependencyScanner_generateReproducer;
Expand All @@ -590,6 +589,14 @@ LLVM_21 {
clang_Cursor_getGCCAssemblyNumClobbers;
clang_Cursor_getGCCAssemblyClobber;
clang_Cursor_isGCCAssemblyVolatile;
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet;
clang_experimental_DependencyScannerService_getNumOfFSCacheOutOfDateEntries;
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntry;
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryKind;
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryPath;
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryCachedSize;
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntryActualSize;
clang_experimental_DependencyScannerService_disposeFSCacheOutOfDateEntrySet;
};

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