Skip to content

Commit 71763a5

Browse files
authored
[clang] Extract CompilerInvocation::visitPaths() (llvm#167420)
This PR extracts visitation of paths stored in `CompilerInvocation` into a member function. We already have a second copy of this downstream, and I'm in the need of adding a third one.
1 parent 53a65ba commit 71763a5

File tree

4 files changed

+102
-76
lines changed

4 files changed

+102
-76
lines changed

clang/include/clang/Frontend/CompilerInvocation.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ class CompilerInvocationBase {
147147
}
148148
/// @}
149149

150+
/// Visitation.
151+
/// @{
152+
/// Visits paths stored in the invocation. The callback may return true to
153+
/// short-circuit the visitation, or return false to continue visiting.
154+
void visitPaths(llvm::function_ref<bool(StringRef)> Callback) const;
155+
/// @}
156+
150157
/// Command line generation.
151158
/// @{
152159
using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
@@ -181,6 +188,12 @@ class CompilerInvocationBase {
181188
/// This is a (less-efficient) wrapper over generateCC1CommandLine().
182189
std::vector<std::string> getCC1CommandLine() const;
183190

191+
protected:
192+
/// Visits paths stored in the invocation. This is generally unsafe to call
193+
/// directly, and each sub-class need to ensure calling this doesn't violate
194+
/// its invariants.
195+
void visitPathsImpl(llvm::function_ref<bool(std::string &)> Predicate);
196+
184197
private:
185198
/// Generate command line options from DiagnosticOptions.
186199
static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ class FrontendInputFile {
241241
/// Whether we're dealing with a 'system' input (vs. a 'user' input).
242242
bool IsSystem = false;
243243

244+
friend class CompilerInvocationBase;
245+
244246
public:
245247
FrontendInputFile() = default;
246248
FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false)

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5280,6 +5280,86 @@ std::string CompilerInvocation::getModuleHash() const {
52805280
return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false);
52815281
}
52825282

5283+
void CompilerInvocationBase::visitPathsImpl(
5284+
llvm::function_ref<bool(std::string &)> Predicate) {
5285+
#define RETURN_IF(PATH) \
5286+
do { \
5287+
if (Predicate(PATH)) \
5288+
return; \
5289+
} while (0)
5290+
5291+
#define RETURN_IF_MANY(PATHS) \
5292+
do { \
5293+
if (llvm::any_of(PATHS, Predicate)) \
5294+
return; \
5295+
} while (0)
5296+
5297+
auto &HeaderSearchOpts = *this->HSOpts;
5298+
// Header search paths.
5299+
RETURN_IF(HeaderSearchOpts.Sysroot);
5300+
for (auto &Entry : HeaderSearchOpts.UserEntries)
5301+
if (Entry.IgnoreSysRoot)
5302+
RETURN_IF(Entry.Path);
5303+
RETURN_IF(HeaderSearchOpts.ResourceDir);
5304+
RETURN_IF(HeaderSearchOpts.ModuleCachePath);
5305+
RETURN_IF(HeaderSearchOpts.ModuleUserBuildPath);
5306+
for (auto &[Name, File] : HeaderSearchOpts.PrebuiltModuleFiles)
5307+
RETURN_IF(File);
5308+
RETURN_IF_MANY(HeaderSearchOpts.PrebuiltModulePaths);
5309+
RETURN_IF_MANY(HeaderSearchOpts.VFSOverlayFiles);
5310+
5311+
// Preprocessor options.
5312+
auto &PPOpts = *this->PPOpts;
5313+
RETURN_IF_MANY(PPOpts.MacroIncludes);
5314+
RETURN_IF_MANY(PPOpts.Includes);
5315+
RETURN_IF(PPOpts.ImplicitPCHInclude);
5316+
5317+
// Frontend options.
5318+
auto &FrontendOpts = *this->FrontendOpts;
5319+
for (auto &Input : FrontendOpts.Inputs) {
5320+
if (Input.isBuffer())
5321+
continue;
5322+
5323+
RETURN_IF(Input.File);
5324+
}
5325+
RETURN_IF(FrontendOpts.CodeCompletionAt.FileName);
5326+
RETURN_IF_MANY(FrontendOpts.ModuleMapFiles);
5327+
RETURN_IF_MANY(FrontendOpts.ModuleFiles);
5328+
RETURN_IF_MANY(FrontendOpts.ModulesEmbedFiles);
5329+
RETURN_IF_MANY(FrontendOpts.ASTMergeFiles);
5330+
RETURN_IF(FrontendOpts.OverrideRecordLayoutsFile);
5331+
RETURN_IF(FrontendOpts.StatsFile);
5332+
5333+
// Filesystem options.
5334+
auto &FileSystemOpts = *this->FSOpts;
5335+
RETURN_IF(FileSystemOpts.WorkingDir);
5336+
5337+
// Codegen options.
5338+
auto &CodeGenOpts = *this->CodeGenOpts;
5339+
RETURN_IF(CodeGenOpts.DebugCompilationDir);
5340+
RETURN_IF(CodeGenOpts.CoverageCompilationDir);
5341+
5342+
// Sanitizer options.
5343+
RETURN_IF_MANY(LangOpts->NoSanitizeFiles);
5344+
5345+
// Coverage mappings.
5346+
RETURN_IF(CodeGenOpts.ProfileInstrumentUsePath);
5347+
RETURN_IF(CodeGenOpts.SampleProfileFile);
5348+
RETURN_IF(CodeGenOpts.ProfileRemappingFile);
5349+
5350+
// Dependency output options.
5351+
for (auto &ExtraDep : DependencyOutputOpts->ExtraDeps)
5352+
RETURN_IF(ExtraDep.first);
5353+
}
5354+
5355+
void CompilerInvocationBase::visitPaths(
5356+
llvm::function_ref<bool(StringRef)> Callback) const {
5357+
// The const_cast here is OK, because visitPathsImpl() itself doesn't modify
5358+
// the invocation, and our callback takes immutable StringRefs.
5359+
return const_cast<CompilerInvocationBase *>(this)->visitPathsImpl(
5360+
[&Callback](std::string &Path) { return Callback(StringRef(Path)); });
5361+
}
5362+
52835363
void CompilerInvocationBase::generateCC1CommandLine(
52845364
ArgumentConsumer Consumer) const {
52855365
llvm::Triple T(getTargetOpts().Triple);

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 7 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -471,82 +471,13 @@ static bool isSafeToIgnoreCWD(const CowCompilerInvocation &CI) {
471471
// Check if the command line input uses relative paths.
472472
// It is not safe to ignore the current working directory if any of the
473473
// command line inputs use relative paths.
474-
#define IF_RELATIVE_RETURN_FALSE(PATH) \
475-
do { \
476-
if (!PATH.empty() && !llvm::sys::path::is_absolute(PATH)) \
477-
return false; \
478-
} while (0)
479-
480-
#define IF_ANY_RELATIVE_RETURN_FALSE(PATHS) \
481-
do { \
482-
if (llvm::any_of(PATHS, [](const auto &P) { \
483-
return !P.empty() && !llvm::sys::path::is_absolute(P); \
484-
})) \
485-
return false; \
486-
} while (0)
487-
488-
// Header search paths.
489-
const auto &HeaderSearchOpts = CI.getHeaderSearchOpts();
490-
IF_RELATIVE_RETURN_FALSE(HeaderSearchOpts.Sysroot);
491-
for (auto &Entry : HeaderSearchOpts.UserEntries)
492-
if (Entry.IgnoreSysRoot)
493-
IF_RELATIVE_RETURN_FALSE(Entry.Path);
494-
IF_RELATIVE_RETURN_FALSE(HeaderSearchOpts.ResourceDir);
495-
IF_RELATIVE_RETURN_FALSE(HeaderSearchOpts.ModuleCachePath);
496-
IF_RELATIVE_RETURN_FALSE(HeaderSearchOpts.ModuleUserBuildPath);
497-
for (auto I = HeaderSearchOpts.PrebuiltModuleFiles.begin(),
498-
E = HeaderSearchOpts.PrebuiltModuleFiles.end();
499-
I != E;) {
500-
auto Current = I++;
501-
IF_RELATIVE_RETURN_FALSE(Current->second);
502-
}
503-
IF_ANY_RELATIVE_RETURN_FALSE(HeaderSearchOpts.PrebuiltModulePaths);
504-
IF_ANY_RELATIVE_RETURN_FALSE(HeaderSearchOpts.VFSOverlayFiles);
505-
506-
// Preprocessor options.
507-
const auto &PPOpts = CI.getPreprocessorOpts();
508-
IF_ANY_RELATIVE_RETURN_FALSE(PPOpts.MacroIncludes);
509-
IF_ANY_RELATIVE_RETURN_FALSE(PPOpts.Includes);
510-
IF_RELATIVE_RETURN_FALSE(PPOpts.ImplicitPCHInclude);
511-
512-
// Frontend options.
513-
const auto &FrontendOpts = CI.getFrontendOpts();
514-
for (const FrontendInputFile &Input : FrontendOpts.Inputs) {
515-
if (Input.isBuffer())
516-
continue; // FIXME: Can this happen when parsing command-line?
517-
518-
IF_RELATIVE_RETURN_FALSE(Input.getFile());
519-
}
520-
IF_RELATIVE_RETURN_FALSE(FrontendOpts.CodeCompletionAt.FileName);
521-
IF_ANY_RELATIVE_RETURN_FALSE(FrontendOpts.ModuleMapFiles);
522-
IF_ANY_RELATIVE_RETURN_FALSE(FrontendOpts.ModuleFiles);
523-
IF_ANY_RELATIVE_RETURN_FALSE(FrontendOpts.ModulesEmbedFiles);
524-
IF_ANY_RELATIVE_RETURN_FALSE(FrontendOpts.ASTMergeFiles);
525-
IF_RELATIVE_RETURN_FALSE(FrontendOpts.OverrideRecordLayoutsFile);
526-
IF_RELATIVE_RETURN_FALSE(FrontendOpts.StatsFile);
527-
528-
// Filesystem options.
529-
const auto &FileSystemOpts = CI.getFileSystemOpts();
530-
IF_RELATIVE_RETURN_FALSE(FileSystemOpts.WorkingDir);
531-
532-
// Codegen options.
533-
const auto &CodeGenOpts = CI.getCodeGenOpts();
534-
IF_RELATIVE_RETURN_FALSE(CodeGenOpts.DebugCompilationDir);
535-
IF_RELATIVE_RETURN_FALSE(CodeGenOpts.CoverageCompilationDir);
536-
537-
// Sanitizer options.
538-
IF_ANY_RELATIVE_RETURN_FALSE(CI.getLangOpts().NoSanitizeFiles);
539-
540-
// Coverage mappings.
541-
IF_RELATIVE_RETURN_FALSE(CodeGenOpts.ProfileInstrumentUsePath);
542-
IF_RELATIVE_RETURN_FALSE(CodeGenOpts.SampleProfileFile);
543-
IF_RELATIVE_RETURN_FALSE(CodeGenOpts.ProfileRemappingFile);
544-
545-
// Dependency output options.
546-
for (auto &ExtraDep : CI.getDependencyOutputOpts().ExtraDeps)
547-
IF_RELATIVE_RETURN_FALSE(ExtraDep.first);
548-
549-
return true;
474+
bool AnyRelative = false;
475+
CI.visitPaths([&](StringRef Path) {
476+
assert(!AnyRelative && "Continuing path visitation despite returning true");
477+
AnyRelative |= !Path.empty() && !llvm::sys::path::is_absolute(Path);
478+
return AnyRelative;
479+
});
480+
return !AnyRelative;
550481
}
551482

552483
static std::string getModuleContextHash(const ModuleDeps &MD,

0 commit comments

Comments
 (0)