I updated it accordingly to the comments (thanks!).
One of the changes is the replacement of an initializer list through an 
explicit call to the default-constructor of std::vector<std::pair<std::string, 
std::string>>, to initialize the new introduced VirtualMappedFiles-parameter of 
the functions runToolOnCodeWithArgs and matchesConditionally. Due to the 
repeated usage of the type-declaration, it would be nice to declare a typedef 
for std::vector<std::pair<std::string, std::string>>, that could also be used 
for the RemappedFiles-instance-variable of the class PreprocessorOptions. 
If it is appropriate to add the typedef, where should I add it and how should I 
name it?

http://reviews.llvm.org/D4283

Files:
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/Tooling/Tooling.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  lib/Tooling/Tooling.cpp
  unittests/ASTMatchers/ASTMatchersTest.cpp
  unittests/ASTMatchers/ASTMatchersTest.h
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -47,6 +47,7 @@
 
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchersInternal.h"
 #include "clang/ASTMatchers/ASTMatchersMacros.h"
 #include "llvm/ADT/Twine.h"
@@ -142,6 +143,95 @@
 /// Usable as: Any Matcher
 inline internal::TrueMatcher anything() { return internal::TrueMatcher(); }
 
+/// \brief Matches typedef declarations.
+///
+/// Given
+/// \code
+///   typedef int X;
+/// \endcode
+/// typedefDecl()
+///   matches "typedef int X"
+const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl;
+
+/// \brief Matches AST nodes that were expanded within the main-file
+///
+/// Example matches X but not Y (matcher = recordDecl(isInMainFile())
+/// \code
+///   #include <Y.h>
+///   class X {};
+/// \endcode
+/// Y.h:
+/// \code
+///   class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER(isInMainFile,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+                                                          TypeLoc)) {
+  auto &SourceManager = Finder->getASTContext().getSourceManager();
+  return SourceManager.isInMainFile(
+      SourceManager.getExpansionLoc(Node.getLocStart()));
+}
+
+/// \brief Matches AST nodes that were expanded within system-header-files
+///
+/// Example matches Y but not X (matcher = recordDecl(isInSytemHeader())
+/// \code
+///   #include <SystemHeader.h>
+///   class X {};
+/// \endcode
+/// SystemHeader.h:
+/// \code
+///   class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER(isInSystemHeader,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+                                                          TypeLoc)) {
+  auto &SourceManager = Finder->getASTContext().getSourceManager();
+  auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+  if (ExpansionLoc.isInvalid()) {
+    return false;
+  }
+  return SourceManager.isInSystemHeader(ExpansionLoc);
+}
+
+/// \brief Matches AST nodes that were expanded within files whose name is
+/// partially matching a given regex
+///
+/// Example matches Y but not X (matcher = recordDecl(isInFileMatchingName("AST.*"))
+/// \code
+///   #include "ASTMatcher.h"
+///   class X {};
+/// \endcode
+/// ASTMatcher.h:
+/// \code
+///   class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER_P(isInFileMatchingName,
+                          AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+                                                            TypeLoc),
+                          std::string, RegExp) {
+  auto &SourceManager = Finder->getASTContext().getSourceManager();
+  auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+  if (ExpansionLoc.isInvalid()) {
+    return false;
+  }
+  auto FileEntry =
+      SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
+  if (!FileEntry) {
+    return false;
+  }
+
+  auto Filename = FileEntry->getName();
+  llvm::Regex RE(RegExp);
+  return RE.match(Filename);
+}
+
 /// \brief Matches declarations.
 ///
 /// Examples matches \c X, \c C, and the friend declaration inside \c C;
Index: include/clang/Tooling/Tooling.h
===================================================================
--- include/clang/Tooling/Tooling.h
+++ include/clang/Tooling/Tooling.h
@@ -152,9 +152,11 @@
 /// \param FileName The file name which 'Code' will be mapped as.
 ///
 /// \return - True if 'ToolAction' was successfully executed.
-bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
-                           const std::vector<std::string> &Args,
-                           const Twine &FileName = "input.cc");
+bool runToolOnCodeWithArgs(
+    clang::FrontendAction *ToolAction, const Twine &Code,
+    const std::vector<std::string> &Args, const Twine &FileName = "input.cc",
+    const std::vector<std::pair<std::string, std::string>> &VirtualMappedFiles =
+        std::vector<std::pair<std::string, std::string>>());
 
 /// \brief Builds an AST for 'Code'.
 ///
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -242,7 +242,10 @@
   REGISTER_MATCHER(isExpr);
   REGISTER_MATCHER(isExternC);
   REGISTER_MATCHER(isImplicit);
+  REGISTER_MATCHER(isInFileMatchingName);
+  REGISTER_MATCHER(isInMainFile);
   REGISTER_MATCHER(isInstantiated);
+  REGISTER_MATCHER(isInSystemHeader);
   REGISTER_MATCHER(isInteger);
   REGISTER_MATCHER(isIntegral);
   REGISTER_MATCHER(isInTemplateInstantiation);
@@ -314,6 +317,7 @@
   REGISTER_MATCHER(to);
   REGISTER_MATCHER(tryStmt);
   REGISTER_MATCHER(type);
+  REGISTER_MATCHER(typedefDecl);
   REGISTER_MATCHER(typedefType);
   REGISTER_MATCHER(typeLoc);
   REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
Index: lib/Tooling/Tooling.cpp
===================================================================
--- lib/Tooling/Tooling.cpp
+++ lib/Tooling/Tooling.cpp
@@ -121,19 +121,29 @@
   return Args;
 }
 
-bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
-                           const std::vector<std::string> &Args,
-                           const Twine &FileName) {
+bool
+runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
+                      const std::vector<std::string> &Args,
+                      const Twine &FileName,
+                      const std::vector<std::pair<std::string, std::string>> &
+                          VirtualMappedFiles) {
+
   SmallString<16> FileNameStorage;
   StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
   llvm::IntrusiveRefCntPtr<FileManager> Files(
       new FileManager(FileSystemOptions()));
-  ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction,
-                            Files.get());
+  ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef),
+                            ToolAction, Files.get());
 
   SmallString<1024> CodeStorage;
   Invocation.mapVirtualFile(FileNameRef,
                             Code.toNullTerminatedStringRef(CodeStorage));
+
+  for (auto &FilenameWithContent : VirtualMappedFiles) {
+    Invocation.mapVirtualFile(FilenameWithContent.first,
+                              FilenameWithContent.second);
+  }
+
   return Invocation.run();
 }
 
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -4597,5 +4597,45 @@
           .bind("data")));
 }
 
+TEST(TypeDefDeclMatcher, Match) {
+  EXPECT_TRUE(matches("typedef int typedefDeclTest;",
+                      typedefDecl(hasName("typedefDeclTest"))));
+}
+
+TEST(Matcher, IsInMainFileMatcher) {
+  EXPECT_TRUE(matches(
+      "class X {};", recordDecl(hasName("X"), isInMainFile())));
+  EXPECT_TRUE(notMatches("", recordDecl(isInMainFile())));
+  EXPECT_TRUE(matchesConditionally("#include <other>\n",
+                                   recordDecl(isInMainFile()), false,
+                                   "-isystem/", {{"/other", "class X {};"}}));
+}
+
+TEST(Matcher, IsInSystemHeaderMatcher) {
+  EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+                                   recordDecl(isInSystemHeader()), true,
+                                   "-isystem/", {{"/other", "class X {};"}}));
+  EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+                                   recordDecl(isInSystemHeader()), false, "-I/",
+                                   {{"/other", "class X {};"}}));
+  EXPECT_TRUE(notMatches("class X {};", recordDecl(isInSystemHeader())));
+  EXPECT_TRUE(notMatches("", recordDecl(isInSystemHeader())));
+}
+
+TEST(Matcher, IsInFileMatchingName) {
+  EXPECT_TRUE(matchesConditionally(
+      "#include <foo>\n"
+      "#include <bar>\n"
+      "class X {};",
+      recordDecl(isInFileMatchingName("b.*"), hasName("B")), true, "-isystem/",
+      {{"/foo", "class A {};"}, {"/bar", "class B {};"}}));
+  EXPECT_TRUE(matchesConditionally(
+      "#include <foo>\n"
+      "#include <bar>\n"
+      "class X {};",
+      recordDecl(isInFileMatchingName("f.*"), hasName("X")), false, "-isystem/",
+      {{"/foo", "class A {};"}, {"/bar", "class B {};"}}));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: unittests/ASTMatchers/ASTMatchersTest.h
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.h
+++ unittests/ASTMatchers/ASTMatchersTest.h
@@ -58,10 +58,11 @@
 };
 
 template <typename T>
-testing::AssertionResult matchesConditionally(const std::string &Code,
-                                              const T &AMatcher,
-                                              bool ExpectMatch,
-                                              llvm::StringRef CompileArg) {
+testing::AssertionResult matchesConditionally(
+    const std::string &Code, const T &AMatcher, bool ExpectMatch,
+    llvm::StringRef CompileArg,
+    const std::vector<std::pair<std::string, std::string>> &VirtualMappedFiles =
+        std::vector<std::pair<std::string, std::string>>()) {
   bool Found = false, DynamicFound = false;
   MatchFinder Finder;
   VerifyMatch VerifyFound(nullptr, &Found);
@@ -73,7 +74,8 @@
       newFrontendActionFactory(&Finder));
   // Some tests use typeof, which is a gnu extension.
   std::vector<std::string> Args(1, CompileArg);
-  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
+  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc",
+                             VirtualMappedFiles)) {
     return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
   }
   if (Found != DynamicFound) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to