Redirecting clang tooling errors

Hello,

I am trying to redirect the output emitted when running a tool through clang::tooling::runToolOnCode() to a buffer or string instead of stderr (llvm::errs()). I’m using clangTooling from release 3.9.

When looking at clangTooling code and following the execution flow, I have found the following:
clang::tooling::runToolOnCode()
calls clang::tooling::runToolOnCodeWithArgs()
which calls clang::tooling::ToolInvocation::run()
which contains the following :
TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
IntrusiveRefCntPtrclang::DiagnosticIDs(new DiagnosticIDs()), &*DiagOpts,
DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);

So at this point I guess I’m stuck because everything is redirected to stderr…
Did I miss something or is there really this limitation?

I also thought of redirecting stderr to somewhere else but… I can’t see how it will fit my needs as in the end I want to call clang::tooling::runToolOnCode() on different files in parallel, all of it in the same process ; so I’ll get stderr mixed with output from several executions. The best solution would obviously being able to provide the DiagnosticConsumer but at the moment everything looks hardcoded.

Best regards,
L. Soltic

Considering that there is no other viable possibility, for now I have gone with the following:

using llvm::Twine;
using llvm::SmallString;
using llvm::IntrusiveRefCntPtr;
using llvm::MemoryBuffer;
using clang::FileManager;
using clang::PCHContainerOperations;
using clang::FileSystemOptions;
using clang::tooling::ToolInvocation;
using clang::tooling::FileContentMappings;

static std::vectorstd::string
getSyntaxOnlyToolArgs(const Twine &ToolName,
const std::vectorstd::string &ExtraArgs,
StringRef FileName) {
std::vectorstd::string Args;
Args.push_back(ToolName.str());
Args.push_back("-fsyntax-only");
Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
Args.push_back(FileName.str());
return Args;
}

bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
const Twine &FileName, clang::DiagnosticConsumer& diagConsumer)
{
const std::vectorstd::string args;
const Twine toolName = “clang-tool”;
std::shared_ptr PCHContainerOps = std::make_shared();
const FileContentMappings virtualMappedFiles = FileContentMappings();

SmallString<16> fileNameStorage;
StringRef fileNameRef = FileName.toNullTerminatedStringRef(fileNameStorage);
IntrusiveRefCntPtrclang::vfs::OverlayFileSystem OverlayFileSystem
= new clang::vfs::OverlayFileSystem(clang::vfs::getRealFileSystem());
IntrusiveRefCntPtrclang::vfs::InMemoryFileSystem inMemoryFileSystem
= new clang::vfs::InMemoryFileSystem;
OverlayFileSystem->pushOverlay(inMemoryFileSystem);
IntrusiveRefCntPtr files(new FileManager(FileSystemOptions(), OverlayFileSystem));
ToolInvocation invocation(getSyntaxOnlyToolArgs(toolName, args, fileNameRef),
ToolAction, files.get(), std::move(PCHContainerOps));
invocation.setDiagnosticConsumer(&diagConsumer);

SmallString<1024> codeStorage;
inMemoryFileSystem->addFile(fileNameRef, 0,
MemoryBuffer::getMemBuffer(Code.toNullTerminatedStringRef(codeStorage)));

for (auto &filenameWithContent : virtualMappedFiles) {
inMemoryFileSystem->addFile(filenameWithContent.first, 0,
MemoryBuffer::getMemBuffer(filenameWithContent.second));
}

return invocation.run();
}

It is basically a copy & past of runToolOnCode() but with the added parameter for diagnostic consumer. In the end it was not too much code to duplicate thanks to ToolInvocation::setDiagnosticConsumer() already existing.

Best regards,
L. Soltic