https://github.com/anutosh491 updated https://github.com/llvm/llvm-project/pull/226022
>From a465f0737e32aeccdc64092abd8c572cf7c4cb9e Mon Sep 17 00:00:00 2001 From: anutosh491 <[email protected]> Date: Thu, 24 Sep 2026 10:09:42 +0530 Subject: [PATCH] [clang] Make verbose output streams configurable --- clang/include/clang/Driver/Driver.h | 13 ++++ clang/include/clang/Interpreter/Interpreter.h | 8 +++ clang/include/clang/Lex/HeaderSearch.h | 4 +- clang/include/clang/Tooling/Tooling.h | 27 ++++++++ clang/lib/Driver/Compilation.cpp | 2 +- clang/lib/Driver/Driver.cpp | 20 +++--- clang/lib/Driver/ToolChains/Darwin.cpp | 8 +-- clang/lib/Driver/ToolChains/ZOS.cpp | 2 +- clang/lib/Frontend/CompilerInstance.cpp | 3 +- clang/lib/Interpreter/Interpreter.cpp | 10 ++- clang/lib/Lex/InitHeaderSearch.cpp | 43 +++++++----- clang/lib/Tooling/Tooling.cpp | 16 ++++- .../IncrementalCompilerBuilderTest.cpp | 27 ++++++++ clang/unittests/Tooling/ToolingTest.cpp | 66 +++++++++++++++++++ 14 files changed, 208 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index e653d8e3a2dbe..0d492b49b8ed3 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -95,6 +95,10 @@ class Driver { IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS; + /// Stream used for informational output produced by verbose driver modes. + /// Diagnostics continue to use the diagnostics engine. + raw_ostream *VerboseOutputStream; + enum DriverMode { GCCMode, GXXMode, @@ -413,6 +417,15 @@ class Driver { void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + /// Replace the stream used for informational verbose output. The caller + /// retains ownership and must keep the stream alive for this Driver. + void setVerboseOutputStream(raw_ostream &Value) { + VerboseOutputStream = &Value; + } + + /// Return the stream used for informational verbose output. + raw_ostream &getVerboseOutputStream() const { return *VerboseOutputStream; } + bool getProbePrecompiled() const { return ProbePrecompiled; } void setProbePrecompiled(bool Value) { ProbePrecompiled = Value; } diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index c2622b23d5d9c..3235b9de44da5 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -59,6 +59,13 @@ class IncrementalCompilerBuilder { void SetTargetTriple(std::string TT) { TargetTriple = TT; } + /// Set the stream used for informational verbose output. The caller must + /// ensure that the stream outlives compiler instances created by this + /// builder. Diagnostics are not redirected. + void SetVerboseOutputStream(llvm::raw_ostream &OS) { + VerboseOutputStream = &OS; + } + // General C++ llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCpp(); @@ -84,6 +91,7 @@ class IncrementalCompilerBuilder { std::vector<const char *> UserArgs; std::optional<std::string> TargetTriple; + llvm::raw_ostream *VerboseOutputStream = nullptr; llvm::StringRef OffloadArch; llvm::StringRef CudaSDKPath; diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index adaa126024c3c..09dfa39088682 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -37,6 +37,7 @@ namespace llvm { +class raw_ostream; class Triple; } // namespace llvm @@ -1061,7 +1062,8 @@ class HeaderSearch { void ApplyHeaderSearchOptions(HeaderSearch &HS, const HeaderSearchOptions &HSOpts, const LangOptions &Lang, - const llvm::Triple &triple); + const llvm::Triple &triple, + llvm::raw_ostream *VerboseOutput = nullptr); void normalizeModuleCachePath(FileManager &FileMgr, StringRef Path, SmallVectorImpl<char> &NormalizedPath); diff --git a/clang/include/clang/Tooling/Tooling.h b/clang/include/clang/Tooling/Tooling.h index 9909394495496..f2bdeb0420a11 100644 --- a/clang/include/clang/Tooling/Tooling.h +++ b/clang/include/clang/Tooling/Tooling.h @@ -79,15 +79,28 @@ getCC1Arguments(DiagnosticsEngine *Diagnostics, /// If your tool is based on FrontendAction, you should be deriving from /// FrontendActionFactory instead. class ToolAction { + llvm::raw_ostream *VerboseOutputStream = nullptr; + public: virtual ~ToolAction(); + /// Set the stream used for informational verbose output. The caller retains + /// ownership and must keep the stream alive while this action runs. + void setVerboseOutputStream(llvm::raw_ostream &OS) { + VerboseOutputStream = &OS; + } + /// Perform an action for an invocation. virtual bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps, DiagnosticConsumer *DiagConsumer) = 0; + +protected: + llvm::raw_ostream *getVerboseOutputStream() const { + return VerboseOutputStream; + } }; /// Interface to generate clang::FrontendActions. @@ -289,6 +302,12 @@ class ToolInvocation { this->DiagOpts = DiagOpts; } + /// Set the stream used for informational verbose output. The caller retains + /// ownership and must keep the stream alive while this invocation runs. + void setVerboseOutputStream(llvm::raw_ostream &OS) { + VerboseOutputStream = &OS; + } + /// Run the clang invocation. /// /// \returns True if there were no errors during execution. @@ -307,6 +326,7 @@ class ToolInvocation { std::shared_ptr<PCHContainerOperations> PCHContainerOps; DiagnosticConsumer *DiagConsumer = nullptr; DiagnosticOptions *DiagOpts = nullptr; + llvm::raw_ostream *VerboseOutputStream = nullptr; }; /// Utility to run a FrontendAction over a set of files. @@ -345,6 +365,12 @@ class ClangTool { this->DiagConsumer = DiagConsumer; } + /// Set the stream used for informational verbose output. The caller retains + /// ownership and must keep the stream alive while this tool runs. + void setVerboseOutputStream(llvm::raw_ostream &OS) { + VerboseOutputStream = &OS; + } + /// Map a virtual file to be used while running the tool. /// /// \param FilePath The path at which the content will be mapped. @@ -400,6 +426,7 @@ class ClangTool { ArgumentsAdjuster ArgsAdjuster; DiagnosticConsumer *DiagConsumer = nullptr; + llvm::raw_ostream *VerboseOutputStream = nullptr; bool PrintErrorMessage = true; }; diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index c81c4445a29f9..54e6d7767942c 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -168,7 +168,7 @@ int Compilation::ExecuteCommand(const Command &C, bool LogOnly) const { if ((getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { - raw_ostream *OS = &llvm::errs(); + raw_ostream *OS = &getDriver().getVerboseOutputStream(); std::unique_ptr<llvm::raw_fd_ostream> OwnedStream; // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7a742e404bf5c..29700f7f3631b 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -200,8 +200,8 @@ std::string CUIDOptions::getCUID(StringRef InputFile, Driver::Driver(StringRef DriverExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, std::string Title, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) - : Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), - SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), + : Diags(Diags), VFS(std::move(VFS)), VerboseOutputStream(&llvm::errs()), + Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), Offload(OffloadHostDevice), CXX20HeaderType(HeaderMode_None), ModulesModeCXX20(false), DriverExecutable(DriverExecutable), SysRoot(DEFAULT_SYSROOT), DriverTitle(Title), CCCPrintBindings(false), @@ -2432,7 +2432,7 @@ int Driver::ExecuteCompilation( SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) { if (C.getArgs().hasArg(options::OPT_fdriver_only)) { if (C.getArgs().hasArg(options::OPT_v)) - C.getJobs().Print(llvm::errs(), "\n", true); + C.getJobs().Print(getVerboseOutputStream(), "\n", true); C.ExecuteJobs(C.getJobs(), FailingCommands, /*LogOnly=*/true); @@ -2445,7 +2445,7 @@ int Driver::ExecuteCompilation( // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { - C.getJobs().Print(llvm::errs(), "\n", true); + C.getJobs().Print(getVerboseOutputStream(), "\n", true); return Diags.hasErrorOccurred() ? 1 : 0; } @@ -2709,23 +2709,23 @@ bool Driver::HandleImmediateArgs(Compilation &C) { C.getArgs().hasArg(options::OPT_print_supported_cpus) || C.getArgs().hasArg(options::OPT_print_supported_extensions) || C.getArgs().hasArg(options::OPT_print_enabled_extensions)) { - PrintVersion(C, llvm::errs()); + PrintVersion(C, getVerboseOutputStream()); SuppressMissingInputWarning = true; } if (C.getArgs().hasArg(options::OPT_v)) { if (!SystemConfigDir.empty()) - llvm::errs() << "System configuration file directory: " - << SystemConfigDir << "\n"; + getVerboseOutputStream() + << "System configuration file directory: " << SystemConfigDir << "\n"; if (!UserConfigDir.empty()) - llvm::errs() << "User configuration file directory: " - << UserConfigDir << "\n"; + getVerboseOutputStream() + << "User configuration file directory: " << UserConfigDir << "\n"; } const ToolChain &TC = C.getDefaultToolChain(); if (C.getArgs().hasArg(options::OPT_v)) - TC.printVerboseInfo(llvm::errs()); + TC.printVerboseInfo(getVerboseOutputStream()); if (C.getArgs().hasArg(options::OPT_print_resource_dir)) { llvm::outs() << ResourceDir << '\n'; diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 0fb94d8712e69..d376992cc0e1b 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -3078,8 +3078,8 @@ void AppleMachO::AddClangCXXStdlibIncludeArgs( addSystemInclude(DriverArgs, CC1Args, InstallBin); return; } else if (DriverArgs.hasArg(options::OPT_v)) { - llvm::errs() << "ignoring nonexistent directory \"" << InstallBin - << "\"\n"; + getDriver().getVerboseOutputStream() + << "ignoring nonexistent directory \"" << InstallBin << "\"\n"; } // Otherwise, check for (2) @@ -3089,8 +3089,8 @@ void AppleMachO::AddClangCXXStdlibIncludeArgs( addSystemInclude(DriverArgs, CC1Args, SysrootUsr); return; } else if (DriverArgs.hasArg(options::OPT_v)) { - llvm::errs() << "ignoring nonexistent directory \"" << SysrootUsr - << "\"\n"; + getDriver().getVerboseOutputStream() + << "ignoring nonexistent directory \"" << SysrootUsr << "\"\n"; } // Otherwise, don't add any path. diff --git a/clang/lib/Driver/ToolChains/ZOS.cpp b/clang/lib/Driver/ToolChains/ZOS.cpp index 4c6df90e419b9..01cdb13869116 100644 --- a/clang/lib/Driver/ToolChains/ZOS.cpp +++ b/clang/lib/Driver/ToolChains/ZOS.cpp @@ -331,7 +331,7 @@ void ZOS::TryAddIncludeFromPath(llvm::SmallString<128> Path, llvm::opt::ArgStringList &CC1Args) const { if (!getVFS().exists(Path)) { if (DriverArgs.hasArg(options::OPT_v)) - WithColor::warning(errs(), "Clang") + WithColor::warning(getDriver().getVerboseOutputStream(), "Clang") << "ignoring nonexistent directory \"" << Path << "\"\n"; if (!DriverArgs.hasArg(options::OPT__HASH_HASH_HASH)) return; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 87abcd38c1a92..bf599ef9a11c2 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -504,7 +504,8 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { HeaderSearchTriple = &PP->getAuxTargetInfo()->getTriple(); ApplyHeaderSearchOptions(PP->getHeaderSearchInfo(), getHeaderSearchOpts(), - PP->getLangOpts(), *HeaderSearchTriple); + PP->getLangOpts(), *HeaderSearchTriple, + &getVerboseOutputStream()); PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP); diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 512b28be5a544..543a6a03e81e6 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -269,6 +269,9 @@ IncrementalCompilerBuilder::create(std::string TT, driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags); Driver.setCheckInputsExist(false); // the input comes from mem buffers + llvm::raw_ostream &VerboseOS = + VerboseOutputStream ? *VerboseOutputStream : llvm::errs(); + Driver.setVerboseOutputStream(VerboseOS); llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv); std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF)); @@ -277,13 +280,16 @@ IncrementalCompilerBuilder::create(std::string TT, return std::move(Err); if (Compilation->getArgs().hasArg(options::OPT_v)) - Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false); + Compilation->getJobs().Print(VerboseOS, "\n", /*Quote=*/false); auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get()); if (auto Err = ErrOrCC1Args.takeError()) return std::move(Err); - return CreateCI(**ErrOrCC1Args); + auto CI = CreateCI(**ErrOrCC1Args); + if (CI) + (*CI)->setVerboseOutputStream(VerboseOS); + return CI; } llvm::Expected<std::unique_ptr<CompilerInstance>> diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index e894086b66e76..5dba00b330ce6 100644 --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -47,13 +47,16 @@ class InitHeaderSearch { std::vector<DirectoryLookupInfo> IncludePath; std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes; HeaderSearch &Headers; + llvm::raw_ostream &VerboseOutput; bool Verbose; std::string IncludeSysroot; bool HasSysroot; public: - InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) - : Headers(HS), Verbose(verbose), IncludeSysroot(std::string(sysroot)), + InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot, + llvm::raw_ostream &VerboseOutput) + : Headers(HS), VerboseOutput(VerboseOutput), Verbose(verbose), + IncludeSysroot(std::string(sysroot)), HasSysroot(!(sysroot.empty() || sysroot == "/")) {} /// Add the specified path to the specified group list, prefixing the sysroot @@ -165,8 +168,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, } if (Verbose) - llvm::errs() << "ignoring nonexistent directory \"" - << MappedPathStr << "\"\n"; + VerboseOutput << "ignoring nonexistent directory \"" << MappedPathStr + << "\"\n"; return false; } @@ -282,7 +285,8 @@ void InitHeaderSearch::AddDefaultIncludePaths( /// remove the later (dead) ones. Returns the number of non-system headers /// removed, which is used to update NumAngled. static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList, - unsigned First, bool Verbose) { + unsigned First, bool Verbose, + llvm::raw_ostream &VerboseOutput) { llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs; llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs; llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps; @@ -347,11 +351,11 @@ static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList, } if (Verbose) { - llvm::errs() << "ignoring duplicate directory \"" - << CurEntry.getName() << "\"\n"; + VerboseOutput << "ignoring duplicate directory \"" << CurEntry.getName() + << "\"\n"; if (DirToRemove != i) - llvm::errs() << " as it is a non-system directory that duplicates " - << "a system directory\n"; + VerboseOutput << " as it is a non-system directory that duplicates " + << "a system directory\n"; } if (DirToRemove != i) ++NonSystemRemoved; @@ -397,14 +401,14 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { SearchList.push_back(Include); // Deduplicate and remember index. - RemoveDuplicates(SearchList, 0, Verbose); + RemoveDuplicates(SearchList, 0, Verbose, VerboseOutput); unsigned NumQuoted = SearchList.size(); for (auto &Include : IncludePath) if (Include.Group == Angled) SearchList.push_back(Include); - RemoveDuplicates(SearchList, NumQuoted, Verbose); + RemoveDuplicates(SearchList, NumQuoted, Verbose, VerboseOutput); unsigned NumAngled = SearchList.size(); for (auto &Include : IncludePath) @@ -423,7 +427,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { // Remove duplicates across both the Angled and System directories. GCC does // this and failing to remove duplicates across these two groups breaks // #include_next. - unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose); + unsigned NonSystemRemoved = + RemoveDuplicates(SearchList, NumQuoted, Verbose, VerboseOutput); NumAngled -= NonSystemRemoved; Headers.SetSearchPaths(extractLookups(SearchList), NumQuoted, NumAngled, @@ -433,10 +438,10 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { // If verbose, print the list of directories that will be searched. if (Verbose) { - llvm::errs() << "#include \"...\" search starts here:\n"; + VerboseOutput << "#include \"...\" search starts here:\n"; for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { if (i == NumQuoted) - llvm::errs() << "#include <...> search starts here:\n"; + VerboseOutput << "#include <...> search starts here:\n"; StringRef Name = SearchList[i].Lookup.getName(); const char *Suffix; if (SearchList[i].Lookup.isNormalDir()) @@ -447,17 +452,19 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { assert(SearchList[i].Lookup.isHeaderMap() && "Unknown DirectoryLookup"); Suffix = " (headermap)"; } - llvm::errs() << " " << Name << Suffix << "\n"; + VerboseOutput << " " << Name << Suffix << "\n"; } - llvm::errs() << "End of search list.\n"; + VerboseOutput << "End of search list.\n"; } } void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, const HeaderSearchOptions &HSOpts, const LangOptions &Lang, - const llvm::Triple &Triple) { - InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); + const llvm::Triple &Triple, + llvm::raw_ostream *VerboseOutput) { + InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot, + VerboseOutput ? *VerboseOutput : llvm::errs()); // Add the user defined entries. for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 71307d1fe7307..a9eeec8cf550b 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -372,6 +372,9 @@ bool ToolInvocation::run() { for (const std::string &Str : CommandLine) Argv.push_back(Str.c_str()); const char *const BinaryName = Argv[0]; + llvm::raw_ostream &VerboseOS = + VerboseOutputStream ? *VerboseOutputStream : llvm::errs(); + Action->setVerboseOutputStream(VerboseOS); // Parse diagnostic options from the driver command-line only if none were // explicitly set. @@ -405,6 +408,7 @@ bool ToolInvocation::run() { const std::unique_ptr<driver::Driver> Driver( newDriver(&*Diagnostics, BinaryName, Files->getVirtualFileSystemPtr())); + Driver->setVerboseOutputStream(VerboseOS); // The "input file not found" diagnostics from the driver are useful. // The driver is only aware of the VFS working directory, but some clients // change this at the FileManager level instead. @@ -431,9 +435,11 @@ bool ToolInvocation::runInvocation( std::shared_ptr<PCHContainerOperations> PCHContainerOps) { // Show the invocation, with -v. if (Invocation->getHeaderSearchOpts().Verbose) { - llvm::errs() << "clang Invocation:\n"; - Compilation->getJobs().Print(llvm::errs(), "\n", true); - llvm::errs() << "\n"; + llvm::raw_ostream &OS = + VerboseOutputStream ? *VerboseOutputStream : llvm::errs(); + OS << "clang Invocation:\n"; + Compilation->getJobs().Print(OS, "\n", true); + OS << "\n"; } return Action->runInvocation(std::move(Invocation), Files, @@ -446,6 +452,8 @@ bool FrontendActionFactory::runInvocation( DiagnosticConsumer *DiagConsumer) { // Create a compiler instance to handle the actual work. CompilerInstance Compiler(std::move(Invocation), std::move(PCHContainerOps)); + if (llvm::raw_ostream *OS = getVerboseOutputStream()) + Compiler.setVerboseOutputStream(*OS); Compiler.setVirtualFileSystem(Files->getVirtualFileSystemPtr()); Compiler.setFileManager(Files); Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); @@ -627,6 +635,8 @@ int ClangTool::run(ToolAction *Action) { ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(), PCHContainerOps); Invocation.setDiagnosticConsumer(DiagConsumer); + if (VerboseOutputStream) + Invocation.setVerboseOutputStream(*VerboseOutputStream); if (!Invocation.run()) { // FIXME: Diagnostics should be used instead. diff --git a/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp b/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp index 7b4633bfc9e7a..175f4f8392f5e 100644 --- a/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp +++ b/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp @@ -6,11 +6,14 @@ // //===----------------------------------------------------------------------===// +#include "InterpreterTestFixture.h" + #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Interpreter/Interpreter.h" #include "clang/Lex/PreprocessorOptions.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" using namespace llvm; @@ -18,6 +21,8 @@ using namespace clang; namespace { +class IncrementalCompilerBuilderInterpreterTest : public InterpreterTestBase {}; + // Usually FrontendAction takes the raw pointers and wraps them back into // unique_ptrs in InitializeFileRemapping() static void cleanupRemappedFileBuffers(CompilerInstance &CI) { @@ -36,6 +41,28 @@ TEST(IncrementalCompilerBuilder, SetCompilerArgs) { cleanupRemappedFileBuffers(*CI); } +TEST_F(IncrementalCompilerBuilderInterpreterTest, SetVerboseOutputStream) { + std::string Output; + llvm::raw_string_ostream OS(Output); + std::vector<const char *> ClangArgv = {"-v", "-nostdinc", "-nostdinc++"}; + auto CB = clang::IncrementalCompilerBuilder(); + CB.SetCompilerArgs(ClangArgv); + CB.SetVerboseOutputStream(OS); + + auto CI = cantFail(CB.CreateCpp()); + OS.flush(); + EXPECT_NE(Output.find("clang version"), std::string::npos); + EXPECT_NE(Output.find("-cc1"), std::string::npos); + + auto Interp = cantFail(clang::Interpreter::create(std::move(CI))); + OS.flush(); + EXPECT_NE(Output.find("clang -cc1 version"), std::string::npos); + EXPECT_NE(Output.find("#include \"...\" search starts here:"), + std::string::npos); + EXPECT_NE(Output.find("End of search list."), std::string::npos); + cleanupRemappedFileBuffers(*Interp->getCompilerInstance()); +} + TEST(IncrementalCompilerBuilder, SetTargetTriple) { // FIXME : This test doesn't current work for Emscripten builds. // It should be possible to make it work.For details on how it fails and diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp index 11a5491dd35fb..2648a1c5d372a 100644 --- a/clang/unittests/Tooling/ToolingTest.cpp +++ b/clang/unittests/Tooling/ToolingTest.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Host.h" #include "gtest/gtest.h" #include <algorithm> @@ -56,6 +57,23 @@ class TestAction : public clang::ASTFrontendAction { std::unique_ptr<clang::ASTConsumer> TestConsumer; }; +class VerifyVerboseOutputAction : public ToolAction { +public: + VerifyVerboseOutputAction(llvm::raw_ostream &Expected, bool &Observed) + : Expected(Expected), Observed(Observed) {} + + bool runInvocation(std::shared_ptr<CompilerInvocation>, FileManager *, + std::shared_ptr<PCHContainerOperations>, + DiagnosticConsumer *) override { + Observed = getVerboseOutputStream() == &Expected; + return true; + } + +private: + llvm::raw_ostream &Expected; + bool &Observed; +}; + class FindTopLevelDeclConsumer : public clang::ASTConsumer { public: explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl) @@ -226,6 +244,54 @@ TEST(ToolInvocation, TestMapVirtualFile) { EXPECT_TRUE(Invocation.run()); } +TEST(ToolInvocation, VerboseOutputStream) { + auto OverlayFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>( + llvm::vfs::getRealFileSystem()); + auto InMemoryFileSystem = + llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + auto Files = llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), + OverlayFileSystem); + InMemoryFileSystem->addFile("test.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("int value;\n")); + + std::vector<std::string> Args = {"tool-executable", "-v", "-fsyntax-only", + "test.cpp"}; + ToolInvocation Invocation(Args, std::make_unique<SyntaxOnlyAction>(), + Files.get()); + std::string Output; + llvm::raw_string_ostream OS(Output); + Invocation.setVerboseOutputStream(OS); + + EXPECT_TRUE(Invocation.run()); + OS.flush(); + EXPECT_NE(Output.find("clang version"), std::string::npos); + EXPECT_NE(Output.find("clang Invocation:"), std::string::npos); + EXPECT_NE(Output.find("-cc1"), std::string::npos); + EXPECT_NE(Output.find("clang -cc1 version"), std::string::npos); + EXPECT_NE(Output.find("End of search list."), std::string::npos); +} + +TEST(ToolInvocation, PropagatesVerboseOutputStreamToToolAction) { + auto FileSystem = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); + FileSystem->addFile("test.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("int value;\n")); + FileManager Files(FileSystemOptions(), FileSystem); + std::string Output; + llvm::raw_string_ostream OS(Output); + bool Observed = false; + VerifyVerboseOutputAction Action(OS, Observed); + std::vector<std::string> Args = {"tool-executable", "-v", "-fsyntax-only", + "test.cpp"}; + ToolInvocation Invocation(Args, &Action, &Files, + std::make_shared<PCHContainerOperations>()); + Invocation.setVerboseOutputStream(OS); + + EXPECT_TRUE(Invocation.run()); + EXPECT_TRUE(Observed); +} + TEST(ToolInvocation, TestVirtualModulesCompilation) { // FIXME: Currently, this only tests that we don't exit with an error if a // mapped module.modulemap is found on the include path. In the future, expand _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
