<div dir="ltr"><div><span style="font-size:13px">Wow, I'm just seeing this through its use on D7289. This is so great! Is there some way we can draw more attention to this? Docs?</span><br></div><div><span style="font-size:13px"><br></span></div><div><span style="font-size:13px">-- Sean Silva</span></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 6, 2013 at 8:12 PM, Peter Collingbourne <span dir="ltr"><<a href="mailto:peter@pcc.me.uk" target="_blank">peter@pcc.me.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: pcc<br>
Date: Wed Nov  6 14:12:45 2013<br>
New Revision: 194164<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=194164&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=194164&view=rev</a><br>
Log:<br>
Introduce ClangTool::buildASTs, and buildASTFromCode.<br>
<br>
These allow clients to retrieve persistent AST objects (ASTUnits) which<br>
can be used in an ad-hoc manner after parsing.<br>
<br>
To accommodate this change, the code for processing a CompilerInvocation<br>
using a FrontendAction has been factored out to FrontendActionFactory, and<br>
a new base class, ToolAction, has been introduced, allowing the tool to do<br>
arbitrary things with each CompilerInvocation.  This change was necessary<br>
because ASTUnit does not use the FrontendAction interface directly.<br>
<br>
This change also causes the FileManager in ClangTool to use shared ownership.<br>
This will become necessary because ASTUnit takes shared ownership of<br>
FileManager (ClangTool's FileManager is currently unused by ASTUnit; this<br>
is a FIXME).  As shown in the tests, any client of ToolInvocation will<br>
need to be modified to use shared ownership for FileManager.<br>
<br>
Differential Revision: <a href="http://llvm-reviews.chandlerc.com/D2097" target="_blank">http://llvm-reviews.chandlerc.com/D2097</a><br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Tooling/Tooling.h<br>
    cfe/trunk/lib/Tooling/Tooling.cpp<br>
    cfe/trunk/unittests/Tooling/ToolingTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Tooling/Tooling.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Tooling.h?rev=194164&r1=194163&r2=194164&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Tooling.h?rev=194164&r1=194163&r2=194164&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Tooling/Tooling.h (original)<br>
+++ cfe/trunk/include/clang/Tooling/Tooling.h Wed Nov  6 14:12:45 2013<br>
@@ -53,14 +53,33 @@ class FrontendAction;<br>
<br>
 namespace tooling {<br>
<br>
+/// \brief Interface to process a clang::CompilerInvocation.<br>
+///<br>
+/// If your tool is based on FrontendAction, you should be deriving from<br>
+/// FrontendActionFactory instead.<br>
+class ToolAction {<br>
+public:<br>
+  virtual ~ToolAction();<br>
+<br>
+  /// \brief Perform an action for an invocation.<br>
+  virtual bool runInvocation(clang::CompilerInvocation *Invocation,<br>
+                             FileManager *Files) = 0;<br>
+};<br>
+<br>
 /// \brief Interface to generate clang::FrontendActions.<br>
 ///<br>
 /// Having a factory interface allows, for example, a new FrontendAction to be<br>
-/// created for each translation unit processed by ClangTool.<br>
-class FrontendActionFactory {<br>
+/// created for each translation unit processed by ClangTool.  This class is<br>
+/// also a ToolAction which uses the FrontendActions created by create() to<br>
+/// process each translation unit.<br>
+class FrontendActionFactory : public ToolAction {<br>
 public:<br>
   virtual ~FrontendActionFactory();<br>
<br>
+  /// \brief Invokes the compiler with a FrontendAction created by create().<br>
+  bool runInvocation(clang::CompilerInvocation *Invocation,<br>
+                     FileManager *Files);<br>
+<br>
   /// \brief Returns a new clang::FrontendAction.<br>
   ///<br>
   /// The caller takes ownership of the returned action.<br>
@@ -133,6 +152,26 @@ bool runToolOnCodeWithArgs(clang::Fronte<br>
                            const std::vector<std::string> &Args,<br>
                            const Twine &FileName = "input.cc");<br>
<br>
+/// \brief Builds an AST for 'Code'.<br>
+///<br>
+/// \param Code C++ code.<br>
+/// \param FileName The file name which 'Code' will be mapped as.<br>
+///<br>
+/// \return The resulting AST or null if an error occurred.<br>
+ASTUnit *buildASTFromCode(const Twine &Code,<br>
+                          const Twine &FileName = "input.cc");<br>
+<br>
+/// \brief Builds an AST for 'Code' with additional flags.<br>
+///<br>
+/// \param Code C++ code.<br>
+/// \param Args Additional flags to pass on.<br>
+/// \param FileName The file name which 'Code' will be mapped as.<br>
+///<br>
+/// \return The resulting AST or null if an error occurred.<br>
+ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,<br>
+                                  const std::vector<std::string> &Args,<br>
+                                  const Twine &FileName = "input.cc");<br>
+<br>
 /// \brief Utility to run a FrontendAction in a single clang invocation.<br>
 class ToolInvocation {<br>
  public:<br>
@@ -145,9 +184,19 @@ class ToolInvocation {<br>
   /// \param ToolAction The action to be executed. Class takes ownership.<br>
   /// \param Files The FileManager used for the execution. Class does not take<br>
   /// ownership.<br>
-  ToolInvocation(ArrayRef<std::string> CommandLine, FrontendAction *ToolAction,<br>
+  ToolInvocation(ArrayRef<std::string> CommandLine, FrontendAction *FAction,<br>
                  FileManager *Files);<br>
<br>
+  /// \brief Create a tool invocation.<br>
+  ///<br>
+  /// \param CommandLine The command line arguments to clang.<br>
+  /// \param Action The action to be executed.<br>
+  /// \param Files The FileManager used for the execution.<br>
+  ToolInvocation(ArrayRef<std::string> CommandLine, ToolAction *Action,<br>
+                 FileManager *Files);<br>
+<br>
+  ~ToolInvocation();<br>
+<br>
   /// \brief Map a virtual file to be used while running the tool.<br>
   ///<br>
   /// \param FilePath The path at which the content will be mapped.<br>
@@ -167,7 +216,8 @@ class ToolInvocation {<br>
                      clang::CompilerInvocation *Invocation);<br>
<br>
   std::vector<std::string> CommandLine;<br>
-  OwningPtr<FrontendAction> ToolAction;<br>
+  ToolAction *Action;<br>
+  bool OwnsAction;<br>
   FileManager *Files;<br>
   // Maps <file name> -> <file content>.<br>
   llvm::StringMap<StringRef> MappedFileContents;<br>
@@ -216,23 +266,25 @@ class ClangTool {<br>
   /// \brief Clear the command line arguments adjuster chain.<br>
   void clearArgumentsAdjusters();<br>
<br>
-  /// Runs a frontend action over all files specified in the command line.<br>
+  /// Runs an action over all files specified in the command line.<br>
   ///<br>
-  /// \param ActionFactory Factory generating the frontend actions. The function<br>
-  /// takes ownership of this parameter. A new action is generated for every<br>
-  /// processed translation unit.<br>
-  virtual int run(FrontendActionFactory *ActionFactory);<br>
+  /// \param Action Tool action.<br>
+  int run(ToolAction *Action);<br>
+<br>
+  /// \brief Create an AST for each file specified in the command line and<br>
+  /// append them to ASTs.<br>
+  int buildASTs(std::vector<ASTUnit *> &ASTs);<br>
<br>
   /// \brief Returns the file manager used in the tool.<br>
   ///<br>
   /// The file manager is shared between all translation units.<br>
-  FileManager &getFiles() { return Files; }<br>
+  FileManager &getFiles() { return *Files; }<br>
<br>
  private:<br>
   // We store compile commands as pair (file name, compile command).<br>
   std::vector< std::pair<std::string, CompileCommand> > CompileCommands;<br>
<br>
-  FileManager Files;<br>
+  llvm::IntrusiveRefCntPtr<FileManager> Files;<br>
   // Contains a list of pairs (<file name>, <file content>).<br>
   std::vector< std::pair<StringRef, StringRef> > MappedFileContents;<br>
<br>
<br>
Modified: cfe/trunk/lib/Tooling/Tooling.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Tooling.cpp?rev=194164&r1=194163&r2=194164&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Tooling.cpp?rev=194164&r1=194163&r2=194164&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Tooling/Tooling.cpp (original)<br>
+++ cfe/trunk/lib/Tooling/Tooling.cpp Wed Nov  6 14:12:45 2013<br>
@@ -13,9 +13,11 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "clang/Tooling/Tooling.h"<br>
+#include "clang/AST/ASTConsumer.h"<br>
 #include "clang/Driver/Compilation.h"<br>
 #include "clang/Driver/Driver.h"<br>
 #include "clang/Driver/Tool.h"<br>
+#include "clang/Frontend/ASTUnit.h"<br>
 #include "clang/Frontend/CompilerInstance.h"<br>
 #include "clang/Frontend/FrontendDiagnostic.h"<br>
 #include "clang/Frontend/TextDiagnosticPrinter.h"<br>
@@ -38,6 +40,8 @@<br>
 namespace clang {<br>
 namespace tooling {<br>
<br>
+ToolAction::~ToolAction() {}<br>
+<br>
 FrontendActionFactory::~FrontendActionFactory() {}<br>
<br>
 // FIXME: This file contains structural duplication with other parts of the<br>
@@ -104,18 +108,26 @@ bool runToolOnCode(clang::FrontendAction<br>
       ToolAction, Code, std::vector<std::string>(), FileName);<br>
 }<br>
<br>
+static std::vector<std::string><br>
+getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs,<br>
+                      StringRef FileName) {<br>
+  std::vector<std::string> Args;<br>
+  Args.push_back("clang-tool");<br>
+  Args.push_back("-fsyntax-only");<br>
+  Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());<br>
+  Args.push_back(FileName.str());<br>
+  return Args;<br>
+}<br>
+<br>
 bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,<br>
                            const std::vector<std::string> &Args,<br>
                            const Twine &FileName) {<br>
   SmallString<16> FileNameStorage;<br>
   StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);<br>
-  std::vector<std::string> Commands;<br>
-  Commands.push_back("clang-tool");<br>
-  Commands.push_back("-fsyntax-only");<br>
-  Commands.insert(Commands.end(), Args.begin(), Args.end());<br>
-  Commands.push_back(FileNameRef.data());<br>
-  FileManager Files((FileSystemOptions()));<br>
-  ToolInvocation Invocation(Commands, ToolAction, &Files);<br>
+  llvm::IntrusiveRefCntPtr<FileManager> Files(<br>
+      new FileManager(FileSystemOptions()));<br>
+  ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction,<br>
+                            Files.getPtr());<br>
<br>
   SmallString<1024> CodeStorage;<br>
   Invocation.mapVirtualFile(FileNameRef,<br>
@@ -138,10 +150,33 @@ std::string getAbsolutePath(StringRef Fi<br>
   return AbsolutePath.str();<br>
 }<br>
<br>
-ToolInvocation::ToolInvocation(<br>
-    ArrayRef<std::string> CommandLine, FrontendAction *ToolAction,<br>
-    FileManager *Files)<br>
-    : CommandLine(CommandLine.vec()), ToolAction(ToolAction), Files(Files) {<br>
+namespace {<br>
+<br>
+class SingleFrontendActionFactory : public FrontendActionFactory {<br>
+  FrontendAction *Action;<br>
+<br>
+public:<br>
+  SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {}<br>
+<br>
+  FrontendAction *create() { return Action; }<br>
+};<br>
+<br>
+}<br>
+<br>
+ToolInvocation::ToolInvocation(ArrayRef<std::string> CommandLine,<br>
+                               ToolAction *Action, FileManager *Files)<br>
+    : CommandLine(CommandLine.vec()), Action(Action), OwnsAction(false),<br>
+      Files(Files) {}<br>
+<br>
+ToolInvocation::ToolInvocation(ArrayRef<std::string> CommandLine,<br>
+                               FrontendAction *FAction, FileManager *Files)<br>
+    : CommandLine(CommandLine.vec()),<br>
+      Action(new SingleFrontendActionFactory(FAction)), OwnsAction(true),<br>
+      Files(Files) {}<br>
+<br>
+ToolInvocation::~ToolInvocation() {<br>
+  if (OwnsAction)<br>
+    delete Action;<br>
 }<br>
<br>
 void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {<br>
@@ -175,6 +210,14 @@ bool ToolInvocation::run() {<br>
   }<br>
   OwningPtr<clang::CompilerInvocation> Invocation(<br>
       newInvocation(&Diagnostics, *CC1Args));<br>
+  for (llvm::StringMap<StringRef>::const_iterator<br>
+           It = MappedFileContents.begin(), End = MappedFileContents.end();<br>
+       It != End; ++It) {<br>
+    // Inject the code as the given file name into the preprocessor options.<br>
+    const llvm::MemoryBuffer *Input =<br>
+        llvm::MemoryBuffer::getMemBuffer(It->getValue());<br>
+    Invocation->getPreprocessorOpts().addRemappedFile(It->getKey(), Input);<br>
+  }<br>
   return runInvocation(BinaryName, Compilation.get(), Invocation.take());<br>
 }<br>
<br>
@@ -189,16 +232,20 @@ bool ToolInvocation::runInvocation(<br>
     llvm::errs() << "\n";<br>
   }<br>
<br>
+  return Action->runInvocation(Invocation, Files);<br>
+}<br>
+<br>
+bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,<br>
+                                          FileManager *Files) {<br>
   // Create a compiler instance to handle the actual work.<br>
   clang::CompilerInstance Compiler;<br>
   Compiler.setInvocation(Invocation);<br>
   Compiler.setFileManager(Files);<br>
-  // FIXME: What about LangOpts?<br>
<br>
-  // ToolAction can have lifetime requirements for Compiler or its members, and<br>
-  // we need to ensure it's deleted earlier than Compiler. So we pass it to an<br>
-  // OwningPtr declared after the Compiler variable.<br>
-  OwningPtr<FrontendAction> ScopedToolAction(ToolAction.take());<br>
+  // The FrontendAction can have lifetime requirements for Compiler or its<br>
+  // members, and we need to ensure it's deleted earlier than Compiler. So we<br>
+  // pass it to an OwningPtr declared after the Compiler variable.<br>
+  OwningPtr<FrontendAction> ScopedToolAction(create());<br>
<br>
   // Create the compilers actual diagnostics engine.<br>
   Compiler.createDiagnostics();<br>
@@ -206,32 +253,16 @@ bool ToolInvocation::runInvocation(<br>
     return false;<br>
<br>
   Compiler.createSourceManager(*Files);<br>
-  addFileMappingsTo(Compiler.getSourceManager());<br>
<br>
   const bool Success = Compiler.ExecuteAction(*ScopedToolAction);<br>
<br>
-  Compiler.resetAndLeakFileManager();<br>
   Files->clearStatCaches();<br>
   return Success;<br>
 }<br>
<br>
-void ToolInvocation::addFileMappingsTo(SourceManager &Sources) {<br>
-  for (llvm::StringMap<StringRef>::const_iterator<br>
-           It = MappedFileContents.begin(), End = MappedFileContents.end();<br>
-       It != End; ++It) {<br>
-    // Inject the code as the given file name into the preprocessor options.<br>
-    const llvm::MemoryBuffer *Input =<br>
-        llvm::MemoryBuffer::getMemBuffer(It->getValue());<br>
-    // FIXME: figure out what '0' stands for.<br>
-    const FileEntry *FromFile = Files->getVirtualFile(<br>
-        It->getKey(), Input->getBufferSize(), 0);<br>
-    Sources.overrideFileContents(FromFile, Input);<br>
-  }<br>
-}<br>
-<br>
 ClangTool::ClangTool(const CompilationDatabase &Compilations,<br>
                      ArrayRef<std::string> SourcePaths)<br>
-    : Files((FileSystemOptions())) {<br>
+    : Files(new FileManager(FileSystemOptions())) {<br>
   ArgsAdjusters.push_back(new ClangStripOutputAdjuster());<br>
   ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster());<br>
   for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {<br>
@@ -274,7 +305,7 @@ void ClangTool::clearArgumentsAdjusters(<br>
   ArgsAdjusters.clear();<br>
 }<br>
<br>
-int ClangTool::run(FrontendActionFactory *ActionFactory) {<br>
+int ClangTool::run(ToolAction *Action) {<br>
   // Exists solely for the purpose of lookup of the resource path.<br>
   // This just needs to be some symbol in the binary.<br>
   static int StaticSymbol;<br>
@@ -309,7 +340,7 @@ int ClangTool::run(FrontendActionFactory<br>
     DEBUG({<br>
       llvm::dbgs() << "Processing: " << File << ".\n";<br>
     });<br>
-    ToolInvocation Invocation(CommandLine, ActionFactory->create(), &Files);<br>
+    ToolInvocation Invocation(CommandLine, Action, Files.getPtr());<br>
     for (int I = 0, E = MappedFileContents.size(); I != E; ++I) {<br>
       Invocation.mapVirtualFile(MappedFileContents[I].first,<br>
                                 MappedFileContents[I].second);<br>
@@ -323,5 +354,58 @@ int ClangTool::run(FrontendActionFactory<br>
   return ProcessingFailed ? 1 : 0;<br>
 }<br>
<br>
+namespace {<br>
+<br>
+class ASTBuilderAction : public ToolAction {<br>
+  std::vector<ASTUnit *> &ASTs;<br>
+<br>
+public:<br>
+  ASTBuilderAction(std::vector<ASTUnit *> &ASTs) : ASTs(ASTs) {}<br>
+<br>
+  bool runInvocation(CompilerInvocation *Invocation,<br>
+                     FileManager *Files) {<br>
+    // FIXME: This should use the provided FileManager.<br>
+    ASTUnit *AST = ASTUnit::LoadFromCompilerInvocation(<br>
+        Invocation,<br>
+        CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts()));<br>
+    if (!AST)<br>
+      return false;<br>
+<br>
+    ASTs.push_back(AST);<br>
+    return true;<br>
+  }<br>
+};<br>
+<br>
+}<br>
+<br>
+int ClangTool::buildASTs(std::vector<ASTUnit *> &ASTs) {<br>
+  ASTBuilderAction Action(ASTs);<br>
+  return run(&Action);<br>
+}<br>
+<br>
+ASTUnit *buildASTFromCode(const Twine &Code, const Twine &FileName) {<br>
+  return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName);<br>
+}<br>
+<br>
+ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,<br>
+                                  const std::vector<std::string> &Args,<br>
+                                  const Twine &FileName) {<br>
+  SmallString<16> FileNameStorage;<br>
+  StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);<br>
+<br>
+  std::vector<ASTUnit *> ASTs;<br>
+  ASTBuilderAction Action(ASTs);<br>
+  ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action, 0);<br>
+<br>
+  SmallString<1024> CodeStorage;<br>
+  Invocation.mapVirtualFile(FileNameRef,<br>
+                            Code.toNullTerminatedStringRef(CodeStorage));<br>
+  if (!Invocation.run())<br>
+    return 0;<br>
+<br>
+  assert(ASTs.size() == 1);<br>
+  return ASTs[0];<br>
+}<br>
+<br>
 } // end namespace tooling<br>
 } // end namespace clang<br>
<br>
Modified: cfe/trunk/unittests/Tooling/ToolingTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ToolingTest.cpp?rev=194164&r1=194163&r2=194164&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ToolingTest.cpp?rev=194164&r1=194163&r2=194164&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/unittests/Tooling/ToolingTest.cpp (original)<br>
+++ cfe/trunk/unittests/Tooling/ToolingTest.cpp Wed Nov  6 14:12:45 2013<br>
@@ -10,12 +10,14 @@<br>
 #include "clang/AST/ASTConsumer.h"<br>
 #include "clang/AST/DeclCXX.h"<br>
 #include "clang/AST/DeclGroup.h"<br>
+#include "clang/Frontend/ASTUnit.h"<br>
 #include "clang/Frontend/CompilerInstance.h"<br>
 #include "clang/Frontend/FrontendAction.h"<br>
 #include "clang/Frontend/FrontendActions.h"<br>
 #include "clang/Tooling/CompilationDatabase.h"<br>
 #include "clang/Tooling/Tooling.h"<br>
 #include "gtest/gtest.h"<br>
+#include "llvm/ADT/STLExtras.h"<br>
 #include <string><br>
<br>
 namespace clang {<br>
@@ -83,6 +85,18 @@ class FindClassDeclXConsumer : public cl<br>
  private:<br>
   bool *FoundClassDeclX;<br>
 };<br>
+bool FindClassDeclX(ASTUnit *AST) {<br>
+  for (std::vector<Decl *>::iterator i = AST->top_level_begin(),<br>
+                                     e = AST->top_level_end();<br>
+       i != e; ++i) {<br>
+    if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {<br>
+      if (Record->getName() == "X") {<br>
+        return true;<br>
+      }<br>
+    }<br>
+  }<br>
+  return false;<br>
+}<br>
 } // end namespace<br>
<br>
 TEST(runToolOnCode, FindsClassDecl) {<br>
@@ -97,6 +111,16 @@ TEST(runToolOnCode, FindsClassDecl) {<br>
   EXPECT_FALSE(FoundClassDeclX);<br>
 }<br>
<br>
+TEST(buildASTFromCode, FindsClassDecl) {<br>
+  OwningPtr<ASTUnit> AST(buildASTFromCode("class X;"));<br>
+  ASSERT_TRUE(AST.get());<br>
+  EXPECT_TRUE(FindClassDeclX(AST.get()));<br>
+<br>
+  AST.reset(buildASTFromCode("class Y;"));<br>
+  ASSERT_TRUE(AST.get());<br>
+  EXPECT_FALSE(FindClassDeclX(AST.get()));<br>
+}<br>
+<br>
 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {<br>
   OwningPtr<FrontendActionFactory> Factory(<br>
       newFrontendActionFactory<SyntaxOnlyAction>());<br>
@@ -119,13 +143,15 @@ TEST(newFrontendActionFactory, CreatesFr<br>
 }<br>
<br>
 TEST(ToolInvocation, TestMapVirtualFile) {<br>
-  clang::FileManager Files((clang::FileSystemOptions()));<br>
+  IntrusiveRefCntPtr<clang::FileManager> Files(<br>
+      new clang::FileManager(clang::FileSystemOptions()));<br>
   std::vector<std::string> Args;<br>
   Args.push_back("tool-executable");<br>
   Args.push_back("-Idef");<br>
   Args.push_back("-fsyntax-only");<br>
   Args.push_back("test.cpp");<br>
-  clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, &Files);<br>
+  clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,<br>
+                                            Files.getPtr());<br>
   Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");<br>
   Invocation.mapVirtualFile("def/abc", "\n");<br>
   EXPECT_TRUE(Invocation.run());<br>
@@ -136,13 +162,15 @@ TEST(ToolInvocation, TestVirtualModulesC<br>
   // mapped module.map is found on the include path. In the future, expand this<br>
   // test to run a full modules enabled compilation, so we make sure we can<br>
   // rerun modules compilations with a virtual file system.<br>
-  clang::FileManager Files((clang::FileSystemOptions()));<br>
+  IntrusiveRefCntPtr<clang::FileManager> Files(<br>
+      new clang::FileManager(clang::FileSystemOptions()));<br>
   std::vector<std::string> Args;<br>
   Args.push_back("tool-executable");<br>
   Args.push_back("-Idef");<br>
   Args.push_back("-fsyntax-only");<br>
   Args.push_back("test.cpp");<br>
-  clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, &Files);<br>
+  clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,<br>
+                                            Files.getPtr());<br>
   Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");<br>
   Invocation.mapVirtualFile("def/abc", "\n");<br>
   // Add a module.map file in the include directory of our header, so we trigger<br>
@@ -254,5 +282,23 @@ TEST(ClangToolTest, ArgumentAdjusters) {<br>
   EXPECT_FALSE(Found);<br>
 }<br>
<br>
+TEST(ClangToolTest, BuildASTs) {<br>
+  FixedCompilationDatabase Compilations("/", std::vector<std::string>());<br>
+<br>
+  std::vector<std::string> Sources;<br>
+  Sources.push_back("/a.cc");<br>
+  Sources.push_back("/b.cc");<br>
+  ClangTool Tool(Compilations, Sources);<br>
+<br>
+  Tool.mapVirtualFile("/a.cc", "void a() {}");<br>
+  Tool.mapVirtualFile("/b.cc", "void b() {}");<br>
+<br>
+  std::vector<ASTUnit *> ASTs;<br>
+  EXPECT_EQ(0, Tool.buildASTs(ASTs));<br>
+  EXPECT_EQ(2u, ASTs.size());<br>
+<br>
+  llvm::DeleteContainerPointers(ASTs);<br>
+}<br>
+<br>
 } // end namespace tooling<br>
 } // end namespace clang<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>