gribozavr updated this revision to Diff 274008.
gribozavr added a comment.

Addressed code review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82179/new/

https://reviews.llvm.org/D82179

Files:
  clang/include/clang/Testing/TestClangConfig.h
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
  clang/unittests/ASTMatchers/ASTMatchersTest.h
  clang/unittests/Tooling/Syntax/TreeTest.cpp

Index: clang/unittests/Tooling/Syntax/TreeTest.cpp
===================================================================
--- clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -18,6 +18,7 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Testing/CommandLineArgs.h"
+#include "clang/Testing/TestClangConfig.h"
 #include "clang/Tooling/Core/Replacement.h"
 #include "clang/Tooling/Syntax/BuildTree.h"
 #include "clang/Tooling/Syntax/Mutations.h"
@@ -47,83 +48,6 @@
                             T->lastLeaf()->token() + 1);
 }
 
-struct TestClangConfig {
-  TestLanguage Language;
-  std::string Target;
-
-  bool isC99OrLater() const { return Language == Lang_C99; }
-
-  bool isC() const { return Language == Lang_C89 || Language == Lang_C99; }
-
-  bool isCXX() const {
-    return Language == Lang_CXX03 || Language == Lang_CXX11 ||
-           Language == Lang_CXX14 || Language == Lang_CXX17 ||
-           Language == Lang_CXX20;
-  }
-
-  bool isCXX11OrLater() const {
-    return Language == Lang_CXX11 || Language == Lang_CXX14 ||
-           Language == Lang_CXX17 || Language == Lang_CXX20;
-  }
-
-  bool isCXX14OrLater() const {
-    return Language == Lang_CXX14 || Language == Lang_CXX17 ||
-           Language == Lang_CXX20;
-  }
-
-  bool isCXX17OrLater() const {
-    return Language == Lang_CXX17 || Language == Lang_CXX20;
-  }
-
-  bool supportsCXXDynamicExceptionSpecification() const {
-    return Language == Lang_CXX03 || Language == Lang_CXX11 ||
-           Language == Lang_CXX14;
-  }
-
-  bool hasDelayedTemplateParsing() const {
-    return Target == "x86_64-pc-win32-msvc";
-  }
-
-  std::vector<std::string> getCommandLineArgs() const {
-    std::vector<std::string> Result = getCommandLineArgsForTesting(Language);
-    Result.push_back("-target");
-    Result.push_back(Target);
-    return Result;
-  }
-
-  std::string toString() const {
-    std::string Result;
-    llvm::raw_string_ostream OS(Result);
-    OS << "{ Language=" << Language << ", Target=" << Target << " }";
-    return OS.str();
-  }
-
-  friend std::ostream &operator<<(std::ostream &OS,
-                                  const TestClangConfig &ClangConfig) {
-    return OS << ClangConfig.toString();
-  }
-
-  static std::vector<TestClangConfig> &allConfigs() {
-    static std::vector<TestClangConfig> all_configs = []() {
-      std::vector<TestClangConfig> all_configs;
-      for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11,
-                                Lang_CXX14, Lang_CXX17, Lang_CXX20}) {
-        TestClangConfig config;
-        config.Language = lang;
-        config.Target = "x86_64-pc-linux-gnu";
-        all_configs.push_back(config);
-
-        // Windows target is interesting to test because it enables
-        // `-fdelayed-template-parsing`.
-        config.Target = "x86_64-pc-win32-msvc";
-        all_configs.push_back(config);
-      }
-      return all_configs;
-    }();
-    return all_configs;
-  }
-};
-
 class SyntaxTreeTest : public ::testing::Test,
                        public ::testing::WithParamInterface<TestClangConfig> {
 protected:
@@ -3893,7 +3817,24 @@
   EXPECT_TRUE(S->isDetached());
 }
 
+static std::vector<TestClangConfig> allTestClangConfigs() {
+  std::vector<TestClangConfig> all_configs;
+  for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11,
+                            Lang_CXX14, Lang_CXX17, Lang_CXX20}) {
+    TestClangConfig config;
+    config.Language = lang;
+    config.Target = "x86_64-pc-linux-gnu";
+    all_configs.push_back(config);
+
+    // Windows target is interesting to test because it enables
+    // `-fdelayed-template-parsing`.
+    config.Target = "x86_64-pc-win32-msvc";
+    all_configs.push_back(config);
+  }
+  return all_configs;
+}
+
 INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, SyntaxTreeTest,
-                        testing::ValuesIn(TestClangConfig::allConfigs()), );
+                        testing::ValuesIn(allTestClangConfigs()), );
 
 } // namespace
Index: clang/unittests/ASTMatchers/ASTMatchersTest.h
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTest.h
+++ clang/unittests/ASTMatchers/ASTMatchersTest.h
@@ -12,6 +12,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Testing/CommandLineArgs.h"
+#include "clang/Testing/TestClangConfig.h"
 #include "clang/Tooling/Tooling.h"
 #include "gtest/gtest.h"
 
@@ -94,17 +95,29 @@
     return testing::AssertionFailure() << "Could not add dynamic matcher";
   std::unique_ptr<FrontendActionFactory> Factory(
       newFrontendActionFactory(&Finder));
-  // Some tests need rtti/exceptions on.  Use an unknown-unknown triple so we
-  // don't instantiate the full system toolchain.  On Linux, instantiating the
-  // toolchain involves stat'ing large portions of /usr/lib, and this slows down
-  // not only this test, but all other tests, via contention in the kernel.
-  //
-  // FIXME: This is a hack to work around the fact that there's no way to do the
-  // equivalent of runToolOnCodeWithArgs without instantiating a full Driver.
-  // We should consider having a function, at least for tests, that invokes cc1.
-  std::vector<std::string> Args(CompileArgs.begin(), CompileArgs.end());
-  Args.insert(Args.end(), {"-frtti", "-fexceptions",
-                           "-target", "i386-unknown-unknown"});
+  std::vector<std::string> Args = {
+      // Some tests need rtti/exceptions on.
+      "-frtti", "-fexceptions",
+      // Ensure that tests specify the C++ standard version that they need.
+      "-Werror=c++14-extensions", "-Werror=c++17-extensions",
+      "-Werror=c++20-extensions"};
+  // Append additional arguments at the end to allow overriding the default
+  // choices that we made above.
+  llvm::copy(CompileArgs, std::back_inserter(Args));
+  if (llvm::find(Args, "-target") == Args.end()) {
+    // Use an unknown-unknown triple so we don't instantiate the full system
+    // toolchain.  On Linux, instantiating the toolchain involves stat'ing
+    // large portions of /usr/lib, and this slows down not only this test, but
+    // all other tests, via contention in the kernel.
+    //
+    // FIXME: This is a hack to work around the fact that there's no way to do
+    // the equivalent of runToolOnCodeWithArgs without instantiating a full
+    // Driver.  We should consider having a function, at least for tests, that
+    // invokes cc1.
+    Args.push_back("-target");
+    Args.push_back("i386-unknown-unknown");
+  }
+
   if (!runToolOnCodeWithArgs(
           Factory->create(), Code, Args, Filename, "clang-tool",
           std::make_shared<PCHContainerOperations>(), VirtualMappedFiles)) {
@@ -131,13 +144,9 @@
 matchesConditionally(const Twine &Code, const T &AMatcher, bool ExpectMatch,
                      ArrayRef<TestLanguage> TestLanguages) {
   for (auto Lang : TestLanguages) {
-    std::vector<std::string> Args = getCommandLineArgsForTesting(Lang);
-    Args.insert(Args.end(),
-                {"-Werror=c++14-extensions", "-Werror=c++17-extensions",
-                 "-Werror=c++20-extensions"});
-    auto Result = matchesConditionally(Code, AMatcher, ExpectMatch, Args,
-                                       FileContentMappings(),
-                                       getFilenameForTesting(Lang));
+    auto Result = matchesConditionally(
+        Code, AMatcher, ExpectMatch, getCommandLineArgsForTesting(Lang),
+        FileContentMappings(), getFilenameForTesting(Lang));
     if (!Result)
       return Result;
   }
@@ -174,11 +183,6 @@
                               "input.c");
 }
 
-template <typename T>
-testing::AssertionResult matchesC99(const Twine &Code, const T &AMatcher) {
-  return matchesConditionally(Code, AMatcher, true, {Lang_C99});
-}
-
 template <typename T>
 testing::AssertionResult notMatchesC(const Twine &Code, const T &AMatcher) {
   return matchesConditionally(Code, AMatcher, false, {Lang_C89});
@@ -410,6 +414,26 @@
   std::string Name;
 };
 
+class ASTMatchersTest : public ::testing::Test,
+                        public ::testing::WithParamInterface<TestClangConfig> {
+protected:
+  template <typename T>
+  testing::AssertionResult matches(const Twine &Code, const T &AMatcher) {
+    const TestClangConfig &TestConfig = GetParam();
+    return clang::ast_matchers::matchesConditionally(
+        Code, AMatcher, /*ExpectMatch=*/true, TestConfig.getCommandLineArgs(),
+        FileContentMappings(), getFilenameForTesting(TestConfig.Language));
+  }
+
+  template <typename T>
+  testing::AssertionResult notMatches(const Twine &Code, const T &AMatcher) {
+    const TestClangConfig &TestConfig = GetParam();
+    return clang::ast_matchers::matchesConditionally(
+        Code, AMatcher, /*ExpectMatch=*/false, TestConfig.getCommandLineArgs(),
+        FileContentMappings(), getFilenameForTesting(TestConfig.Language));
+  }
+};
+
 } // namespace ast_matchers
 } // namespace clang
 
Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -18,52 +18,47 @@
 namespace clang {
 namespace ast_matchers {
 
-TEST(Finder, DynamicOnlyAcceptsSomeMatchers) {
-  MatchFinder Finder;
-  EXPECT_TRUE(Finder.addDynamicMatcher(decl(), nullptr));
-  EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), nullptr));
-  EXPECT_TRUE(Finder.addDynamicMatcher(constantArrayType(hasSize(42)),
-                                       nullptr));
-
-  // Do not accept non-toplevel matchers.
-  EXPECT_FALSE(Finder.addDynamicMatcher(isMain(), nullptr));
-  EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr));
-}
-
-TEST(Decl, MatchesDeclarations) {
+TEST_P(ASTMatchersTest, Decl_CXX) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `decl()` that does not depend on C++.
+    return;
+  }
   EXPECT_TRUE(notMatches("", decl(usingDecl())));
-  EXPECT_TRUE(matches("namespace x { class X {}; } using x::X;",
-                      decl(usingDecl())));
+  EXPECT_TRUE(
+      matches("namespace x { class X {}; } using x::X;", decl(usingDecl())));
 }
 
-TEST(NameableDeclaration, MatchesVariousDecls) {
+TEST_P(ASTMatchersTest, NameableDeclaration_MatchesVariousDecls) {
   DeclarationMatcher NamedX = namedDecl(hasName("X"));
   EXPECT_TRUE(matches("typedef int X;", NamedX));
   EXPECT_TRUE(matches("int X;", NamedX));
-  EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX));
-  EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", NamedX));
   EXPECT_TRUE(matches("void foo() { int X; }", NamedX));
-  EXPECT_TRUE(matches("namespace X { }", NamedX));
   EXPECT_TRUE(matches("enum X { A, B, C };", NamedX));
 
   EXPECT_TRUE(notMatches("#define X 1", NamedX));
 }
 
-TEST(NameableDeclaration, REMatchesVariousDecls) {
+TEST_P(ASTMatchersTest, NamedDecl_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  DeclarationMatcher NamedX = namedDecl(hasName("X"));
+  EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX));
+  EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", NamedX));
+  EXPECT_TRUE(matches("namespace X { }", NamedX));
+}
+
+TEST_P(ASTMatchersTest, MatchesNameRE) {
   DeclarationMatcher NamedX = namedDecl(matchesName("::X"));
   EXPECT_TRUE(matches("typedef int Xa;", NamedX));
   EXPECT_TRUE(matches("int Xb;", NamedX));
-  EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX));
-  EXPECT_TRUE(matches("void foo() try { } catch(int Xdef) { }", NamedX));
   EXPECT_TRUE(matches("void foo() { int Xgh; }", NamedX));
-  EXPECT_TRUE(matches("namespace Xij { }", NamedX));
   EXPECT_TRUE(matches("enum X { A, B, C };", NamedX));
 
   EXPECT_TRUE(notMatches("#define Xkl 1", NamedX));
 
   DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no"));
   EXPECT_TRUE(matches("int no_foo;", StartsWithNo));
-  EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo));
 
   DeclarationMatcher Abc = namedDecl(matchesName("a.*b.*c"));
   EXPECT_TRUE(matches("int abc;", Abc));
@@ -74,18 +69,30 @@
   DeclarationMatcher StartsWithK = namedDecl(matchesName(":k[^:]*$"));
   EXPECT_TRUE(matches("int k;", StartsWithK));
   EXPECT_TRUE(matches("int kAbc;", StartsWithK));
+}
+
+TEST_P(ASTMatchersTest, MatchesNameRE_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  DeclarationMatcher NamedX = namedDecl(matchesName("::X"));
+  EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX));
+  EXPECT_TRUE(matches("void foo() try { } catch(int Xdef) { }", NamedX));
+  EXPECT_TRUE(matches("namespace Xij { }", NamedX));
+
+  DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no"));
+  EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo));
+
+  DeclarationMatcher StartsWithK = namedDecl(matchesName(":k[^:]*$"));
   EXPECT_TRUE(matches("namespace x { int kTest; }", StartsWithK));
   EXPECT_TRUE(matches("class C { int k; };", StartsWithK));
   EXPECT_TRUE(notMatches("class C { int ckc; };", StartsWithK));
 }
 
-TEST(DeclarationMatcher, MatchClass) {
-  DeclarationMatcher ClassMatcher(recordDecl());
-
-  // This passes on Windows only because we explicitly pass -target
-  // i386-unknown-unknown.  If we were to compile with the default target
-  // triple, we'd want to EXPECT_TRUE if it's Win32 or MSVC.
-  EXPECT_FALSE(matches("", ClassMatcher));
+TEST_P(ASTMatchersTest, DeclarationMatcher_MatchClass) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
 
   DeclarationMatcher ClassX = recordDecl(recordDecl(hasName("X")));
   EXPECT_TRUE(matches("class X;", ClassX));
@@ -94,7 +101,12 @@
   EXPECT_TRUE(notMatches("", ClassX));
 }
 
-TEST(DeclarationMatcher, translationUnitDecl) {
+TEST_P(ASTMatchersTest, TranslationUnitDecl) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `translationUnitDecl()` that does not depend on
+    // C++.
+    return;
+  }
   StringRef Code = "int MyVar1;\n"
                    "namespace NameSpace {\n"
                    "int MyVar2;\n"
@@ -109,57 +121,84 @@
             hasDeclContext(decl(hasDeclContext(translationUnitDecl()))))));
 }
 
-TEST(DeclarationMatcher, LinkageSpecification) {
+TEST_P(ASTMatchersTest, LinkageSpecDecl) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("extern \"C\" { void foo() {}; }", linkageSpecDecl()));
   EXPECT_TRUE(notMatches("void foo() {};", linkageSpecDecl()));
 }
 
-TEST(ClassTemplate, DoesNotMatchClass) {
+TEST_P(ASTMatchersTest, ClassTemplateDecl_DoesNotMatchClass) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
   EXPECT_TRUE(notMatches("class X;", ClassX));
   EXPECT_TRUE(notMatches("class X {};", ClassX));
 }
 
-TEST(ClassTemplate, MatchesClassTemplate) {
+TEST_P(ASTMatchersTest, ClassTemplateDecl_MatchesClassTemplate) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
   EXPECT_TRUE(matches("template<typename T> class X {};", ClassX));
   EXPECT_TRUE(matches("class Z { template<class T> class X {}; };", ClassX));
 }
 
-TEST(ClassTemplate, DoesNotMatchClassTemplateExplicitSpecialization) {
+TEST_P(ASTMatchersTest,
+       ClassTemplateDecl_DoesNotMatchClassTemplateExplicitSpecialization) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("template<typename T> class X { };"
                            "template<> class X<int> { int a; };",
                          classTemplateDecl(hasName("X"),
                                            hasDescendant(fieldDecl(hasName("a"))))));
 }
 
-TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) {
+TEST_P(ASTMatchersTest,
+       ClassTemplateDecl_DoesNotMatchClassTemplatePartialSpecialization) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("template<typename T, typename U> class X { };"
                            "template<typename T> class X<T, int> { int a; };",
                          classTemplateDecl(hasName("X"),
                                            hasDescendant(fieldDecl(hasName("a"))))));
 }
 
-TEST(DeclarationMatcher, MatchCudaDecl) {
+TEST(ASTMatchersTestCUDA, CUDAKernelCallExpr) {
   EXPECT_TRUE(matchesWithCuda("__global__ void f() { }"
                                 "void g() { f<<<1, 2>>>(); }",
                               cudaKernelCallExpr()));
-  EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
-                              hasAttr(clang::attr::CUDADevice)));
   EXPECT_TRUE(notMatchesWithCuda("void f() {}",
                                  cudaKernelCallExpr()));
+}
+
+TEST(ASTMatchersTestCUDA, HasAttrCUDA) {
+  EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
+                              hasAttr(clang::attr::CUDADevice)));
   EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}",
                                   hasAttr(clang::attr::CUDAGlobal)));
 }
 
-TEST(ValueDecl, Matches) {
+TEST_P(ASTMatchersTest, ValueDecl) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Fix this test in non-C++ language modes.
+    return;
+  }
   EXPECT_TRUE(matches("enum EnumType { EnumValue };",
                       valueDecl(hasType(asString("enum EnumType")))));
   EXPECT_TRUE(matches("void FunctionDecl();",
                       valueDecl(hasType(asString("void (void)")))));
 }
 
-TEST(FriendDecl, Matches) {
+TEST_P(ASTMatchersTest, FriendDecl) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("class Y { friend class X; };",
                       friendDecl(hasType(asString("class X")))));
   EXPECT_TRUE(matches("class Y { friend class X; };",
@@ -169,43 +208,69 @@
                       functionDecl(hasName("f"), hasParent(friendDecl()))));
 }
 
-TEST(Enum, DoesNotMatchClasses) {
+TEST_P(ASTMatchersTest, EnumDecl_DoesNotMatchClasses) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
 }
 
-TEST(Enum, MatchesEnums) {
+TEST_P(ASTMatchersTest, EnumDecl_MatchesEnums) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Fix this test in non-C++ language modes.
+    return;
+  }
   EXPECT_TRUE(matches("enum X {};", enumDecl(hasName("X"))));
 }
 
-TEST(EnumConstant, Matches) {
+TEST_P(ASTMatchersTest, EnumConstantDecl) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Fix this test in non-C++ language modes.
+    return;
+  }
   DeclarationMatcher Matcher = enumConstantDecl(hasName("A"));
   EXPECT_TRUE(matches("enum X{ A };", Matcher));
   EXPECT_TRUE(notMatches("enum X{ B };", Matcher));
   EXPECT_TRUE(notMatches("enum X {};", Matcher));
 }
 
-TEST(TagDecl, MatchesTagDecls) {
+TEST_P(ASTMatchersTest, TagDecl) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Fix this test in non-C++ language modes.
+    return;
+  }
   EXPECT_TRUE(matches("struct X {};", tagDecl(hasName("X"))));
-  EXPECT_TRUE(matches("class C {};", tagDecl(hasName("C"))));
   EXPECT_TRUE(matches("union U {};", tagDecl(hasName("U"))));
   EXPECT_TRUE(matches("enum E {};", tagDecl(hasName("E"))));
 }
 
-TEST(Matcher, UnresolvedLookupExpr) {
-  // FIXME: The test is known to be broken on Windows with delayed template
-  // parsing.
-  EXPECT_TRUE(matchesConditionally("template<typename T>"
-                                   "T foo() { T a; return a; }"
-                                   "template<typename T>"
-                                   "void bar() {"
-                                   "  foo<T>();"
-                                   "}",
-                                   unresolvedLookupExpr(),
-                                   /*ExpectMatch=*/true,
-                                   {"-fno-delayed-template-parsing"}));
+TEST_P(ASTMatchersTest, TagDecl_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(matches("class C {};", tagDecl(hasName("C"))));
+}
+
+TEST_P(ASTMatchersTest, UnresolvedLookupExpr) {
+  if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
+    // FIXME: Fix this test to work with delayed template parsing.
+    return;
+  }
+
+  EXPECT_TRUE(matches("template<typename T>"
+                      "T foo() { T a; return a; }"
+                      "template<typename T>"
+                      "void bar() {"
+                      "  foo<T>();"
+                      "}",
+                      unresolvedLookupExpr()));
 }
 
-TEST(Matcher, ADLCall) {
+TEST_P(ASTMatchersTest, UsesADL) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
   StatementMatcher ADLMatch = callExpr(usesADL());
   StatementMatcher ADLMatchOper = cxxOperatorCallExpr(usesADL());
   StringRef NS_Str = R"cpp(
@@ -237,7 +302,11 @@
   EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::operator+(x, x);"), ADLMatch));
 }
 
-TEST(Matcher, Call) {
+TEST_P(ASTMatchersTest, CallExpr_CXX) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `callExpr()` that does not depend on C++.
+    return;
+  }
   // FIXME: Do we want to overload Call() to directly take
   // Matcher<Decl>, too?
   StatementMatcher MethodX =
@@ -284,20 +353,33 @@
     notMatches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
                MethodOnYPointer));
 }
-TEST(Matcher, Lambda) {
+
+TEST_P(ASTMatchersTest, LambdaExpr) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("auto f = [] (int i) { return i; };",
                       lambdaExpr()));
 }
 
-TEST(Matcher, ForRange) {
+TEST_P(ASTMatchersTest, CXXForRangeStmt) {
+  EXPECT_TRUE(
+      notMatches("void f() { for (int i; i<5; ++i); }", cxxForRangeStmt()));
+}
+
+TEST_P(ASTMatchersTest, CXXForRangeStmt_CXX11) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };"
                         "void f() { for (auto &a : as); }",
                       cxxForRangeStmt()));
-  EXPECT_TRUE(notMatches("void f() { for (int i; i<5; ++i); }",
-                         cxxForRangeStmt()));
 }
 
-TEST(Matcher, SubstNonTypeTemplateParm) {
+TEST_P(ASTMatchersTest, SubstNonTypeTemplateParmExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_FALSE(matches("template<int N>\n"
                          "struct A {  static const int n = 0; };\n"
                          "struct B : public A<42> {};",
@@ -310,21 +392,30 @@
                       substNonTypeTemplateParmExpr())));
 }
 
-TEST(Matcher, NonTypeTemplateParmDecl) {
+TEST_P(ASTMatchersTest, NonTypeTemplateParmDecl) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("template <int N> void f();",
                       nonTypeTemplateParmDecl(hasName("N"))));
   EXPECT_TRUE(
     notMatches("template <typename T> void f();", nonTypeTemplateParmDecl()));
 }
 
-TEST(Matcher, templateTypeParmDecl) {
+TEST_P(ASTMatchersTest, TemplateTypeParmDecl) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("template <typename T> void f();",
                       templateTypeParmDecl(hasName("T"))));
   EXPECT_TRUE(
     notMatches("template <int N> void f();", templateTypeParmDecl()));
 }
 
-TEST(Matcher, UserDefinedLiteral) {
+TEST_P(ASTMatchersTest, UserDefinedLiteral) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {"
                         "  return i + 1;"
                         "}"
@@ -332,10 +423,9 @@
                       userDefinedLiteral()));
 }
 
-TEST(Matcher, FlowControl) {
-  EXPECT_TRUE(matches("void f() { while(true) { break; } }", breakStmt()));
-  EXPECT_TRUE(matches("void f() { while(true) { continue; } }",
-                      continueStmt()));
+TEST_P(ASTMatchersTest, FlowControl) {
+  EXPECT_TRUE(matches("void f() { while(1) { break; } }", breakStmt()));
+  EXPECT_TRUE(matches("void f() { while(1) { continue; } }", continueStmt()));
   EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", gotoStmt()));
   EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}",
                       labelStmt(
@@ -346,7 +436,11 @@
   EXPECT_TRUE(matches("void f() { return; }", returnStmt()));
 }
 
-TEST(Matcher, OverloadedOperatorCall) {
+TEST_P(ASTMatchersTest, CXXOperatorCallExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
   StatementMatcher OpCall = cxxOperatorCallExpr();
   // Unary operator
   EXPECT_TRUE(matches("class Y { }; "
@@ -372,7 +466,11 @@
   EXPECT_TRUE(notMatches("int t = 5 << 2;", OpCall));
 }
 
-TEST(Matcher, ThisPointerType) {
+TEST_P(ASTMatchersTest, ThisPointerType) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
   StatementMatcher MethodOnY =
       traverse(ast_type_traits::TK_AsIs,
                cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y")))));
@@ -403,7 +501,11 @@
       "void z() { X *x; x->Y::x(); }", MethodOnY));
 }
 
-TEST(Matcher, VariableUsage) {
+TEST_P(ASTMatchersTest, DeclRefExpr) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `declRefExpr()` that does not depend on C++.
+    return;
+  }
   StatementMatcher Reference =
     declRefExpr(to(
       varDecl(hasInitializer(
@@ -429,7 +531,10 @@
       "}", Reference));
 }
 
-TEST(Matcher, CalledVariable) {
+TEST_P(ASTMatchersTest, CXXMemberCallExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   StatementMatcher CallOnVariableY =
     cxxMemberCallExpr(on(declRefExpr(to(varDecl(hasName("y"))))));
 
@@ -449,9 +554,12 @@
     CallOnVariableY));
 }
 
-TEST(UnaryExprOrTypeTraitExpr, MatchesSizeOfAndAlignOf) {
+TEST_P(ASTMatchersTest, UnaryExprOrTypeTraitExpr) {
   EXPECT_TRUE(matches("void x() { int a = sizeof(a); }",
                       unaryExprOrTypeTraitExpr()));
+}
+
+TEST_P(ASTMatchersTest, AlignOfExpr) {
   EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }",
                          alignOfExpr(anything())));
   // FIXME: Uncomment once alignof is enabled.
@@ -461,14 +569,21 @@
   //                        sizeOfExpr()));
 }
 
-TEST(MemberExpression, DoesNotMatchClasses) {
+TEST_P(ASTMatchersTest, MemberExpr_DoesNotMatchClasses) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpr()));
   EXPECT_TRUE(notMatches("class Y { void x() {} };", unresolvedMemberExpr()));
   EXPECT_TRUE(
       notMatches("class Y { void x() {} };", cxxDependentScopeMemberExpr()));
 }
 
-TEST(MemberExpression, MatchesMemberFunctionCall) {
+TEST_P(ASTMatchersTest, MemberExpr_MatchesMemberFunctionCall) {
+  if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
+    // FIXME: Fix this test to work with delayed template parsing.
+    return;
+  }
   EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpr()));
   EXPECT_TRUE(matches("class Y { template <class T> void x() { x<T>(); } };",
                       unresolvedMemberExpr()));
@@ -476,7 +591,11 @@
                       cxxDependentScopeMemberExpr()));
 }
 
-TEST(MemberExpression, MatchesVariable) {
+TEST_P(ASTMatchersTest, MemberExpr_MatchesVariable) {
+  if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
+    // FIXME: Fix this test to work with delayed template parsing.
+    return;
+  }
   EXPECT_TRUE(
     matches("class Y { void x() { this->y; } int y; };", memberExpr()));
   EXPECT_TRUE(
@@ -492,7 +611,10 @@
                       cxxDependentScopeMemberExpr()));
 }
 
-TEST(MemberExpression, MatchesStaticVariable) {
+TEST_P(ASTMatchersTest, MemberExpr_MatchesStaticVariable) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
                       memberExpr()));
   EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
@@ -501,15 +623,34 @@
                          memberExpr()));
 }
 
-TEST(Function, MatchesFunctionDeclarations) {
+TEST_P(ASTMatchersTest, FunctionDecl) {
   StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f"))));
 
   EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF));
   EXPECT_TRUE(notMatches("void f() { }", CallFunctionF));
 
-  if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getOS() !=
-    llvm::Triple::Win32) {
-    // FIXME: Make this work for MSVC.
+  EXPECT_TRUE(notMatches("void f(int);", functionDecl(isVariadic())));
+  EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic())));
+  EXPECT_TRUE(matches("void f(int, ...);", functionDecl(parameterCountIs(1))));
+}
+
+TEST_P(ASTMatchersTest, FunctionDecl_C) {
+  if (!GetParam().isC()) {
+    return;
+  }
+  EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic())));
+  EXPECT_TRUE(matches("void f();", functionDecl(parameterCountIs(0))));
+}
+
+TEST_P(ASTMatchersTest, FunctionDecl_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
+  StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f"))));
+
+  if (!GetParam().hasDelayedTemplateParsing()) {
+    // FIXME: Fix this test to work with delayed template parsing.
     // Dependent contexts, but a non-dependent call.
     EXPECT_TRUE(matches("void f(); template <int N> void g() { f(); }",
                         CallFunctionF));
@@ -528,29 +669,40 @@
                CallFunctionF));
 
   EXPECT_TRUE(matches("void f(...);", functionDecl(isVariadic())));
-  EXPECT_TRUE(notMatches("void f(int);", functionDecl(isVariadic())));
+  EXPECT_TRUE(matches("void f(...);", functionDecl(parameterCountIs(0))));
+}
+
+TEST_P(ASTMatchersTest, FunctionDecl_CXX11) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+
   EXPECT_TRUE(notMatches("template <typename... Ts> void f(Ts...);",
                          functionDecl(isVariadic())));
-  EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic())));
-  EXPECT_TRUE(notMatchesC("void f();", functionDecl(isVariadic())));
-  EXPECT_TRUE(matches("void f(...);", functionDecl(parameterCountIs(0))));
-  EXPECT_TRUE(matchesC("void f();", functionDecl(parameterCountIs(0))));
-  EXPECT_TRUE(matches("void f(int, ...);", functionDecl(parameterCountIs(1))));
 }
 
-TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) {
+TEST_P(ASTMatchersTest,
+       FunctionTemplateDecl_MatchesFunctionTemplateDeclarations) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(
     matches("template <typename T> void f(T t) {}",
             functionTemplateDecl(hasName("f"))));
 }
 
-TEST(FunctionTemplate, DoesNotMatchFunctionDeclarations) {
+TEST_P(ASTMatchersTest, FunctionTemplate_DoesNotMatchFunctionDeclarations) {
   EXPECT_TRUE(
-    notMatches("void f(double d); void f(int t) {}",
-               functionTemplateDecl(hasName("f"))));
+      notMatches("void f(double d);", functionTemplateDecl(hasName("f"))));
+  EXPECT_TRUE(
+      notMatches("void f(int t) {}", functionTemplateDecl(hasName("f"))));
 }
 
-TEST(FunctionTemplate, DoesNotMatchFunctionTemplateSpecializations) {
+TEST_P(ASTMatchersTest,
+       FunctionTemplateDecl_DoesNotMatchFunctionTemplateSpecializations) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(
     notMatches("void g(); template <typename T> void f(T t) {}"
                  "template <> void f(int t) { g(); }",
@@ -559,7 +711,10 @@
                                       functionDecl(hasName("g"))))))));
 }
 
-TEST(Matcher, MatchesClassTemplateSpecialization) {
+TEST_P(ASTMatchersTest, ClassTemplateSpecializationDecl) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("template<typename T> struct A {};"
                         "template<> struct A<int> {};",
                       classTemplateSpecializationDecl()));
@@ -569,17 +724,28 @@
                          classTemplateSpecializationDecl()));
 }
 
-TEST(DeclaratorDecl, MatchesDeclaratorDecls) {
+TEST_P(ASTMatchersTest, DeclaratorDecl) {
   EXPECT_TRUE(matches("int x;", declaratorDecl()));
+  EXPECT_TRUE(notMatches("struct A {};", declaratorDecl()));
+}
+
+TEST_P(ASTMatchersTest, DeclaratorDecl_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("class A {};", declaratorDecl()));
 }
 
-TEST(ParmVarDecl, MatchesParmVars) {
+TEST_P(ASTMatchersTest, ParmVarDecl) {
   EXPECT_TRUE(matches("void f(int x);", parmVarDecl()));
   EXPECT_TRUE(notMatches("void f();", parmVarDecl()));
 }
 
-TEST(Matcher, ConstructorCall) {
+TEST_P(ASTMatchersTest, Matcher_ConstructorCall) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
   StatementMatcher Constructor =
       traverse(ast_type_traits::TK_AsIs, cxxConstructExpr());
 
@@ -594,19 +760,29 @@
   EXPECT_TRUE(matches("class X {}; void x(int) { X x; }", Constructor));
 }
 
-TEST(Match, ConstructorInitializers) {
+TEST_P(ASTMatchersTest, Match_ConstructorInitializers) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("class C { int i; public: C(int ii) : i(ii) {} };",
                       cxxCtorInitializer(forField(hasName("i")))));
 }
 
-TEST(Matcher, ThisExpr) {
+TEST_P(ASTMatchersTest, Matcher_ThisExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(
     matches("struct X { int a; int f () { return a; } };", cxxThisExpr()));
   EXPECT_TRUE(
     notMatches("struct X { int f () { int a; return a; } };", cxxThisExpr()));
 }
 
-TEST(Matcher, BindTemporaryExpression) {
+TEST_P(ASTMatchersTest, Matcher_BindTemporaryExpression) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
   StatementMatcher TempExpression =
       traverse(ast_type_traits::TK_AsIs, cxxBindTemporaryExpr());
 
@@ -638,16 +814,29 @@
                TempExpression));
 }
 
-TEST(MaterializeTemporaryExpr, MatchesTemporary) {
-  StringRef ClassString = "class string { public: string(); int length(); }; ";
+TEST_P(ASTMatchersTest, MaterializeTemporaryExpr_MatchesTemporaryCXX11CXX14) {
+  if (GetParam().Language != Lang_CXX11 && GetParam().Language != Lang_CXX14) {
+    return;
+  }
+
   StatementMatcher TempExpression =
       traverse(ast_type_traits::TK_AsIs, materializeTemporaryExpr());
 
-  EXPECT_TRUE(matches(
-      ClassString + "string GetStringByValue();"
-                    "void FunctionTakesString(string s);"
-                    "void run() { FunctionTakesString(GetStringByValue()); }",
-      TempExpression));
+  EXPECT_TRUE(matches("class string { public: string(); }; "
+                      "string GetStringByValue();"
+                      "void FunctionTakesString(string s);"
+                      "void run() { FunctionTakesString(GetStringByValue()); }",
+                      TempExpression));
+}
+
+TEST_P(ASTMatchersTest, MaterializeTemporaryExpr_MatchesTemporary) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
+  StringRef ClassString = "class string { public: string(); int length(); }; ";
+  StatementMatcher TempExpression =
+      traverse(ast_type_traits::TK_AsIs, materializeTemporaryExpr());
 
   EXPECT_TRUE(notMatches(ClassString +
                              "string* GetStringPointer(); "
@@ -669,7 +858,11 @@
                          TempExpression));
 }
 
-TEST(Matcher, NewExpression) {
+TEST_P(ASTMatchersTest, Matcher_NewExpression) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+
   StatementMatcher New = cxxNewExpr();
 
   EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New));
@@ -680,12 +873,18 @@
   EXPECT_TRUE(matches("class X {}; void x(int) { new X; }", New));
 }
 
-TEST(Matcher, DeleteExpression) {
+TEST_P(ASTMatchersTest, Matcher_DeleteExpression) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }",
                       cxxDeleteExpr()));
 }
 
-TEST(Matcher, NoexceptExpression) {
+TEST_P(ASTMatchersTest, Matcher_NoexceptExpression) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   StatementMatcher NoExcept = cxxNoexceptExpr();
   EXPECT_TRUE(matches("void foo(); bool bar = noexcept(foo());", NoExcept));
   EXPECT_TRUE(
@@ -695,37 +894,49 @@
   EXPECT_TRUE(matches("void foo() noexcept(noexcept(1+1));", NoExcept));
 }
 
-TEST(Matcher, DefaultArgument) {
+TEST_P(ASTMatchersTest, Matcher_DefaultArgument) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   StatementMatcher Arg = cxxDefaultArgExpr();
-
   EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg));
   EXPECT_TRUE(
     matches("class X { void x(int, int = 0) { int y; x(y); } };", Arg));
   EXPECT_TRUE(notMatches("void x(int, int = 0) { int y; x(y, 0); }", Arg));
 }
 
-TEST(Matcher, StringLiterals) {
+TEST_P(ASTMatchersTest, StringLiteral) {
   StatementMatcher Literal = stringLiteral();
   EXPECT_TRUE(matches("const char *s = \"string\";", Literal));
-  // wide string
-  EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", Literal));
   // with escaped characters
   EXPECT_TRUE(matches("const char *s = \"\x05five\";", Literal));
   // no matching -- though the data type is the same, there is no string literal
   EXPECT_TRUE(notMatches("const char s[1] = {'a'};", Literal));
 }
 
-TEST(Matcher, CharacterLiterals) {
-  StatementMatcher CharLiteral = characterLiteral();
-  EXPECT_TRUE(matches("const char c = 'c';", CharLiteral));
+TEST_P(ASTMatchersTest, StringLiteral_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", stringLiteral()));
+}
+
+TEST_P(ASTMatchersTest, CharacterLiteral) {
+  EXPECT_TRUE(matches("const char c = 'c';", characterLiteral()));
+  EXPECT_TRUE(notMatches("const char c = 0x1;", characterLiteral()));
+}
+
+TEST_P(ASTMatchersTest, CharacterLiteral_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   // wide character
-  EXPECT_TRUE(matches("const char c = L'c';", CharLiteral));
+  EXPECT_TRUE(matches("const char c = L'c';", characterLiteral()));
   // wide character, Hex encoded, NOT MATCHED!
-  EXPECT_TRUE(notMatches("const wchar_t c = 0x2126;", CharLiteral));
-  EXPECT_TRUE(notMatches("const char c = 0x1;", CharLiteral));
+  EXPECT_TRUE(notMatches("const wchar_t c = 0x2126;", characterLiteral()));
 }
 
-TEST(Matcher, IntegerLiterals) {
+TEST_P(ASTMatchersTest, IntegerLiteral) {
   StatementMatcher HasIntLiteral = integerLiteral();
   EXPECT_TRUE(matches("int i = 10;", HasIntLiteral));
   EXPECT_TRUE(matches("int i = 0x1AB;", HasIntLiteral));
@@ -747,7 +958,7 @@
                             hasUnaryOperand(integerLiteral(equals(10))))));
 }
 
-TEST(Matcher, FloatLiterals) {
+TEST_P(ASTMatchersTest, FloatLiteral) {
   StatementMatcher HasFloatLiteral = floatLiteral();
   EXPECT_TRUE(matches("float i = 10.0;", HasFloatLiteral));
   EXPECT_TRUE(matches("float i = 10.0f;", HasFloatLiteral));
@@ -766,42 +977,38 @@
     notMatches("double i = 5.0;", floatLiteral(equals(llvm::APFloat(6.0)))));
 }
 
-TEST(Matcher, NullPtrLiteral) {
+TEST_P(ASTMatchersTest, CXXNullPtrLiteralExpr) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("int* i = nullptr;", cxxNullPtrLiteralExpr()));
 }
 
-TEST(Matcher, ChooseExpr) {
-  EXPECT_TRUE(matchesC("void f() { (void)__builtin_choose_expr(1, 2, 3); }",
-                       chooseExpr()));
+TEST_P(ASTMatchersTest, ChooseExpr) {
+  EXPECT_TRUE(matches("void f() { (void)__builtin_choose_expr(1, 2, 3); }",
+                      chooseExpr()));
 }
 
-TEST(Matcher, GNUNullExpr) {
+TEST_P(ASTMatchersTest, GNUNullExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("int* i = __null;", gnuNullExpr()));
 }
 
-TEST(Matcher, AtomicExpr) {
+TEST_P(ASTMatchersTest, AtomicExpr) {
   EXPECT_TRUE(matches("void foo() { int *ptr; __atomic_load_n(ptr, 1); }",
                       atomicExpr()));
 }
 
-TEST(Matcher, Initializers) {
-  const char *ToMatch = "void foo() { struct point { double x; double y; };"
-    "  struct point ptarray[10] = "
-    "      { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }";
-  EXPECT_TRUE(matchesConditionally(
-      ToMatch,
-      initListExpr(
-          has(cxxConstructExpr(requiresZeroInitialization())),
-          has(initListExpr(
-              hasType(asString("struct point")), has(floatLiteral(equals(1.0))),
-              has(implicitValueInitExpr(hasType(asString("double")))))),
-          has(initListExpr(hasType(asString("struct point")),
-                           has(floatLiteral(equals(2.0))),
-                           has(floatLiteral(equals(1.0)))))),
-      true, {"-std=gnu++03"}));
-
-  EXPECT_TRUE(matchesC99(
-      ToMatch,
+TEST_P(ASTMatchersTest, Initializers_C99) {
+  if (!GetParam().isC99OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(matches(
+      "void foo() { struct point { double x; double y; };"
+      "  struct point ptarray[10] = "
+      "      { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
       initListExpr(hasSyntacticForm(initListExpr(
           has(designatedInitExpr(designatorCountIs(2),
                                  hasDescendant(floatLiteral(equals(1.0))),
@@ -814,19 +1021,41 @@
               hasDescendant(integerLiteral(equals(0))))))))));
 }
 
-TEST(Matcher, ParenListExpr) {
+TEST_P(ASTMatchersTest, Initializers_CXX) {
+  if (GetParam().Language != Lang_CXX03) {
+    // FIXME: Make this test pass with other C++ standard versions.
+    return;
+  }
+  EXPECT_TRUE(matches(
+      "void foo() { struct point { double x; double y; };"
+      "  struct point ptarray[10] = "
+      "      { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
+      initListExpr(
+          has(cxxConstructExpr(requiresZeroInitialization())),
+          has(initListExpr(
+              hasType(asString("struct point")), has(floatLiteral(equals(1.0))),
+              has(implicitValueInitExpr(hasType(asString("double")))))),
+          has(initListExpr(hasType(asString("struct point")),
+                           has(floatLiteral(equals(2.0))),
+                           has(floatLiteral(equals(1.0))))))));
+}
+
+TEST_P(ASTMatchersTest, ParenListExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(
     matches("template<typename T> class foo { void bar() { foo X(*this); } };"
               "template class foo<int>;",
             varDecl(hasInitializer(parenListExpr(has(unaryOperator()))))));
 }
 
-TEST(Matcher, StmtExpr) {
+TEST_P(ASTMatchersTest, StmtExpr) {
   EXPECT_TRUE(matches("void declToImport() { int C = ({int X=4; X;}); }",
                       varDecl(hasInitializer(stmtExpr()))));
 }
 
-TEST(Matcher, ImportPredefinedExpr) {
+TEST_P(ASTMatchersTest, PredefinedExpr) {
   // __func__ expands as StringLiteral("foo")
   EXPECT_TRUE(matches("void foo() { __func__; }",
                       predefinedExpr(
@@ -834,11 +1063,16 @@
                         has(stringLiteral()))));
 }
 
-TEST(Matcher, AsmStatement) {
+TEST_P(ASTMatchersTest, AsmStatement) {
   EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt()));
 }
 
-TEST(Matcher, Conditions) {
+TEST_P(ASTMatchersTest, HasCondition) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `hasCondition()` that does not depend on C++.
+    return;
+  }
+
   StatementMatcher Condition =
     ifStmt(hasCondition(cxxBoolLiteral(equals(true))));
 
@@ -849,7 +1083,13 @@
   EXPECT_TRUE(notMatches("void x() { if (1) {} }", Condition));
 }
 
-TEST(Matcher, ConditionalOperator) {
+TEST_P(ASTMatchersTest, ConditionalOperator) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `conditionalOperator()` that does not depend on
+    // C++.
+    return;
+  }
+
   StatementMatcher Conditional = conditionalOperator(
     hasCondition(cxxBoolLiteral(equals(true))),
     hasTrueExpression(cxxBoolLiteral(equals(false))));
@@ -870,7 +1110,12 @@
     notMatches("void x() { true ? false : true; }", ConditionalFalse));
 }
 
-TEST(Matcher, BinaryConditionalOperator) {
+TEST_P(ASTMatchersTest, BinaryConditionalOperator) {
+  if (!GetParam().isCXX()) {
+    // FIXME: This test should work in non-C++ language modes.
+    return;
+  }
+
   StatementMatcher AlwaysOne =
       traverse(ast_type_traits::TK_AsIs,
                binaryConditionalOperator(
@@ -888,33 +1133,43 @@
   EXPECT_TRUE(matches("void x() { 4 ?: 5; }", FourNotFive));
 }
 
-TEST(ArraySubscriptMatchers, ArraySubscripts) {
+TEST_P(ASTMatchersTest, ArraySubscriptExpr) {
   EXPECT_TRUE(matches("int i[2]; void f() { i[1] = 1; }",
                       arraySubscriptExpr()));
   EXPECT_TRUE(notMatches("int i; void f() { i = 1; }",
                          arraySubscriptExpr()));
 }
 
-TEST(For, FindsForLoops) {
+TEST_P(ASTMatchersTest, ForStmt) {
   EXPECT_TRUE(matches("void f() { for(;;); }", forStmt()));
-  EXPECT_TRUE(matches("void f() { if(true) for(;;); }", forStmt()));
+  EXPECT_TRUE(matches("void f() { if(1) for(;;); }", forStmt()));
+}
+
+TEST_P(ASTMatchersTest, ForStmt_CXX11) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("int as[] = { 1, 2, 3 };"
-                           "void f() { for (auto &a : as); }",
+                         "void f() { for (auto &a : as); }",
                          forStmt()));
 }
 
-TEST(For, ReportsNoFalsePositives) {
+TEST_P(ASTMatchersTest, ForStmt_NoFalsePositives) {
   EXPECT_TRUE(notMatches("void f() { ; }", forStmt()));
-  EXPECT_TRUE(notMatches("void f() { if(true); }", forStmt()));
+  EXPECT_TRUE(notMatches("void f() { if(1); }", forStmt()));
 }
 
-TEST(CompoundStatement, HandlesSimpleCases) {
+TEST_P(ASTMatchersTest, CompoundStatement) {
   EXPECT_TRUE(notMatches("void f();", compoundStmt()));
   EXPECT_TRUE(matches("void f() {}", compoundStmt()));
   EXPECT_TRUE(matches("void f() {{}}", compoundStmt()));
 }
 
-TEST(CompoundStatement, DoesNotMatchEmptyStruct) {
+TEST_P(ASTMatchersTest, CompoundStatement_DoesNotMatchEmptyStruct) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a similar test that does not depend on C++.
+    return;
+  }
   // It's not a compound statement just because there's "{}" in the source
   // text. This is an AST search, not grep.
   EXPECT_TRUE(notMatches("namespace n { struct S {}; }",
@@ -923,34 +1178,53 @@
                       compoundStmt()));
 }
 
-TEST(CastExpression, MatchesExplicitCasts) {
-  EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);",castExpr()));
+TEST_P(ASTMatchersTest, CastExpr_MatchesExplicitCasts) {
   EXPECT_TRUE(matches("void *p = (void *)(&p);", castExpr()));
+}
+
+TEST_P(ASTMatchersTest, CastExpr_MatchesExplicitCasts_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);", castExpr()));
   EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);", castExpr()));
   EXPECT_TRUE(matches("char c = char(0);", castExpr()));
 }
-TEST(CastExpression, MatchesImplicitCasts) {
+
+TEST_P(ASTMatchersTest, CastExpression_MatchesImplicitCasts) {
   // This test creates an implicit cast from int to char.
   EXPECT_TRUE(
       matches("char c = 0;", traverse(ast_type_traits::TK_AsIs, castExpr())));
   // This test creates an implicit cast from lvalue to rvalue.
-  EXPECT_TRUE(matches("char c = 0, d = c;",
+  EXPECT_TRUE(matches("void f() { char c = 0, d = c; }",
                       traverse(ast_type_traits::TK_AsIs, castExpr())));
 }
 
-TEST(CastExpression, DoesNotMatchNonCasts) {
+TEST_P(ASTMatchersTest, CastExpr_DoesNotMatchNonCasts) {
   EXPECT_TRUE(notMatches("char c = '0';", castExpr()));
-  EXPECT_TRUE(notMatches("char c, &q = c;", castExpr()));
   EXPECT_TRUE(notMatches("int i = (0);", castExpr()));
   EXPECT_TRUE(notMatches("int i = 0;", castExpr()));
 }
 
-TEST(ReinterpretCast, MatchesSimpleCase) {
+TEST_P(ASTMatchersTest, CastExpr_DoesNotMatchNonCasts_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(notMatches("char c, &q = c;", castExpr()));
+}
+
+TEST_P(ASTMatchersTest, CXXReinterpretCastExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);",
                       cxxReinterpretCastExpr()));
 }
 
-TEST(ReinterpretCast, DoesNotMatchOtherCasts) {
+TEST_P(ASTMatchersTest, CXXReinterpretCastExpr_DoesNotMatchOtherCasts) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxReinterpretCastExpr()));
   EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
                          cxxReinterpretCastExpr()));
@@ -962,13 +1236,19 @@
                          cxxReinterpretCastExpr()));
 }
 
-TEST(FunctionalCast, MatchesSimpleCase) {
+TEST_P(ASTMatchersTest, CXXFunctionalCastExpr_MatchesSimpleCase) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   StringRef foo_class = "class Foo { public: Foo(const char*); };";
   EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
                       cxxFunctionalCastExpr()));
 }
 
-TEST(FunctionalCast, DoesNotMatchOtherCasts) {
+TEST_P(ASTMatchersTest, CXXFunctionalCastExpr_DoesNotMatchOtherCasts) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   StringRef FooClass = "class Foo { public: Foo(const char*); };";
   EXPECT_TRUE(
     notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
@@ -978,19 +1258,28 @@
                cxxFunctionalCastExpr()));
 }
 
-TEST(DynamicCast, MatchesSimpleCase) {
+TEST_P(ASTMatchersTest, CXXDynamicCastExpr) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};"
                         "B b;"
                         "D* p = dynamic_cast<D*>(&b);",
                       cxxDynamicCastExpr()));
 }
 
-TEST(StaticCast, MatchesSimpleCase) {
+TEST_P(ASTMatchersTest, CXXStaticCastExpr_MatchesSimpleCase) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));",
                       cxxStaticCastExpr()));
 }
 
-TEST(StaticCast, DoesNotMatchOtherCasts) {
+TEST_P(ASTMatchersTest, CXXStaticCastExpr_DoesNotMatchOtherCasts) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxStaticCastExpr()));
   EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
                          cxxStaticCastExpr()));
@@ -1002,11 +1291,14 @@
                          cxxStaticCastExpr()));
 }
 
-TEST(CStyleCast, MatchesSimpleCase) {
+TEST_P(ASTMatchersTest, CStyleCastExpr_MatchesSimpleCase) {
   EXPECT_TRUE(matches("int i = (int) 2.2f;", cStyleCastExpr()));
 }
 
-TEST(CStyleCast, DoesNotMatchOtherCasts) {
+TEST_P(ASTMatchersTest, CStyleCastExpr_DoesNotMatchOtherCasts) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);"
                            "char q, *r = const_cast<char*>(&q);"
                            "void* s = reinterpret_cast<char*>(&s);"
@@ -1016,9 +1308,9 @@
                          cStyleCastExpr()));
 }
 
-TEST(ImplicitCast, MatchesSimpleCase) {
+TEST_P(ASTMatchersTest, ImplicitCastExpr_MatchesSimpleCase) {
   // This test creates an implicit const cast.
-  EXPECT_TRUE(matches("int x = 0; const int y = x;",
+  EXPECT_TRUE(matches("void f() { int x = 0; const int y = x; }",
                       traverse(ast_type_traits::TK_AsIs,
                                varDecl(hasInitializer(implicitCastExpr())))));
   // This test creates an implicit cast from int to char.
@@ -1031,42 +1323,49 @@
                                varDecl(hasInitializer(implicitCastExpr())))));
 }
 
-TEST(ImplicitCast, DoesNotMatchIncorrectly) {
+TEST_P(ASTMatchersTest, ImplicitCastExpr_DoesNotMatchIncorrectly) {
   // This test verifies that implicitCastExpr() matches exactly when implicit casts
   // are present, and that it ignores explicit and paren casts.
 
   // These two test cases have no casts.
   EXPECT_TRUE(notMatches("int x = 0;",
                          varDecl(hasInitializer(implicitCastExpr()))));
-  EXPECT_TRUE(notMatches("int x = 0, &y = x;",
+  EXPECT_TRUE(
+      notMatches("int x = (0);", varDecl(hasInitializer(implicitCastExpr()))));
+  EXPECT_TRUE(notMatches("void f() { int x = 0; double d = (double) x; }",
                          varDecl(hasInitializer(implicitCastExpr()))));
+}
 
-  EXPECT_TRUE(notMatches("int x = 0; double d = (double) x;",
+TEST_P(ASTMatchersTest, ImplicitCastExpr_DoesNotMatchIncorrectly_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(notMatches("int x = 0, &y = x;",
                          varDecl(hasInitializer(implicitCastExpr()))));
   EXPECT_TRUE(notMatches("const int *p; int *q = const_cast<int *>(p);",
                          varDecl(hasInitializer(implicitCastExpr()))));
-
-  EXPECT_TRUE(notMatches("int x = (0);",
-                         varDecl(hasInitializer(implicitCastExpr()))));
 }
 
-TEST(Statement, DoesNotMatchDeclarations) {
-  EXPECT_TRUE(notMatches("class X {};", stmt()));
+TEST_P(ASTMatchersTest, Stmt_DoesNotMatchDeclarations) {
+  EXPECT_TRUE(notMatches("struct X {};", stmt()));
 }
 
-TEST(Statement, MatchesCompoundStatments) {
+TEST_P(ASTMatchersTest, Stmt_MatchesCompoundStatments) {
   EXPECT_TRUE(matches("void x() {}", stmt()));
 }
 
-TEST(DeclarationStatement, DoesNotMatchCompoundStatements) {
+TEST_P(ASTMatchersTest, DeclStmt_DoesNotMatchCompoundStatements) {
   EXPECT_TRUE(notMatches("void x() {}", declStmt()));
 }
 
-TEST(DeclarationStatement, MatchesVariableDeclarationStatements) {
+TEST_P(ASTMatchersTest, DeclStmt_MatchesVariableDeclarationStatements) {
   EXPECT_TRUE(matches("void x() { int a; }", declStmt()));
 }
 
-TEST(ExprWithCleanups, MatchesExprWithCleanups) {
+TEST_P(ASTMatchersTest, ExprWithCleanups_MatchesExprWithCleanups) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("struct Foo { ~Foo(); };"
                       "const Foo f = Foo();",
                       traverse(ast_type_traits::TK_AsIs,
@@ -1077,20 +1376,30 @@
                                 varDecl(hasInitializer(exprWithCleanups())))));
 }
 
-TEST(InitListExpression, MatchesInitListExpression) {
+TEST_P(ASTMatchersTest, InitListExpr) {
   EXPECT_TRUE(matches("int a[] = { 1, 2 };",
                       initListExpr(hasType(asString("int [2]")))));
-  EXPECT_TRUE(matches("struct B { int x, y; }; B b = { 5, 6 };",
+  EXPECT_TRUE(matches("struct B { int x, y; }; struct B b = { 5, 6 };",
                       initListExpr(hasType(recordDecl(hasName("B"))))));
-  EXPECT_TRUE(matches("struct S { S(void (*a)()); };"
-                        "void f();"
-                        "S s[1] = { &f };",
-                      declRefExpr(to(functionDecl(hasName("f"))))));
   EXPECT_TRUE(
     matches("int i[1] = {42, [0] = 43};", integerLiteral(equals(42))));
 }
 
-TEST(CXXStdInitializerListExpression, MatchesCXXStdInitializerListExpression) {
+TEST_P(ASTMatchersTest, InitListExpr_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(matches("struct S { S(void (*a)()); };"
+                      "void f();"
+                      "S s[1] = { &f };",
+                      declRefExpr(to(functionDecl(hasName("f"))))));
+}
+
+TEST_P(ASTMatchersTest,
+       CXXStdInitializerListExpression_MatchesCXXStdInitializerListExpression) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   StringRef code = "namespace std {"
                    "template <typename> class initializer_list {"
                    "  public: initializer_list() noexcept {}"
@@ -1117,54 +1426,65 @@
                          cxxStdInitializerListExpr()));
 }
 
-TEST(UsingDeclaration, MatchesUsingDeclarations) {
+TEST_P(ASTMatchersTest, UsingDecl_MatchesUsingDeclarations) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("namespace X { int x; } using X::x;",
                       usingDecl()));
 }
 
-TEST(UsingDeclaration, MatchesShadowUsingDelcarations) {
+TEST_P(ASTMatchersTest, UsingDecl_MatchesShadowUsingDelcarations) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("namespace f { int a; } using f::a;",
                       usingDecl(hasAnyUsingShadowDecl(hasName("a")))));
 }
 
-TEST(UsingDirectiveDeclaration, MatchesUsingNamespace) {
+TEST_P(ASTMatchersTest, UsingDirectiveDecl_MatchesUsingNamespace) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("namespace X { int x; } using namespace X;",
                       usingDirectiveDecl()));
   EXPECT_FALSE(
     matches("namespace X { int x; } using X::x;", usingDirectiveDecl()));
 }
 
-
-TEST(While, MatchesWhileLoops) {
+TEST_P(ASTMatchersTest, WhileStmt) {
   EXPECT_TRUE(notMatches("void x() {}", whileStmt()));
-  EXPECT_TRUE(matches("void x() { while(true); }", whileStmt()));
-  EXPECT_TRUE(notMatches("void x() { do {} while(true); }", whileStmt()));
+  EXPECT_TRUE(matches("void x() { while(1); }", whileStmt()));
+  EXPECT_TRUE(notMatches("void x() { do {} while(1); }", whileStmt()));
 }
 
-TEST(Do, MatchesDoLoops) {
-  EXPECT_TRUE(matches("void x() { do {} while(true); }", doStmt()));
-  EXPECT_TRUE(matches("void x() { do ; while(false); }", doStmt()));
+TEST_P(ASTMatchersTest, DoStmt_MatchesDoLoops) {
+  EXPECT_TRUE(matches("void x() { do {} while(1); }", doStmt()));
+  EXPECT_TRUE(matches("void x() { do ; while(0); }", doStmt()));
 }
 
-TEST(Do, DoesNotMatchWhileLoops) {
-  EXPECT_TRUE(notMatches("void x() { while(true) {} }", doStmt()));
+TEST_P(ASTMatchersTest, DoStmt_DoesNotMatchWhileLoops) {
+  EXPECT_TRUE(notMatches("void x() { while(1) {} }", doStmt()));
 }
 
-TEST(SwitchCase, MatchesCase) {
+TEST_P(ASTMatchersTest, SwitchCase_MatchesCase) {
   EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchCase()));
   EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchCase()));
   EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchCase()));
   EXPECT_TRUE(notMatches("void x() { switch(42) {} }", switchCase()));
 }
 
-TEST(SwitchCase, MatchesSwitch) {
+TEST_P(ASTMatchersTest, SwitchCase_MatchesSwitch) {
   EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchStmt()));
   EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchStmt()));
   EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchStmt()));
   EXPECT_TRUE(notMatches("void x() {}", switchStmt()));
 }
 
-TEST(ExceptionHandling, SimpleCases) {
+TEST_P(ASTMatchersTest, CxxExceptionHandling_SimpleCases) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxCatchStmt()));
   EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxTryStmt()));
   EXPECT_TRUE(
@@ -1183,18 +1503,18 @@
                          varDecl(isExceptionVariable())));
 }
 
-TEST(ParenExpression, SimpleCases) {
+TEST_P(ASTMatchersTest, ParenExpr_SimpleCases) {
   EXPECT_TRUE(
       matches("int i = (3);", traverse(ast_type_traits::TK_AsIs, parenExpr())));
   EXPECT_TRUE(matches("int i = (3 + 7);",
                       traverse(ast_type_traits::TK_AsIs, parenExpr())));
   EXPECT_TRUE(notMatches("int i = 3;",
                          traverse(ast_type_traits::TK_AsIs, parenExpr())));
-  EXPECT_TRUE(notMatches("int foo() { return 1; }; int a = foo();",
+  EXPECT_TRUE(notMatches("int f() { return 1; }; void g() { int a = f(); }",
                          traverse(ast_type_traits::TK_AsIs, parenExpr())));
 }
 
-TEST(ParenExpression, IgnoringParens) {
+TEST_P(ASTMatchersTest, IgnoringParens) {
   EXPECT_FALSE(matches(
       "const char* str = (\"my-string\");",
       traverse(ast_type_traits::TK_AsIs,
@@ -1205,11 +1525,11 @@
                                    ignoringParens(stringLiteral()))))));
 }
 
-TEST(TypeMatching, MatchesTypes) {
+TEST_P(ASTMatchersTest, QualType) {
   EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
 }
 
-TEST(TypeMatching, MatchesConstantArrayTypes) {
+TEST_P(ASTMatchersTest, ConstantArrayType) {
   EXPECT_TRUE(matches("int a[2];", constantArrayType()));
   EXPECT_TRUE(notMatches(
     "void f() { int a[] = { 2, 3 }; int b[a[0]]; }",
@@ -1220,7 +1540,10 @@
   EXPECT_TRUE(notMatches("int c[41], d[43];", constantArrayType(hasSize(42))));
 }
 
-TEST(TypeMatching, MatchesDependentSizedArrayTypes) {
+TEST_P(ASTMatchersTest, DependentSizedArrayType) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches(
     "template <typename T, int Size> class array { T data[Size]; };",
     dependentSizedArrayType()));
@@ -1229,7 +1552,7 @@
     dependentSizedArrayType()));
 }
 
-TEST(TypeMatching, MatchesIncompleteArrayType) {
+TEST_P(ASTMatchersTest, IncompleteArrayType) {
   EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
   EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
 
@@ -1237,7 +1560,7 @@
                          incompleteArrayType()));
 }
 
-TEST(TypeMatching, MatchesVariableArrayType) {
+TEST_P(ASTMatchersTest, VariableArrayType) {
   EXPECT_TRUE(matches("void f(int b) { int a[b]; }", variableArrayType()));
   EXPECT_TRUE(notMatches("int a[] = {2, 3}; int b[42];", variableArrayType()));
 
@@ -1247,8 +1570,7 @@
       varDecl(hasName("b")))))))));
 }
 
-
-TEST(TypeMatching, MatchesAtomicTypes) {
+TEST_P(ASTMatchersTest, AtomicType) {
   if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getOS() !=
     llvm::Triple::Win32) {
     // FIXME: Make this work for MSVC.
@@ -1261,7 +1583,10 @@
   }
 }
 
-TEST(TypeMatching, MatchesAutoTypes) {
+TEST_P(ASTMatchersTest, AutoType) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("auto i = 2;", autoType()));
   EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }",
                       autoType()));
@@ -1278,34 +1603,48 @@
   //                       autoType(hasDeducedType(isInteger()))));
 }
 
-TEST(TypeMatching, MatchesDeclTypes) {
+TEST_P(ASTMatchersTest, DecltypeType) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("decltype(1 + 1) sum = 1 + 1;", decltypeType()));
   EXPECT_TRUE(matches("decltype(1 + 1) sum = 1 + 1;",
                       decltypeType(hasUnderlyingType(isInteger()))));
 }
 
-TEST(TypeMatching, MatchesFunctionTypes) {
+TEST_P(ASTMatchersTest, FunctionType) {
   EXPECT_TRUE(matches("int (*f)(int);", functionType()));
   EXPECT_TRUE(matches("void f(int i) {}", functionType()));
 }
 
-TEST(TypeMatching, IgnoringParens) {
+TEST_P(ASTMatchersTest, IgnoringParens_Type) {
   EXPECT_TRUE(
       notMatches("void (*fp)(void);", pointerType(pointee(functionType()))));
   EXPECT_TRUE(matches("void (*fp)(void);",
                       pointerType(pointee(ignoringParens(functionType())))));
 }
 
-TEST(TypeMatching, MatchesFunctionProtoTypes) {
+TEST_P(ASTMatchersTest, FunctionProtoType) {
   EXPECT_TRUE(matches("int (*f)(int);", functionProtoType()));
   EXPECT_TRUE(matches("void f(int i);", functionProtoType()));
+  EXPECT_TRUE(matches("void f(void);", functionProtoType(parameterCountIs(0))));
+}
+
+TEST_P(ASTMatchersTest, FunctionProtoType_C) {
+  if (!GetParam().isC()) {
+    return;
+  }
+  EXPECT_TRUE(notMatches("void f();", functionProtoType()));
+}
+
+TEST_P(ASTMatchersTest, FunctionProtoType_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("void f();", functionProtoType(parameterCountIs(0))));
-  EXPECT_TRUE(notMatchesC("void f();", functionProtoType()));
-  EXPECT_TRUE(
-    matchesC("void f(void);", functionProtoType(parameterCountIs(0))));
 }
 
-TEST(TypeMatching, MatchesParenType) {
+TEST_P(ASTMatchersTest, ParenType) {
   EXPECT_TRUE(
     matches("int (*array)[4];", varDecl(hasType(pointsTo(parenType())))));
   EXPECT_TRUE(notMatches("int *array[4];", varDecl(hasType(parenType()))));
@@ -1318,7 +1657,7 @@
     varDecl(hasType(pointsTo(parenType(innerType(functionType())))))));
 }
 
-TEST(TypeMatching, PointerTypes) {
+TEST_P(ASTMatchersTest, PointerType) {
   // FIXME: Reactive when these tests can be more specific (not matching
   // implicit code on certain platforms), likely when we have hasDescendant for
   // Types/TypeLocs.
@@ -1340,21 +1679,7 @@
     "int* b; int* * const a = &b;",
     loc(qualType(isConstQualified(), pointerType()))));
 
-  StringRef Fragment = "struct A { int i; }; int A::* ptr = &A::i;";
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
-                                           hasType(blockPointerType()))));
-  EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"),
-                                        hasType(memberPointerType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
-                                           hasType(pointerType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
-                                           hasType(referenceType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
-                                           hasType(lValueReferenceType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
-                                           hasType(rValueReferenceType()))));
-
-  Fragment = "int *ptr;";
+  StringRef Fragment = "int *ptr;";
   EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
                                            hasType(blockPointerType()))));
   EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
@@ -1363,37 +1688,65 @@
                                         hasType(pointerType()))));
   EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
                                            hasType(referenceType()))));
+}
+
+TEST_P(ASTMatchersTest, PointerType_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  StringRef Fragment = "struct A { int i; }; int A::* ptr = &A::i;";
+  EXPECT_TRUE(notMatches(Fragment,
+                         varDecl(hasName("ptr"), hasType(blockPointerType()))));
+  EXPECT_TRUE(
+      matches(Fragment, varDecl(hasName("ptr"), hasType(memberPointerType()))));
+  EXPECT_TRUE(
+      notMatches(Fragment, varDecl(hasName("ptr"), hasType(pointerType()))));
+  EXPECT_TRUE(
+      notMatches(Fragment, varDecl(hasName("ptr"), hasType(referenceType()))));
+  EXPECT_TRUE(notMatches(
+      Fragment, varDecl(hasName("ptr"), hasType(lValueReferenceType()))));
+  EXPECT_TRUE(notMatches(
+      Fragment, varDecl(hasName("ptr"), hasType(rValueReferenceType()))));
 
   Fragment = "int a; int &ref = a;";
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(blockPointerType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(memberPointerType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(pointerType()))));
-  EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
-                                        hasType(referenceType()))));
-  EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
-                                        hasType(lValueReferenceType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(rValueReferenceType()))));
+  EXPECT_TRUE(notMatches(Fragment,
+                         varDecl(hasName("ref"), hasType(blockPointerType()))));
+  EXPECT_TRUE(notMatches(
+      Fragment, varDecl(hasName("ref"), hasType(memberPointerType()))));
+  EXPECT_TRUE(
+      notMatches(Fragment, varDecl(hasName("ref"), hasType(pointerType()))));
+  EXPECT_TRUE(
+      matches(Fragment, varDecl(hasName("ref"), hasType(referenceType()))));
+  EXPECT_TRUE(matches(Fragment,
+                      varDecl(hasName("ref"), hasType(lValueReferenceType()))));
+  EXPECT_TRUE(notMatches(
+      Fragment, varDecl(hasName("ref"), hasType(rValueReferenceType()))));
+}
 
-  Fragment = "int &&ref = 2;";
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(blockPointerType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(memberPointerType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(pointerType()))));
-  EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
-                                        hasType(referenceType()))));
-  EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
-                                           hasType(lValueReferenceType()))));
-  EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
-                                        hasType(rValueReferenceType()))));
+TEST_P(ASTMatchersTest, PointerType_CXX11) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  StringRef Fragment = "int &&ref = 2;";
+  EXPECT_TRUE(notMatches(Fragment,
+                         varDecl(hasName("ref"), hasType(blockPointerType()))));
+  EXPECT_TRUE(notMatches(
+      Fragment, varDecl(hasName("ref"), hasType(memberPointerType()))));
+  EXPECT_TRUE(
+      notMatches(Fragment, varDecl(hasName("ref"), hasType(pointerType()))));
+  EXPECT_TRUE(
+      matches(Fragment, varDecl(hasName("ref"), hasType(referenceType()))));
+  EXPECT_TRUE(notMatches(
+      Fragment, varDecl(hasName("ref"), hasType(lValueReferenceType()))));
+  EXPECT_TRUE(matches(Fragment,
+                      varDecl(hasName("ref"), hasType(rValueReferenceType()))));
 }
 
-TEST(TypeMatching, AutoRefTypes) {
+TEST_P(ASTMatchersTest, AutoRefTypes) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+
   StringRef Fragment = "auto a = 1;"
                        "auto b = a;"
                        "auto &c = a;"
@@ -1423,14 +1776,28 @@
                                         hasType(rValueReferenceType()))));
 }
 
-TEST(TypeMatching, MatchesEnumTypes) {
+TEST_P(ASTMatchersTest, EnumType) {
+  EXPECT_TRUE(
+      matches("enum Color { Green }; enum Color color;", loc(enumType())));
+}
+
+TEST_P(ASTMatchersTest, EnumType_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("enum Color { Green }; Color color;",
                       loc(enumType())));
+}
+
+TEST_P(ASTMatchersTest, EnumType_CXX11) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   EXPECT_TRUE(matches("enum class Color { Green }; Color color;",
                       loc(enumType())));
 }
 
-TEST(TypeMatching, MatchesPointersToConstTypes) {
+TEST_P(ASTMatchersTest, PointerType_MatchesPointersToConstTypes) {
   EXPECT_TRUE(matches("int b; int * const a = &b;",
                       loc(pointerType())));
   EXPECT_TRUE(matches("int b; int * const a = &b;",
@@ -1443,31 +1810,49 @@
     pointerType(pointee(builtinType()))));
 }
 
-TEST(TypeMatching, MatchesTypedefTypes) {
+TEST_P(ASTMatchersTest, TypedefType) {
   EXPECT_TRUE(matches("typedef int X; X a;", varDecl(hasName("a"),
                                                      hasType(typedefType()))));
 }
 
-TEST(TypeMatching, MatchesTemplateSpecializationType) {
+TEST_P(ASTMatchersTest, TemplateSpecializationType) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("template <typename T> class A{}; A<int> a;",
                       templateSpecializationType()));
 }
 
-TEST(TypeMatching, MatchesDeucedTemplateSpecializationType) {
+TEST_P(ASTMatchersTest, DeducedTemplateSpecializationType) {
+  if (!GetParam().isCXX17OrLater()) {
+    return;
+  }
   EXPECT_TRUE(
       matches("template <typename T> class A{ public: A(T) {} }; A a(1);",
-              deducedTemplateSpecializationType(), langCxx17OrLater()));
+              deducedTemplateSpecializationType()));
 }
 
-TEST(TypeMatching, MatchesRecordType) {
-  EXPECT_TRUE(matches("class C{}; C c;", recordType()));
-  EXPECT_TRUE(matches("struct S{}; S s;",
+TEST_P(ASTMatchersTest, RecordType) {
+  EXPECT_TRUE(matches("struct S {}; struct S s;",
                       recordType(hasDeclaration(recordDecl(hasName("S"))))));
   EXPECT_TRUE(notMatches("int i;",
                          recordType(hasDeclaration(recordDecl(hasName("S"))))));
 }
 
-TEST(TypeMatching, MatchesElaboratedType) {
+TEST_P(ASTMatchersTest, RecordType_CXX) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(matches("class C {}; C c;", recordType()));
+  EXPECT_TRUE(matches("struct S {}; S s;",
+                      recordType(hasDeclaration(recordDecl(hasName("S"))))));
+}
+
+TEST_P(ASTMatchersTest, ElaboratedType) {
+  if (!GetParam().isCXX()) {
+    // FIXME: Add a test for `elaboratedType()` that does not depend on C++.
+    return;
+  }
   EXPECT_TRUE(matches(
     "namespace N {"
       "  namespace M {"
@@ -1479,7 +1864,10 @@
   EXPECT_TRUE(notMatches("class C {}; C c;", elaboratedType()));
 }
 
-TEST(TypeMatching, MatchesSubstTemplateTypeParmType) {
+TEST_P(ASTMatchersTest, SubstTemplateTypeParmType) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   StringRef code = "template <typename T>"
                    "int F() {"
                    "  return 1 + T();"
@@ -1491,7 +1879,10 @@
     expr(hasType(substTemplateTypeParmType()))))));
 }
 
-TEST(NNS, MatchesNestedNameSpecifiers) {
+TEST_P(ASTMatchersTest, NestedNameSpecifier) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;",
                       nestedNameSpecifier()));
   EXPECT_TRUE(matches("template <typename T> class A { typename T::B b; };",
@@ -1509,17 +1900,23 @@
     nestedNameSpecifier()));
 }
 
-TEST(NullStatement, SimpleCases) {
+TEST_P(ASTMatchersTest, NullStmt) {
   EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
   EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));
 }
 
-TEST(NS, Alias) {
+TEST_P(ASTMatchersTest, NamespaceAliasDecl) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches("namespace test {} namespace alias = ::test;",
                       namespaceAliasDecl(hasName("alias"))));
 }
 
-TEST(NNS, MatchesTypes) {
+TEST_P(ASTMatchersTest, NestedNameSpecifier_MatchesTypes) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
     specifiesType(hasDeclaration(recordDecl(hasName("A")))));
   EXPECT_TRUE(matches("struct A { struct B {}; }; A::B b;", Matcher));
@@ -1528,7 +1925,10 @@
   EXPECT_TRUE(notMatches("namespace A { struct B {}; } A::B b;", Matcher));
 }
 
-TEST(NNS, MatchesNamespaceDecls) {
+TEST_P(ASTMatchersTest, NestedNameSpecifier_MatchesNamespaceDecls) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
     specifiesNamespace(hasName("ns")));
   EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", Matcher));
@@ -1536,7 +1936,11 @@
   EXPECT_TRUE(notMatches("struct ns { struct A {}; }; ns::A a;", Matcher));
 }
 
-TEST(NNS, MatchesNestedNameSpecifierPrefixes) {
+TEST_P(ASTMatchersTest,
+       NestedNameSpecifier_MatchesNestedNameSpecifierPrefixes) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matches(
     "struct A { struct B { struct C {}; }; }; A::B::C c;",
     nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A"))))));
@@ -1550,7 +1954,6 @@
       specifiesTypeLoc(loc(qualType(asString("struct N::A"))))))));
 }
 
-
 template <typename T>
 class VerifyAncestorHasChildIsEqual : public BoundNodesCallback {
 public:
@@ -1591,41 +1994,68 @@
   }
 };
 
-TEST(IsEqualTo, MatchesNodesByIdentity) {
+TEST_P(ASTMatchersTest, IsEqualTo_MatchesNodesByIdentity) {
   EXPECT_TRUE(matchAndVerifyResultTrue(
-    "class X { class Y {}; };", recordDecl(hasName("::X::Y")).bind(""),
-    std::make_unique<VerifyAncestorHasChildIsEqual<CXXRecordDecl>>()));
+      "void f() { if (1) if(1) {} }", ifStmt().bind(""),
+      std::make_unique<VerifyAncestorHasChildIsEqual<IfStmt>>()));
+}
+
+TEST_P(ASTMatchersTest, IsEqualTo_MatchesNodesByIdentity_Cxx) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
   EXPECT_TRUE(matchAndVerifyResultTrue(
-    "void f() { if (true) if(true) {} }", ifStmt().bind(""),
-    std::make_unique<VerifyAncestorHasChildIsEqual<IfStmt>>()));
+      "class X { class Y {}; };", recordDecl(hasName("::X::Y")).bind(""),
+      std::make_unique<VerifyAncestorHasChildIsEqual<CXXRecordDecl>>()));
   EXPECT_TRUE(matchAndVerifyResultTrue(
-    "class X { class Y {} y; };",
-    fieldDecl(hasName("y"), hasType(type().bind(""))).bind("decl"),
-    std::make_unique<VerifyAncestorHasChildIsEqual<Type>>()));
+      "class X { class Y {} y; };",
+      fieldDecl(hasName("y"), hasType(type().bind(""))).bind("decl"),
+      std::make_unique<VerifyAncestorHasChildIsEqual<Type>>()));
 }
 
-TEST(TypedefDeclMatcher, Match) {
+TEST_P(ASTMatchersTest, TypedefDecl) {
   EXPECT_TRUE(matches("typedef int typedefDeclTest;",
                       typedefDecl(hasName("typedefDeclTest"))));
-  EXPECT_TRUE(notMatches("using typedefDeclTest2 = int;",
-                         typedefDecl(hasName("typedefDeclTest2"))));
 }
 
-TEST(TypeAliasDeclMatcher, Match) {
-  EXPECT_TRUE(matches("using typeAliasTest2 = int;",
-                      typeAliasDecl(hasName("typeAliasTest2"))));
+TEST_P(ASTMatchersTest, TypedefDecl_Cxx) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(notMatches("using typedefDeclTest = int;",
+                         typedefDecl(hasName("typedefDeclTest"))));
+}
+
+TEST_P(ASTMatchersTest, TypeAliasDecl) {
   EXPECT_TRUE(notMatches("typedef int typeAliasTest;",
                          typeAliasDecl(hasName("typeAliasTest"))));
 }
 
-TEST(TypedefNameDeclMatcher, Match) {
+TEST_P(ASTMatchersTest, TypeAliasDecl_CXX) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(matches("using typeAliasTest = int;",
+                      typeAliasDecl(hasName("typeAliasTest"))));
+}
+
+TEST_P(ASTMatchersTest, TypedefNameDecl) {
   EXPECT_TRUE(matches("typedef int typedefNameDeclTest1;",
                       typedefNameDecl(hasName("typedefNameDeclTest1"))));
-  EXPECT_TRUE(matches("using typedefNameDeclTest2 = int;",
-                      typedefNameDecl(hasName("typedefNameDeclTest2"))));
 }
 
-TEST(TypeAliasTemplateDeclMatcher, Match) {
+TEST_P(ASTMatchersTest, TypedefNameDecl_CXX) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(matches("using typedefNameDeclTest = int;",
+                      typedefNameDecl(hasName("typedefNameDeclTest"))));
+}
+
+TEST_P(ASTMatchersTest, TypeAliasTemplateDecl) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
   StringRef Code = R"(
     template <typename T>
     class X { T t; };
@@ -1641,8 +2071,8 @@
       notMatches(Code, typeAliasTemplateDecl(hasName("typeAliasDecl"))));
 }
 
-TEST(ObjCMessageExprMatcher, SimpleExprs) {
-  // don't find ObjCMessageExpr where none are present
+TEST(ASTMatchersTestObjC, ObjCMessageExpr) {
+  // Don't find ObjCMessageExpr where none are present.
   EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything())));
 
   StringRef Objc1String = "@interface Str "
@@ -1698,7 +2128,7 @@
     )));
 }
 
-TEST(ObjCDeclMatcher, CoreDecls) {
+TEST(ASTMatchersTestObjC, ObjCDecls) {
   StringRef ObjCString = "@protocol Proto "
                          "- (void)protoDidThing; "
                          "@end "
@@ -1745,7 +2175,7 @@
     objcPropertyDecl(hasName("enabled"))));
 }
 
-TEST(ObjCStmtMatcher, ExceptionStmts) {
+TEST(ASTMatchersTestObjC, ObjCExceptionStmts) {
   StringRef ObjCString = "void f(id obj) {"
                          "  @try {"
                          "    @throw obj;"
@@ -1767,7 +2197,7 @@
     objcFinallyStmt()));
 }
 
-TEST(ObjCAutoreleaseMatcher, AutoreleasePool) {
+TEST(ASTMatchersTestObjC, ObjCAutoreleasePoolStmt) {
   StringRef ObjCString = "void f() {"
                          "@autoreleasepool {"
                          "  int x = 1;"
@@ -1778,7 +2208,7 @@
   EXPECT_FALSE(matchesObjC(ObjCStringNoPool, autoreleasePoolStmt()));
 }
 
-TEST(OMPExecutableDirective, Matches) {
+TEST(ASTMatchersTestOpenMP, OMPExecutableDirective) {
   auto Matcher = stmt(ompExecutableDirective());
 
   StringRef Source0 = R"(
@@ -1802,7 +2232,7 @@
   EXPECT_TRUE(notMatchesWithOpenMP(Source2, Matcher));
 }
 
-TEST(OMPDefaultClause, Matches) {
+TEST(ASTMatchersTestOpenMP, OMPDefaultClause) {
   auto Matcher = ompExecutableDirective(hasAnyClause(ompDefaultClause()));
 
   StringRef Source0 = R"(
@@ -1840,8 +2270,19 @@
   EXPECT_TRUE(notMatchesWithOpenMP(Source4, Matcher));
 }
 
-TEST(MatchFinderAPI, matchesDynamic) {
+TEST(ASTMatchersTest, Finder_DynamicOnlyAcceptsSomeMatchers) {
+  MatchFinder Finder;
+  EXPECT_TRUE(Finder.addDynamicMatcher(decl(), nullptr));
+  EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), nullptr));
+  EXPECT_TRUE(
+      Finder.addDynamicMatcher(constantArrayType(hasSize(42)), nullptr));
+
+  // Do not accept non-toplevel matchers.
+  EXPECT_FALSE(Finder.addDynamicMatcher(isMain(), nullptr));
+  EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr));
+}
 
+TEST(MatchFinderAPI, MatchesDynamic) {
   StringRef SourceCode = "struct A { void f() {} };";
   auto Matcher = functionDecl(isDefinition()).bind("method");
 
@@ -1864,5 +2305,35 @@
   EXPECT_EQ(MethodNode, GlobalMethodNode);
 }
 
+static std::vector<TestClangConfig> allTestClangConfigs() {
+  std::vector<TestClangConfig> all_configs;
+  for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11,
+                            Lang_CXX14, Lang_CXX17, Lang_CXX20}) {
+    TestClangConfig config;
+    config.Language = lang;
+
+    // Use an unknown-unknown triple so we don't instantiate the full system
+    // toolchain.  On Linux, instantiating the toolchain involves stat'ing
+    // large portions of /usr/lib, and this slows down not only this test, but
+    // all other tests, via contention in the kernel.
+    //
+    // FIXME: This is a hack to work around the fact that there's no way to do
+    // the equivalent of runToolOnCodeWithArgs without instantiating a full
+    // Driver.  We should consider having a function, at least for tests, that
+    // invokes cc1.
+    config.Target = "i386-unknown-unknown";
+    all_configs.push_back(config);
+
+    // Windows target is interesting to test because it enables
+    // `-fdelayed-template-parsing`.
+    config.Target = "x86_64-pc-win32-msvc";
+    all_configs.push_back(config);
+  }
+  return all_configs;
+}
+
+INSTANTIATE_TEST_CASE_P(ASTMatchersTests, ASTMatchersTest,
+                        testing::ValuesIn(allTestClangConfigs()), );
+
 } // namespace ast_matchers
 } // namespace clang
Index: clang/include/clang/Testing/TestClangConfig.h
===================================================================
--- /dev/null
+++ clang/include/clang/Testing/TestClangConfig.h
@@ -0,0 +1,85 @@
+//===--- TestClangConfig.h ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TESTING_TESTCLANGCONFIG_H
+#define LLVM_CLANG_TESTING_TESTCLANGCONFIG_H
+
+#include "clang/Testing/CommandLineArgs.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+/// A Clang configuration for end-to-end tests that can be converted to
+/// command line arguments for the driver.
+///
+/// The configuration is represented as typed, named values, making it easier
+/// and safer to work with compared to an array of string command line flags.
+struct TestClangConfig {
+  TestLanguage Language;
+
+  /// The argument of the `-target` command line flag.
+  std::string Target;
+
+  bool isC() const { return Language == Lang_C89 || Language == Lang_C99; }
+
+  bool isC99OrLater() const { return Language == Lang_C99; }
+
+  bool isCXX() const {
+    return Language == Lang_CXX03 || Language == Lang_CXX11 ||
+           Language == Lang_CXX14 || Language == Lang_CXX17 ||
+           Language == Lang_CXX20;
+  }
+
+  bool isCXX11OrLater() const {
+    return Language == Lang_CXX11 || Language == Lang_CXX14 ||
+           Language == Lang_CXX17 || Language == Lang_CXX20;
+  }
+
+  bool isCXX14OrLater() const {
+    return Language == Lang_CXX14 || Language == Lang_CXX17 ||
+           Language == Lang_CXX20;
+  }
+
+  bool isCXX17OrLater() const {
+    return Language == Lang_CXX17 || Language == Lang_CXX20;
+  }
+
+  bool supportsCXXDynamicExceptionSpecification() const {
+    return Language == Lang_CXX03 || Language == Lang_CXX11 ||
+           Language == Lang_CXX14;
+  }
+
+  bool hasDelayedTemplateParsing() const {
+    return Target == "x86_64-pc-win32-msvc";
+  }
+
+  std::vector<std::string> getCommandLineArgs() const {
+    std::vector<std::string> Result = getCommandLineArgsForTesting(Language);
+    Result.push_back("-target");
+    Result.push_back(Target);
+    return Result;
+  }
+
+  std::string toString() const {
+    std::string Result;
+    llvm::raw_string_ostream OS(Result);
+    OS << "{ Language=" << Language << ", Target=" << Target << " }";
+    return OS.str();
+  }
+
+  friend std::ostream &operator<<(std::ostream &OS,
+                                  const TestClangConfig &ClangConfig) {
+    return OS << ClangConfig.toString();
+  }
+};
+
+} // end namespace clang
+
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to