Skip to content

Commit d20efe3

Browse files
committed
[clang Dependency Scanning] Out-of-Date Scanning File System Cache Entry Reporting C-APIs (swiftlang#10927)
This PR implements the C-APIs to report a scanning file system cache's out-of-date entries. The C-APIs contains a function to return a set of file system cache out-of-date entries, functions to facilitate looping through all the entries, and reporting the relevant information from the entries. The APIs are based on llvm#144105. rdar://152247357 (cherry picked from commit 6fbcea6)
1 parent f53ab61 commit d20efe3

File tree

8 files changed

+382
-7
lines changed

8 files changed

+382
-7
lines changed

clang/include/clang-c/Dependencies.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,99 @@ CINDEX_LINKAGE CXString clang_experimental_DepGraphModuleLinkLibrary_getLibrary(
785785
CINDEX_LINKAGE bool clang_experimental_DepGraphModuleLinkLibrary_isFramework(
786786
CXDepGraphModuleLinkLibrary);
787787

788+
/**
789+
* The kind of scanning file system cache out-of-date entries.
790+
*/
791+
typedef enum {
792+
/**
793+
* The entry is negatively stat cached (which indicates the file did not exist
794+
* the first time it was looked up during scanning), but the cached file
795+
* exists on the underlying file system.
796+
*/
797+
NegativelyCached,
798+
799+
/**
800+
* The entry indicates that for the cached file, its cached size
801+
* is different from its size reported by the underlying file system.
802+
*/
803+
SizeChanged
804+
} CXDepScanFSCacheOutOfDateKind;
805+
806+
/**
807+
* The opaque object that contains the scanning file system cache's out-of-date
808+
* entires.
809+
*/
810+
typedef struct CXOpaqueDepScanFSOutOfDateEntrySet *CXDepScanFSOutOfDateEntrySet;
811+
812+
/**
813+
* The opaque object that represents a single scanning file system cache's out-
814+
* of-date entry.
815+
*/
816+
typedef struct CXOpaqueDepScanFSOutOfDateEntry *CXDepScanFSOutOfDateEntry;
817+
818+
/**
819+
* Returns all the file system cache out-of-date entries given a
820+
* \c CXDependencyScannerService .
821+
*
822+
* This function is intended to be called when the build has finished,
823+
* and the \c CXDependencyScannerService instance is about to be disposed.
824+
*
825+
* The \c CXDependencyScannerService instance owns the strings used
826+
* by the out-of-date entries and should be disposed after the
827+
* out-of-date entries are used and disposed.
828+
*/
829+
CXDepScanFSOutOfDateEntrySet
830+
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet(
831+
CXDependencyScannerService S);
832+
833+
/**
834+
* Returns the number of out-of-date entries contained in a
835+
* \c CXDepScanFSOutOfDateEntrySet .
836+
*/
837+
size_t clang_experimental_DepScanFSCacheOutOfDateEntrySet_getNumOfEntries(
838+
CXDepScanFSOutOfDateEntrySet Entries);
839+
840+
/**
841+
* Returns the out-of-date entry at offset \p Idx of the \c
842+
* CXDepScanFSOutOfDateEntrySet instance.
843+
*/
844+
CXDepScanFSOutOfDateEntry
845+
clang_experimental_DepScanFSCacheOutOfDateEntrySet_getEntry(
846+
CXDepScanFSOutOfDateEntrySet Entries, size_t Idx);
847+
848+
/**
849+
* Given an instance of \c CXDepScanFSOutOfDateEntry, returns its Kind.
850+
*/
851+
CXDepScanFSCacheOutOfDateKind
852+
clang_experimental_DepScanFSCacheOutOfDateEntry_getKind(
853+
CXDepScanFSOutOfDateEntry Entry);
854+
855+
/**
856+
* Given an instance of \c CXDepScanFSOutOfDateEntry, returns the path.
857+
*/
858+
CXString clang_experimental_DepScanFSCacheOutOfDateEntry_getPath(
859+
CXDepScanFSOutOfDateEntry Entry);
860+
861+
/**
862+
* Given an instance of \c CXDepScanFSOutOfDateEntry of kind SizeChanged,
863+
* returns the cached size.
864+
*/
865+
uint64_t clang_experimental_DepScanFSCacheOutOfDateEntry_getCachedSize(
866+
CXDepScanFSOutOfDateEntry Entry);
867+
868+
/**
869+
* Given an instance of \c CXDepScanFSOutOfDateEntry of kind SizeChanged,
870+
* returns the actual size on the underlying file system.
871+
*/
872+
uint64_t clang_experimental_DepScanFSCacheOutOfDateEntry_getActualSize(
873+
CXDepScanFSOutOfDateEntry Entry);
874+
875+
/**
876+
* Dispose the \c CXDepScanFSOutOfDateEntrySet instance.
877+
*/
878+
void clang_experimental_DepScanFSCacheOutOfDateEntrySet_disposeSet(
879+
CXDepScanFSOutOfDateEntrySet Entries);
880+
788881
/**
789882
* @}
790883
*/

clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,22 @@ DependencyScanningFilesystemSharedCache::getOutOfDateEntries(
134134
InvalidDiagInfo.emplace_back(Path.data());
135135
} else {
136136
llvm::vfs::Status CachedStatus = Entry->getStatus();
137-
uint64_t CachedSize = CachedStatus.getSize();
138-
uint64_t ActualSize = Status->getSize();
139-
if (CachedSize != ActualSize) {
140-
// This is the case where the cached file has a different size
141-
// from the actual file that comes from the underlying FS.
142-
InvalidDiagInfo.emplace_back(Path.data(), CachedSize, ActualSize);
137+
if (Status->getType() == llvm::sys::fs::file_type::regular_file &&
138+
Status->getType() == CachedStatus.getType()) {
139+
// We only check regular files. Directory files sizes could change
140+
// due to content changes, and reporting directory size changes can
141+
// lead to false positives.
142+
// TODO: At the moment, we do not detect symlinks to files whose
143+
// size may change. We need to decide if we want to detect cached
144+
// symlink size changes. We can also expand this to detect file
145+
// type changes.
146+
uint64_t CachedSize = CachedStatus.getSize();
147+
uint64_t ActualSize = Status->getSize();
148+
if (CachedSize != ActualSize) {
149+
// This is the case where the cached file has a different size
150+
// from the actual file that comes from the underlying FS.
151+
InvalidDiagInfo.emplace_back(Path.data(), CachedSize, ActualSize);
152+
}
143153
}
144154
}
145155
}

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 out of date file system cache entries: 0

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,20 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
916916
clang_disposeString(Spelling);
917917
clang_disposeDiagnostic(Diag);
918918
}
919+
920+
CXDepScanFSOutOfDateEntrySet OutOfDateEntrySet =
921+
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet(
922+
Service);
923+
924+
llvm::errs()
925+
<< "note: number of out of date file system cache entries: "
926+
<< clang_experimental_DepScanFSCacheOutOfDateEntrySet_getNumOfEntries(
927+
OutOfDateEntrySet)
928+
<< "\n";
929+
930+
clang_experimental_DepScanFSCacheOutOfDateEntrySet_disposeSet(
931+
OutOfDateEntrySet);
932+
919933
return 1;
920934
}
921935

clang/tools/libclang/CDependencies.cpp

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ struct DependencyScannerServiceOptions {
4545

4646
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerServiceOptions,
4747
CXDependencyScannerServiceOptions)
48-
4948
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningService,
5049
CXDependencyScannerService)
5150
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningWorker,
@@ -816,3 +815,96 @@ bool clang_experimental_DepGraphModuleLinkLibrary_isFramework(
816815
return Lib->IsFramework;
817816
}
818817

818+
819+
namespace {
820+
typedef std::vector<DependencyScanningFilesystemSharedCache::OutOfDateEntry>
821+
DependencyScannerFSOutOfDateEntrySet;
822+
823+
typedef DependencyScanningFilesystemSharedCache::OutOfDateEntry
824+
DependencyScannerFSOutOfDateEntry;
825+
} // namespace
826+
827+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerFSOutOfDateEntrySet,
828+
CXDepScanFSOutOfDateEntrySet)
829+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerFSOutOfDateEntry,
830+
CXDepScanFSOutOfDateEntry)
831+
832+
CXDepScanFSOutOfDateEntrySet
833+
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet(
834+
CXDependencyScannerService S) {
835+
DependencyScanningService &Service = *unwrap(S);
836+
837+
// FIXME: CAS FS currently does not use the shared cache, and cannot produce
838+
// the same diagnostics. We should add such a diagnostics to CAS as well.
839+
if (Service.useCASFS())
840+
return nullptr;
841+
842+
// Note that it is critical that this FS is the same as the default virtual
843+
// file system we pass to the DependencyScanningWorkers.
844+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
845+
llvm::vfs::createPhysicalFileSystem();
846+
847+
DependencyScannerFSOutOfDateEntrySet *OODEntrySet =
848+
new DependencyScannerFSOutOfDateEntrySet();
849+
*OODEntrySet = Service.getSharedCache().getOutOfDateEntries(*FS);
850+
851+
return wrap(OODEntrySet);
852+
}
853+
854+
size_t clang_experimental_DepScanFSCacheOutOfDateEntrySet_getNumOfEntries(
855+
CXDepScanFSOutOfDateEntrySet Entries) {
856+
return unwrap(Entries)->size();
857+
}
858+
859+
CXDepScanFSOutOfDateEntry
860+
clang_experimental_DepScanFSCacheOutOfDateEntrySet_getEntry(
861+
CXDepScanFSOutOfDateEntrySet Entries, size_t Idx) {
862+
DependencyScannerFSOutOfDateEntrySet *EntSet = unwrap(Entries);
863+
return wrap(&(*EntSet)[Idx]);
864+
}
865+
866+
CXDepScanFSCacheOutOfDateKind
867+
clang_experimental_DepScanFSCacheOutOfDateEntry_getKind(
868+
CXDepScanFSOutOfDateEntry Entry) {
869+
DependencyScannerFSOutOfDateEntry *E = unwrap(Entry);
870+
auto &Info = E->Info;
871+
return std::visit(
872+
llvm::makeVisitor(
873+
[](const DependencyScannerFSOutOfDateEntry::NegativelyCachedInfo
874+
&Info) { return NegativelyCached; },
875+
[](const DependencyScannerFSOutOfDateEntry::SizeChangedInfo &Info) {
876+
return SizeChanged;
877+
}),
878+
Info);
879+
}
880+
881+
CXString clang_experimental_DepScanFSCacheOutOfDateEntry_getPath(
882+
CXDepScanFSOutOfDateEntry Entry) {
883+
return cxstring::createRef(unwrap(Entry)->Path);
884+
}
885+
886+
static DependencyScannerFSOutOfDateEntry::SizeChangedInfo *
887+
getOutOfDateEntrySizeChangedInfo(DependencyScannerFSOutOfDateEntry *E) {
888+
auto *SizeInfo =
889+
std::get_if<DependencyScannerFSOutOfDateEntry::SizeChangedInfo>(&E->Info);
890+
assert(SizeInfo && "Wrong entry kind to get size changed info!");
891+
return SizeInfo;
892+
}
893+
894+
uint64_t clang_experimental_DepScanFSCacheOutOfDateEntry_getCachedSize(
895+
CXDepScanFSOutOfDateEntry Entry) {
896+
DependencyScannerFSOutOfDateEntry *E = unwrap(Entry);
897+
return getOutOfDateEntrySizeChangedInfo(E)->CachedSize;
898+
}
899+
900+
uint64_t clang_experimental_DepScanFSCacheOutOfDateEntry_getActualSize(
901+
CXDepScanFSOutOfDateEntry Entry) {
902+
DependencyScannerFSOutOfDateEntry *E = unwrap(Entry);
903+
return getOutOfDateEntrySizeChangedInfo(E)->ActualSize;
904+
}
905+
906+
void clang_experimental_DepScanFSCacheOutOfDateEntrySet_disposeSet(
907+
CXDepScanFSOutOfDateEntrySet Entries) {
908+
delete unwrap(Entries);
909+
}
910+

clang/tools/libclang/libclang.map

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,14 @@ LLVM_21 {
580580
clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary;
581581
clang_experimental_DepGraphModuleLinkLibrary_getLibrary;
582582
clang_experimental_DepGraphModuleLinkLibrary_isFramework;
583+
clang_experimental_DependencyScannerService_getFSCacheOutOfDateEntrySet;
584+
clang_experimental_DepScanFSCacheOutOfDateEntrySet_getNumOfEntries;
585+
clang_experimental_DepScanFSCacheOutOfDateEntrySet_getEntry;
586+
clang_experimental_DepScanFSCacheOutOfDateEntry_getKind;
587+
clang_experimental_DepScanFSCacheOutOfDateEntry_getPath;
588+
clang_experimental_DepScanFSCacheOutOfDateEntry_getCachedSize;
589+
clang_experimental_DepScanFSCacheOutOfDateEntry_getActualSize;
590+
clang_experimental_DepScanFSCacheOutOfDateEntrySet_disposeSet;
583591
};
584592

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

clang/unittests/libclang/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_clang_unittest(libclangTests
22
LibclangTest.cpp
33
DriverTest.cpp
4+
DependencyScanningCAPITests.cpp
45
)
56

67
target_link_libraries(libclangTests

0 commit comments

Comments
 (0)