diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -11,8 +11,8 @@ #include "clang/Basic/LLVM.h" #include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/VirtualFileSystem.h" @@ -308,13 +308,15 @@ private: /// Check whether the file should be minimized. - bool shouldMinimize(StringRef Filename); + bool shouldMinimize(StringRef Filename, llvm::sys::fs::UniqueID UID); /// Returns entry for the given filename. /// /// Attempts to use the local and shared caches first, then falls back to /// using the underlying filesystem. - llvm::ErrorOr getOrCreateFileSystemEntry(StringRef Filename); + llvm::ErrorOr + getOrCreateFileSystemEntry(StringRef Filename, + bool DisableMinimization = false); /// For a filename that's not yet associated with any entry in the caches, /// uses the underlying filesystem to either look up the entry based in the @@ -325,7 +327,7 @@ /// Minimizes the given entry if necessary and returns a wrapper object with /// reference semantics. EntryRef minimizeIfNecessary(const CachedFileSystemEntry &Entry, - StringRef Filename); + StringRef Filename, bool Disable); /// Represents a filesystem entry that has been stat-ed (and potentially read) /// and that's about to be inserted into the cache as `CachedFileSystemEntry`. @@ -401,7 +403,7 @@ /// currently active preprocessor. ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; /// The set of files that should not be minimized. - llvm::StringSet<> NotToBeMinimized; + llvm::DenseSet NotToBeMinimized; }; } // end namespace dependencies diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp @@ -42,8 +42,9 @@ } EntryRef DependencyScanningWorkerFilesystem::minimizeIfNecessary( - const CachedFileSystemEntry &Entry, StringRef Filename) { - if (Entry.isError() || Entry.isDirectory() || !shouldMinimize(Filename)) + const CachedFileSystemEntry &Entry, StringRef Filename, bool Disable) { + if (Entry.isError() || Entry.isDirectory() || Disable || + !shouldMinimize(Filename, Entry.getUniqueID())) return EntryRef(/*Minimized=*/false, Filename, Entry); CachedFileContents *Contents = Entry.getContents(); @@ -210,19 +211,18 @@ } void DependencyScanningWorkerFilesystem::disableMinimization( - StringRef RawFilename) { - llvm::SmallString<256> Filename; - llvm::sys::path::native(RawFilename, Filename); - NotToBeMinimized.insert(Filename); + StringRef Filename) { + // Since we're not done setting up `NotToBeMinimized` yet, we need to disable + // minimization explicitly. + if (llvm::ErrorOr Result = + getOrCreateFileSystemEntry(Filename, /*DisableMinimization=*/true)) + NotToBeMinimized.insert(Result->getStatus().getUniqueID()); } -bool DependencyScanningWorkerFilesystem::shouldMinimize(StringRef RawFilename) { - if (!shouldMinimizeBasedOnExtension(RawFilename)) - return false; - - llvm::SmallString<256> Filename; - llvm::sys::path::native(RawFilename, Filename); - return !NotToBeMinimized.contains(Filename); +bool DependencyScanningWorkerFilesystem::shouldMinimize( + StringRef Filename, llvm::sys::fs::UniqueID UID) { + return shouldMinimizeBasedOnExtension(Filename) && + !NotToBeMinimized.contains(UID); } const CachedFileSystemEntry & @@ -275,13 +275,15 @@ llvm::ErrorOr DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( - StringRef Filename) { + StringRef Filename, bool DisableMinimization) { if (const auto *Entry = findEntryByFilenameWithWriteThrough(Filename)) - return minimizeIfNecessary(*Entry, Filename).unwrapError(); + return minimizeIfNecessary(*Entry, Filename, DisableMinimization) + .unwrapError(); auto MaybeEntry = computeAndStoreResult(Filename); if (!MaybeEntry) return MaybeEntry.getError(); - return minimizeIfNecessary(*MaybeEntry, Filename).unwrapError(); + return minimizeIfNecessary(*MaybeEntry, Filename, DisableMinimization) + .unwrapError(); } llvm::ErrorOr diff --git a/clang/test/ClangScanDeps/modules-symlink.c b/clang/test/ClangScanDeps/modules-symlink.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/modules-symlink.c @@ -0,0 +1,54 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t + +//--- cdb_pch.json +[ + { + "directory": "DIR", + "command": "clang -x c-header DIR/pch.h -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -o DIR/pch.h.gch", + "file": "DIR/pch.h" + } +] + +//--- cdb_tu.json +[ + { + "directory": "DIR", + "command": "clang -c DIR/tu.c -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -include DIR/pch.h -o DIR/tu.o", + "file": "DIR/tu.c" + } +] + +//--- module.modulemap +module mod { header "symlink.h" } + +//--- pch.h +#include "symlink.h" + +//--- original.h +// Comment that will be stripped by the minimizer. +#define MACRO 1 + +//--- tu.c +#include "original.h" +static int foo = MACRO; // Macro usage that will trigger + // input file consistency checks. + +// RUN: ln -s %t/original.h %t/symlink.h + +// RUN: sed -e "s|DIR|%/t|g" %t/cdb_pch.json > %t/cdb.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full \ +// RUN: -generate-modules-path-args -module-files-dir %t/build > %t/result_pch.json +// +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json \ +// RUN: --module-name=mod > %t/mod.cc1.rsp +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json \ +// RUN: --tu-index=0 > %t/pch.rsp +// +// RUN: %clang @%t/mod.cc1.rsp +// RUN: %clang -x c-header %t/pch.h -fmodules -gmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t/cache -o %t/pch.h.gch -I %t @%t/pch.rsp + +// RUN: sed -e "s|DIR|%/t|g" %t/cdb_tu.json > %t/cdb.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full \ +// RUN: -generate-modules-path-args -module-files-dir %t/build > %t/result_tu.json