summaryrefslogtreecommitdiffstats
path: root/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
diff options
context:
space:
mode:
authorPiotr Padlewski <piotr.padlewski@gmail.com>2016-05-17 19:22:57 +0000
committerPiotr Padlewski <piotr.padlewski@gmail.com>2016-05-17 19:22:57 +0000
commit051792e88ef67903a1754e83c7c896f55a38b195 (patch)
tree5f0245fbfd1f3ce5d70fbe721ced98d26bbaa120 /unittests/ASTMatchers/ASTMatchersInternalTest.cpp
parent89a379de617e1914a6aa0ab8ad757bc3a74800be (diff)
Dividied ASTMatcherTests into 4 files
fix for long compilation [20061] http://reviews.llvm.org/D20210 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269802 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ASTMatchers/ASTMatchersInternalTest.cpp')
-rw-r--r--unittests/ASTMatchers/ASTMatchersInternalTest.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersInternalTest.cpp b/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
new file mode 100644
index 0000000000..c12056f444
--- /dev/null
+++ b/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
@@ -0,0 +1,240 @@
+// unittests/ASTMatchers/ASTMatchersInternalTest.cpp - AST matcher unit tests //
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTMatchersTest.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+#if GTEST_HAS_DEATH_TEST
+TEST(HasNameDeathTest, DiesOnEmptyName) {
+ ASSERT_DEBUG_DEATH({
+ DeclarationMatcher HasEmptyName = recordDecl(hasName(""));
+ EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
+ }, "");
+}
+
+TEST(HasNameDeathTest, DiesOnEmptyPattern) {
+ ASSERT_DEBUG_DEATH({
+ DeclarationMatcher HasEmptyName = recordDecl(matchesName(""));
+ EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
+ }, "");
+}
+
+TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
+ ASSERT_DEBUG_DEATH({
+ DeclarationMatcher IsDerivedFromEmpty = cxxRecordDecl(isDerivedFrom(""));
+ EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty));
+ }, "");
+}
+#endif
+
+TEST(ConstructVariadic, MismatchedTypes_Regression) {
+ EXPECT_TRUE(
+ matches("const int a = 0;",
+ internal::DynTypedMatcher::constructVariadic(
+ internal::DynTypedMatcher::VO_AnyOf,
+ ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(),
+ {isConstQualified(), arrayType()})
+ .convertTo<QualType>()));
+}
+
+// For testing AST_MATCHER_P().
+AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) {
+ // Make sure all special variables are used: node, match_finder,
+ // bound_nodes_builder, and the parameter named 'AMatcher'.
+ return AMatcher.matches(Node, Finder, Builder);
+}
+
+TEST(AstMatcherPMacro, Works) {
+ DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b")));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
+ HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
+ HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("a")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
+ HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
+}
+
+AST_POLYMORPHIC_MATCHER_P(polymorphicHas,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt),
+ internal::Matcher<Decl>, AMatcher) {
+ return Finder->matchesChildOf(
+ Node, AMatcher, Builder,
+ ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
+ ASTMatchFinder::BK_First);
+}
+
+TEST(AstPolymorphicMatcherPMacro, Works) {
+ DeclarationMatcher HasClassB =
+ polymorphicHas(recordDecl(hasName("B")).bind("b"));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
+ HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
+ HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("a")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
+ HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
+
+ StatementMatcher StatementHasClassB =
+ polymorphicHas(recordDecl(hasName("B")));
+
+ EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB));
+}
+
+TEST(MatchFinder, CheckProfiling) {
+ MatchFinder::MatchFinderOptions Options;
+ llvm::StringMap<llvm::TimeRecord> Records;
+ Options.CheckProfiling.emplace(Records);
+ MatchFinder Finder(std::move(Options));
+
+ struct NamedCallback : public MatchFinder::MatchCallback {
+ void run(const MatchFinder::MatchResult &Result) override {}
+ StringRef getID() const override { return "MyID"; }
+ } Callback;
+ Finder.addMatcher(decl(), &Callback);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+
+ EXPECT_EQ(1u, Records.size());
+ EXPECT_EQ("MyID", Records.begin()->getKey());
+}
+
+class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
+public:
+ VerifyStartOfTranslationUnit() : Called(false) {}
+ void run(const MatchFinder::MatchResult &Result) override {
+ EXPECT_TRUE(Called);
+ }
+ void onStartOfTranslationUnit() override { Called = true; }
+ bool Called;
+};
+
+TEST(MatchFinder, InterceptsStartOfTranslationUnit) {
+ MatchFinder Finder;
+ VerifyStartOfTranslationUnit VerifyCallback;
+ Finder.addMatcher(decl(), &VerifyCallback);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+ EXPECT_TRUE(VerifyCallback.Called);
+
+ VerifyCallback.Called = false;
+ std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
+ ASSERT_TRUE(AST.get());
+ Finder.matchAST(AST->getASTContext());
+ EXPECT_TRUE(VerifyCallback.Called);
+}
+
+class VerifyEndOfTranslationUnit : public MatchFinder::MatchCallback {
+public:
+ VerifyEndOfTranslationUnit() : Called(false) {}
+ void run(const MatchFinder::MatchResult &Result) override {
+ EXPECT_FALSE(Called);
+ }
+ void onEndOfTranslationUnit() override { Called = true; }
+ bool Called;
+};
+
+TEST(MatchFinder, InterceptsEndOfTranslationUnit) {
+ MatchFinder Finder;
+ VerifyEndOfTranslationUnit VerifyCallback;
+ Finder.addMatcher(decl(), &VerifyCallback);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+ EXPECT_TRUE(VerifyCallback.Called);
+
+ VerifyCallback.Called = false;
+ std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
+ ASSERT_TRUE(AST.get());
+ Finder.matchAST(AST->getASTContext());
+ EXPECT_TRUE(VerifyCallback.Called);
+}
+
+TEST(Matcher, matchOverEntireASTContext) {
+ std::unique_ptr<ASTUnit> AST =
+ clang::tooling::buildASTFromCode("struct { int *foo; };");
+ ASSERT_TRUE(AST.get());
+ auto PT = selectFirst<PointerType>(
+ "x", match(pointerType().bind("x"), AST->getASTContext()));
+ EXPECT_NE(nullptr, PT);
+}
+
+TEST(IsInlineMatcher, IsInline) {
+ EXPECT_TRUE(matches("void g(); inline void f();",
+ functionDecl(isInline(), hasName("f"))));
+ EXPECT_TRUE(matches("namespace n { inline namespace m {} }",
+ namespaceDecl(isInline(), hasName("m"))));
+}
+
+// FIXME: Figure out how to specify paths so the following tests pass on
+// Windows.
+#ifndef LLVM_ON_WIN32
+
+TEST(Matcher, IsExpansionInMainFileMatcher) {
+ EXPECT_TRUE(matches("class X {};",
+ recordDecl(hasName("X"), isExpansionInMainFile())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile())));
+ FileContentMappings M;
+ M.push_back(std::make_pair("/other", "class X {};"));
+ EXPECT_TRUE(matchesConditionally("#include <other>\n",
+ recordDecl(isExpansionInMainFile()), false,
+ "-isystem/", M));
+}
+
+TEST(Matcher, IsExpansionInSystemHeader) {
+ FileContentMappings M;
+ M.push_back(std::make_pair("/other", "class X {};"));
+ EXPECT_TRUE(matchesConditionally(
+ "#include \"other\"\n", recordDecl(isExpansionInSystemHeader()), true,
+ "-isystem/", M));
+ EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+ recordDecl(isExpansionInSystemHeader()),
+ false, "-I/", M));
+ EXPECT_TRUE(notMatches("class X {};",
+ recordDecl(isExpansionInSystemHeader())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInSystemHeader())));
+}
+
+TEST(Matcher, IsExpansionInFileMatching) {
+ FileContentMappings M;
+ M.push_back(std::make_pair("/foo", "class A {};"));
+ M.push_back(std::make_pair("/bar", "class B {};"));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true,
+ "-isystem/", M));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("f.*"), hasName("X")), false,
+ "-isystem/", M));
+}
+
+#endif // LLVM_ON_WIN32
+
+} // end namespace ast_matchers
+} // end namespace clang