From fa8e7d344fc6ac9bf464419cc9cc2743b5036047 Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Thu, 7 Nov 2013 23:18:05 +0000 Subject: [PATCH] Adds the ability to inject a DiagnosticConsumer into ClangTools. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194226 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Tooling/Tooling.h | 17 +++++++++--- lib/Tooling/Tooling.cpp | 44 +++++++++++++++++++++---------- unittests/Tooling/ToolingTest.cpp | 19 +++++++++++++ 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h index 74253fffae..de507a7a8b 100644 --- a/include/clang/Tooling/Tooling.h +++ b/include/clang/Tooling/Tooling.h @@ -30,6 +30,7 @@ #ifndef LLVM_CLANG_TOOLING_TOOLING_H #define LLVM_CLANG_TOOLING_TOOLING_H +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/Util.h" @@ -63,7 +64,8 @@ public: /// \brief Perform an action for an invocation. virtual bool runInvocation(clang::CompilerInvocation *Invocation, - FileManager *Files) = 0; + FileManager *Files, + DiagnosticConsumer *DiagConsumer) = 0; }; /// \brief Interface to generate clang::FrontendActions. @@ -77,8 +79,8 @@ public: virtual ~FrontendActionFactory(); /// \brief Invokes the compiler with a FrontendAction created by create(). - bool runInvocation(clang::CompilerInvocation *Invocation, - FileManager *Files); + bool runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files, + DiagnosticConsumer *DiagConsumer); /// \brief Returns a new clang::FrontendAction. /// @@ -197,6 +199,9 @@ class ToolInvocation { ~ToolInvocation(); + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer); + /// \brief Map a virtual file to be used while running the tool. /// /// \param FilePath The path at which the content will be mapped. @@ -221,6 +226,7 @@ class ToolInvocation { FileManager *Files; // Maps -> . llvm::StringMap MappedFileContents; + DiagnosticConsumer *DiagConsumer; }; /// \brief Utility to run a FrontendAction over a set of files. @@ -243,6 +249,9 @@ class ClangTool { virtual ~ClangTool() { clearArgumentsAdjusters(); } + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer); + /// \brief Map a virtual file to be used while running the tool. /// /// \param FilePath The path at which the content will be mapped. @@ -289,6 +298,8 @@ class ClangTool { std::vector< std::pair > MappedFileContents; SmallVector ArgsAdjusters; + + DiagnosticConsumer *DiagConsumer; }; template diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index 576989b454..a58854d1af 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -165,20 +165,29 @@ public: ToolInvocation::ToolInvocation(ArrayRef CommandLine, ToolAction *Action, FileManager *Files) - : CommandLine(CommandLine.vec()), Action(Action), OwnsAction(false), - Files(Files) {} + : CommandLine(CommandLine.vec()), + Action(Action), + OwnsAction(false), + Files(Files), + DiagConsumer(NULL) {} ToolInvocation::ToolInvocation(ArrayRef CommandLine, FrontendAction *FAction, FileManager *Files) : CommandLine(CommandLine.vec()), - Action(new SingleFrontendActionFactory(FAction)), OwnsAction(true), - Files(Files) {} + Action(new SingleFrontendActionFactory(FAction)), + OwnsAction(true), + Files(Files), + DiagConsumer(NULL) {} ToolInvocation::~ToolInvocation() { if (OwnsAction) delete Action; } +void ToolInvocation::setDiagnosticConsumer(DiagnosticConsumer *D) { + DiagConsumer = D; +} + void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) { SmallString<1024> PathStorage; llvm::sys::path::native(FilePath, PathStorage); @@ -194,8 +203,8 @@ bool ToolInvocation::run() { TextDiagnosticPrinter DiagnosticPrinter( llvm::errs(), &*DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), - &*DiagOpts, &DiagnosticPrinter, false); + IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); const OwningPtr Driver( newDriver(&Diagnostics, BinaryName)); @@ -232,11 +241,12 @@ bool ToolInvocation::runInvocation( llvm::errs() << "\n"; } - return Action->runInvocation(Invocation, Files); + return Action->runInvocation(Invocation, Files, DiagConsumer); } bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation, - FileManager *Files) { + FileManager *Files, + DiagnosticConsumer *DiagConsumer) { // Create a compiler instance to handle the actual work. clang::CompilerInstance Compiler; Compiler.setInvocation(Invocation); @@ -248,7 +258,7 @@ bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation, OwningPtr ScopedToolAction(create()); // Create the compilers actual diagnostics engine. - Compiler.createDiagnostics(); + Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); if (!Compiler.hasDiagnostics()) return false; @@ -262,7 +272,7 @@ bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation, ClangTool::ClangTool(const CompilationDatabase &Compilations, ArrayRef SourcePaths) - : Files(new FileManager(FileSystemOptions())) { + : Files(new FileManager(FileSystemOptions())), DiagConsumer(NULL) { ArgsAdjusters.push_back(new ClangStripOutputAdjuster()); ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster()); for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) { @@ -286,6 +296,10 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations, } } +void ClangTool::setDiagnosticConsumer(DiagnosticConsumer *D) { + DiagConsumer = D; +} + void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) { MappedFileContents.push_back(std::make_pair(FilePath, Content)); } @@ -341,6 +355,7 @@ int ClangTool::run(ToolAction *Action) { llvm::dbgs() << "Processing: " << File << ".\n"; }); ToolInvocation Invocation(CommandLine, Action, Files.getPtr()); + Invocation.setDiagnosticConsumer(DiagConsumer); for (int I = 0, E = MappedFileContents.size(); I != E; ++I) { Invocation.mapVirtualFile(MappedFileContents[I].first, MappedFileContents[I].second); @@ -362,12 +377,13 @@ class ASTBuilderAction : public ToolAction { public: ASTBuilderAction(std::vector &ASTs) : ASTs(ASTs) {} - bool runInvocation(CompilerInvocation *Invocation, - FileManager *Files) { + bool runInvocation(CompilerInvocation *Invocation, FileManager *Files, + DiagnosticConsumer *DiagConsumer) { // FIXME: This should use the provided FileManager. ASTUnit *AST = ASTUnit::LoadFromCompilerInvocation( - Invocation, - CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts())); + Invocation, CompilerInstance::createDiagnostics( + &Invocation->getDiagnosticOpts(), DiagConsumer, + /*ShouldOwnClient=*/false)); if (!AST) return false; diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp index 25df601df8..40360fb45e 100644 --- a/unittests/Tooling/ToolingTest.cpp +++ b/unittests/Tooling/ToolingTest.cpp @@ -302,5 +302,24 @@ TEST(ClangToolTest, BuildASTs) { } #endif +struct TestDiagnosticConsumer : public DiagnosticConsumer { + TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {} + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + ++NumDiagnosticsSeen; + } + unsigned NumDiagnosticsSeen; +}; + +TEST(ClangToolTest, InjectDiagnosticConsumer) { + FixedCompilationDatabase Compilations("/", std::vector()); + ClangTool Tool(Compilations, std::vector(1, "/a.cc")); + Tool.mapVirtualFile("/a.cc", "int x = undeclared;"); + TestDiagnosticConsumer Consumer; + Tool.setDiagnosticConsumer(&Consumer); + Tool.run(newFrontendActionFactory()); + EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen); +} + } // end namespace tooling } // end namespace clang -- 2.40.0