@@ -246,24 +246,49 @@ IncludeTree::FileList::getFileSize(size_t I) const {
246
246
Data.data () + I * sizeof (FileSizeTy));
247
247
}
248
248
249
+ static llvm::Error diagnoseFileChange (IncludeTree::File F, ObjectRef Content) {
250
+ auto FilenameBlob = F.getFilename ();
251
+ if (!FilenameBlob)
252
+ return FilenameBlob.takeError ();
253
+ cas::ObjectStore &DB = F.getCAS ();
254
+ std::string Filename (FilenameBlob->getData ());
255
+ std::string OldID = DB.getID (Content).toString ();
256
+ std::string NewID = DB.getID (F.getContentsRef ()).toString ();
257
+ return llvm::createStringError (llvm::inconvertibleErrorCode (),
258
+ " file '%s' changed during build; include-tree "
259
+ " contents changed from %s to %s" ,
260
+ Filename.c_str (), OldID.c_str (),
261
+ NewID.c_str ());
262
+ }
263
+
249
264
llvm::Error IncludeTree::FileList::forEachFileImpl (
250
- llvm::DenseSet< ObjectRef> &Seen,
265
+ llvm::DenseMap<ObjectRef, ObjectRef> &Seen,
251
266
llvm::function_ref<llvm::Error(File, FileSizeTy)> Callback) {
252
267
size_t Next = 0 ;
253
268
size_t FileCount = getNumFilesCurrentList ();
269
+
254
270
return forEachReference ([&](ObjectRef Ref) -> llvm::Error {
255
271
size_t Index = Next++;
256
- if (!Seen.insert (Ref).second )
257
- return llvm::Error::success ();
258
-
259
272
if (Index < FileCount) {
260
273
auto Include = File::get (getCAS (), Ref);
261
274
if (!Include)
262
275
return Include.takeError ();
276
+ auto Inserted = Seen.try_emplace (Ref, Include->getContentsRef ());
277
+ if (!Inserted.second ) {
278
+ if (Inserted.first ->second != Include->getContentsRef ())
279
+ return diagnoseFileChange (*Include, Inserted.first ->second );
280
+ return llvm::Error::success ();
281
+ }
263
282
return Callback (std::move (*Include), getFileSize (Index));
264
283
}
265
284
266
285
// Otherwise, it's a chained FileList.
286
+ // Use a value to itself to indicate if the filelist node has been
287
+ // visited or not.
288
+ auto Inserted = Seen.try_emplace (Ref, Ref);
289
+ if (!Inserted.second )
290
+ return llvm::Error::success ();
291
+
267
292
auto Proxy = getCAS ().getProxy (Ref);
268
293
if (!Proxy)
269
294
return Proxy.takeError ();
@@ -274,7 +299,7 @@ llvm::Error IncludeTree::FileList::forEachFileImpl(
274
299
275
300
llvm::Error IncludeTree::FileList::forEachFile (
276
301
llvm::function_ref<llvm::Error(File, FileSizeTy)> Callback) {
277
- llvm::DenseSet< ObjectRef> Seen;
302
+ llvm::DenseMap<ObjectRef, ObjectRef> Seen;
278
303
return forEachFileImpl (Seen, Callback);
279
304
}
280
305
@@ -321,7 +346,7 @@ bool IncludeTree::FileList::isValid(const ObjectProxy &Node) {
321
346
return false ;
322
347
unsigned NumFiles =
323
348
llvm::support::endian::read <uint32_t , llvm::endianness::little>(Data.data ());
324
- return NumFiles != 0 && NumFiles <= Base.getNumReferences () &&
349
+ return NumFiles <= Base.getNumReferences () &&
325
350
Data.size () == sizeof (uint32_t ) + NumFiles * sizeof (FileSizeTy);
326
351
}
327
352
@@ -1015,38 +1040,19 @@ class IncludeTreeFileSystem : public llvm::vfs::FileSystem {
1015
1040
};
1016
1041
} // namespace
1017
1042
1018
- static llvm::Error diagnoseFileChange (IncludeTree::File F, ObjectRef Content) {
1019
- auto FilenameBlob = F.getFilename ();
1020
- if (!FilenameBlob)
1021
- return FilenameBlob.takeError ();
1022
- cas::ObjectStore &DB = F.getCAS ();
1023
- std::string Filename (FilenameBlob->getData ());
1024
- std::string OldID = DB.getID (Content).toString ();
1025
- std::string NewID = DB.getID (F.getContentsRef ()).toString ();
1026
- return llvm::createStringError (llvm::inconvertibleErrorCode (),
1027
- " file '%s' changed during build; include-tree "
1028
- " contents changed from %s to %s" ,
1029
- Filename.c_str (), OldID.c_str (),
1030
- NewID.c_str ());
1031
- }
1032
-
1033
- Expected<IntrusiveRefCntPtr<llvm::vfs::FileSystem>>
1034
- cas::createIncludeTreeFileSystem (IncludeTreeRoot &Root) {
1035
- auto FileList = Root.getFileList ();
1036
- if (!FileList)
1037
- return FileList.takeError ();
1038
-
1039
- std::vector<IncludeTree::FileList::FileEntry> Files;
1040
- Files.reserve (FileList->getNumReferences ());
1041
-
1042
- if (auto Err = FileList->forEachFile (
1043
- [&](IncludeTree::File File, IncludeTree::FileList::FileSizeTy Size ) {
1044
- Files.push_back ({File.getRef (), Size });
1045
- return llvm::Error::success ();
1046
- }))
1047
- return std::move (Err);
1048
-
1049
- return createIncludeTreeFileSystem (Root.getCAS (), Files);
1043
+ static std::string computeFilename (StringRef Name, IncludeTreeFileSystem &FS) {
1044
+ SmallString<128 > Filename (Name);
1045
+ assert (Filename != " ." );
1046
+ llvm::sys::path::remove_dots (Filename);
1047
+
1048
+ StringRef DirName = llvm::sys::path::parent_path (Filename);
1049
+ if (DirName.empty ())
1050
+ DirName = " ." ;
1051
+ auto &DirEntry = FS.Directories [DirName];
1052
+ if (DirEntry == llvm::sys::fs::UniqueID ()) {
1053
+ DirEntry = llvm::vfs::getNextVirtualUniqueID ();
1054
+ }
1055
+ return Filename.str ().str ();
1050
1056
}
1051
1057
1052
1058
Expected<IntrusiveRefCntPtr<llvm::vfs::FileSystem>>
@@ -1077,20 +1083,7 @@ cas::createIncludeTreeFileSystem(
1077
1083
if (!FilenameBlob)
1078
1084
return FilenameBlob.takeError ();
1079
1085
1080
- SmallString<128 > Filename (FilenameBlob->getData ());
1081
- // Strip './' in the filename to match the behaviour of ASTWriter; we
1082
- // also strip './' in IncludeTreeFileSystem::getPath.
1083
- assert (Filename != " ." );
1084
- llvm::sys::path::remove_dots (Filename);
1085
-
1086
- StringRef DirName = llvm::sys::path::parent_path (Filename);
1087
- if (DirName.empty ())
1088
- DirName = " ." ;
1089
- auto &DirEntry = IncludeTreeFS->Directories [DirName];
1090
- if (DirEntry == llvm::sys::fs::UniqueID ()) {
1091
- DirEntry = llvm::vfs::getNextVirtualUniqueID ();
1092
- }
1093
-
1086
+ auto Filename = computeFilename (FilenameBlob->getData (), *IncludeTreeFS);
1094
1087
IncludeTreeFS->Files .insert (std::make_pair (
1095
1088
Filename,
1096
1089
IncludeTreeFileSystem::FileEntry{File->getContentsRef (), Entry.Size ,
@@ -1099,3 +1092,30 @@ cas::createIncludeTreeFileSystem(
1099
1092
1100
1093
return IncludeTreeFS;
1101
1094
}
1095
+
1096
+ Expected<IntrusiveRefCntPtr<llvm::vfs::FileSystem>>
1097
+ cas::createIncludeTreeFileSystem (IncludeTree::FileList &List) {
1098
+ auto &CAS = List.getCAS ();
1099
+ IntrusiveRefCntPtr<IncludeTreeFileSystem> IncludeTreeFS =
1100
+ new IncludeTreeFileSystem (CAS);
1101
+
1102
+ auto E = List.forEachFile (
1103
+ [&](IncludeTree::File File,
1104
+ IncludeTree::FileList::FileSizeTy Size ) -> llvm::Error {
1105
+ auto FilenameBlob = File.getFilename ();
1106
+ if (!FilenameBlob)
1107
+ return FilenameBlob.takeError ();
1108
+ auto Filename =
1109
+ computeFilename (FilenameBlob->getData (), *IncludeTreeFS);
1110
+ IncludeTreeFS->Files .insert (
1111
+ std::make_pair (Filename, IncludeTreeFileSystem::FileEntry{
1112
+ File.getContentsRef (), Size ,
1113
+ llvm::vfs::getNextVirtualUniqueID ()}));
1114
+ return llvm::Error::success ();
1115
+ });
1116
+
1117
+ if (E)
1118
+ return std::move (E);
1119
+
1120
+ return IncludeTreeFS;
1121
+ }
0 commit comments