Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/DependencyDirectivesScanner.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/ArrayRef.h"
Expand Down Expand Up @@ -99,6 +100,9 @@ class CompilerInstance : public ModuleLoader {
/// The cache of PCM files.
IntrusiveRefCntPtr<ModuleCache> ModCache;

/// Functor for getting the dependency preprocessor directives of a file.
std::unique_ptr<DependencyDirectivesGetter> GetDependencyDirectives;

/// The preprocessor.
std::shared_ptr<Preprocessor> PP;

Expand Down Expand Up @@ -697,6 +701,11 @@ class CompilerInstance : public ModuleLoader {
/// and replace any existing one with it.
void createPreprocessor(TranslationUnitKind TUKind);

void setDependencyDirectivesGetter(
std::unique_ptr<DependencyDirectivesGetter> Getter) {
GetDependencyDirectives = std::move(Getter);
}

std::string getSpecificModuleCachePath(StringRef ModuleHash);
std::string getSpecificModuleCachePath() {
return getSpecificModuleCachePath(getInvocation().getModuleHash());
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/Lex/DependencyDirectivesScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/ADT/ArrayRef.h"

namespace clang {
class FileManager;

namespace tok {
enum TokenKind : unsigned short;
Expand Down Expand Up @@ -135,6 +136,19 @@ void printDependencyDirectivesAsSource(
ArrayRef<dependency_directives_scan::Directive> Directives,
llvm::raw_ostream &OS);

/// Functor that returns the dependency directives for a given file.
class DependencyDirectivesGetter {
public:
/// Clone the getter for a new \c FileManager instance.
virtual std::unique_ptr<DependencyDirectivesGetter>
cloneFor(FileManager &FileMgr) = 0;

/// Get the dependency directives for the given file.
virtual std::optional<ArrayRef<dependency_directives_scan::Directive>>
operator()(FileEntryRef File) = 0;

virtual ~DependencyDirectivesGetter() = default;
};
} // end namespace clang

#endif // LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H
10 changes: 10 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ class Preprocessor {
friend class VariadicMacroScopeGuard;

llvm::unique_function<void(const clang::Token &)> OnToken;
/// Functor for getting the dependency preprocessor directives of a file.
///
/// These are directives derived from a special form of lexing where the
/// source input is scanned for the preprocessor directives that might have an
/// effect on the dependencies for a compilation unit.
DependencyDirectivesGetter *GetDependencyDirectives = nullptr;
const PreprocessorOptions &PPOpts;
DiagnosticsEngine *Diags;
const LangOptions &LangOpts;
Expand Down Expand Up @@ -1326,6 +1332,10 @@ class Preprocessor {
OnToken = std::move(F);
}

void setDependencyDirectivesGetter(DependencyDirectivesGetter &Get) {
GetDependencyDirectives = &Get;
}

void setPreprocessToken(bool Preprocess) { PreprocessToken = Preprocess; }

bool isMacroDefined(StringRef Id) {
Expand Down
13 changes: 0 additions & 13 deletions clang/include/clang/Lex/PreprocessorOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,6 @@ class PreprocessorOptions {
/// with support for lifetime-qualified pointers.
ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib;

/// Function for getting the dependency preprocessor directives of a file.
///
/// These are directives derived from a special form of lexing where the
/// source input is scanned for the preprocessor directives that might have an
/// effect on the dependencies for a compilation unit.
///
/// Enables a client to cache the directives for a file and provide them
/// across multiple compiler invocations.
/// FIXME: Allow returning an error.
std::function<std::optional<ArrayRef<dependency_directives_scan::Directive>>(
FileEntryRef)>
DependencyDirectivesForFile;

/// Set up preprocessor for RunAnalysis action.
bool SetUpStaticAnalyzer = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,16 @@ class DependencyScanningWorkerFilesystem
/// false if not (i.e. this entry is not a file or its scan fails).
bool ensureDirectiveTokensArePopulated(EntryRef Entry);

/// \returns The scanned preprocessor directive tokens of the file that are
/// used to speed up preprocessing, if available.
std::optional<ArrayRef<dependency_directives_scan::Directive>>
getDirectiveTokens(const Twine &Path) {
if (llvm::ErrorOr<EntryRef> Entry = getOrCreateFileSystemEntry(Path.str()))
if (ensureDirectiveTokensArePopulated(*Entry))
return Entry->getDirectiveTokens();
return std::nullopt;
}

/// Check whether \p Path exists. By default checks cached result of \c
/// status(), and falls back on FS if unable to do so.
bool exists(const Twine &Path) override;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
/*ShowAllHeaders=*/true, /*OutputPath=*/"",
/*ShowDepth=*/true, /*MSStyle=*/true);
}

if (GetDependencyDirectives)
PP->setDependencyDirectivesGetter(*GetDependencyDirectives);
}

std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) {
Expand Down Expand Up @@ -1237,6 +1240,10 @@ std::unique_ptr<CompilerInstance> CompilerInstance::cloneForModuleCompileImpl(
// Make a copy for the new instance.
Instance.FailedModules = FailedModules;

if (GetDependencyDirectives)
Instance.GetDependencyDirectives =
GetDependencyDirectives->cloneFor(Instance.getFileManager());

// If we're collecting module dependencies, we need to share a collector
// between all of the module CompilerInstances. Other than that, we don't
// want to produce any dependency output from the module build.
Expand Down
14 changes: 4 additions & 10 deletions clang/lib/Lex/PPLexerChange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,10 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir,
}

Lexer *TheLexer = new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile);
if (getPreprocessorOpts().DependencyDirectivesForFile &&
FID != PredefinesFileID) {
if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) {
if (std::optional<ArrayRef<dependency_directives_scan::Directive>>
DepDirectives =
getPreprocessorOpts().DependencyDirectivesForFile(*File)) {
TheLexer->DepDirectives = *DepDirectives;
}
}
}
if (GetDependencyDirectives && FID != PredefinesFileID)
if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID))
if (auto MaybeDepDirectives = (*GetDependencyDirectives)(*File))
TheLexer->DepDirectives = *MaybeDepDirectives;

EnterSourceFileWithLexer(TheLexer, CurDir);
return false;
Expand Down
42 changes: 31 additions & 11 deletions clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,32 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) {
std::swap(PPOpts.Macros, NewMacros);
}

class ActualDependencyDirectivesGetter : public DependencyDirectivesGetter {
DependencyScanningWorkerFilesystem *DepFS;

public:
ActualDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) {
FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) {
auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
if (DFS) {
assert(!DepFS && "Found multiple scanning VFSs");
DepFS = DFS;
}
});
assert(DepFS && "Did not find scanning VFS");
}

std::unique_ptr<DependencyDirectivesGetter>
cloneFor(FileManager &FileMgr) override {
return std::make_unique<ActualDependencyDirectivesGetter>(FileMgr);
}

std::optional<ArrayRef<dependency_directives_scan::Directive>>
operator()(FileEntryRef File) override {
return DepFS->getDirectiveTokens(File.getName());
}
};

/// A clang tool that runs the preprocessor in a mode that's optimized for
/// dependency scanning for the given compiler invocation.
class DependencyScanningAction : public tooling::ToolAction {
Expand Down Expand Up @@ -424,6 +450,9 @@ class DependencyScanningAction : public tooling::ToolAction {
ScanInstance.getInvocation(), ScanInstance.getDiagnostics(),
DriverFileMgr->getVirtualFileSystemPtr());

// Create a new FileManager to match the invocation's FileSystemOptions.
auto *FileMgr = ScanInstance.createFileManager(FS);

// Use the dependency scanning optimized file system if requested to do so.
if (DepFS) {
StringRef ModulesCachePath =
Expand All @@ -433,19 +462,10 @@ class DependencyScanningAction : public tooling::ToolAction {
if (!ModulesCachePath.empty())
DepFS->setBypassedPathPrefix(ModulesCachePath);

ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile =
[LocalDepFS = DepFS](FileEntryRef File)
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
if (llvm::ErrorOr<EntryRef> Entry =
LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
return Entry->getDirectiveTokens();
return std::nullopt;
};
ScanInstance.setDependencyDirectivesGetter(
std::make_unique<ActualDependencyDirectivesGetter>(*FileMgr));
}

// Create a new FileManager to match the invocation's FileSystemOptions.
auto *FileMgr = ScanInstance.createFileManager(FS);
ScanInstance.createSourceManager(*FileMgr);

// Store a mapping of prebuilt module files and their properties like header
Expand Down
42 changes: 26 additions & 16 deletions clang/unittests/Lex/PPDependencyDirectivesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,25 +103,33 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) {
SmallVector<dependency_directives_scan::Token> Tokens;
SmallVector<dependency_directives_scan::Directive> Directives;
};
SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects;

auto getDependencyDirectives = [&](FileEntryRef File)
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
DepDirectivesObjects.push_back(std::make_unique<DepDirectives>());
StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer();
bool Err = scanSourceForDependencyDirectives(
Input, DepDirectivesObjects.back()->Tokens,
DepDirectivesObjects.back()->Directives);
EXPECT_FALSE(Err);
return llvm::ArrayRef(DepDirectivesObjects.back()->Directives);
};

PreprocessorOptions PPOpts;
PPOpts.DependencyDirectivesForFile = [&](FileEntryRef File)
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
return getDependencyDirectives(File);
class TestDependencyDirectivesGetter : public DependencyDirectivesGetter {
FileManager &FileMgr;
SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects;

public:
TestDependencyDirectivesGetter(FileManager &FileMgr) : FileMgr(FileMgr) {}

std::unique_ptr<DependencyDirectivesGetter>
cloneFor(FileManager &FileMgr) override {
return std::make_unique<TestDependencyDirectivesGetter>(FileMgr);
}

std::optional<ArrayRef<dependency_directives_scan::Directive>>
operator()(FileEntryRef File) override {
DepDirectivesObjects.push_back(std::make_unique<DepDirectives>());
StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer();
bool Err = scanSourceForDependencyDirectives(
Input, DepDirectivesObjects.back()->Tokens,
DepDirectivesObjects.back()->Directives);
EXPECT_FALSE(Err);
return DepDirectivesObjects.back()->Directives;
}
};
TestDependencyDirectivesGetter GetDependencyDirectives(FileMgr);

PreprocessorOptions PPOpts;
HeaderSearchOptions HSOpts;
TrivialModuleLoader ModLoader;
HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
Expand All @@ -130,6 +138,8 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) {
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);

PP.setDependencyDirectivesGetter(GetDependencyDirectives);

SmallVector<StringRef> IncludedFiles;
PP.addPPCallbacks(std::make_unique<IncludeCollector>(PP, IncludedFiles));
PP.EnterMainSourceFile();
Expand Down
Loading