summaryrefslogtreecommitdiffstats
path: root/unittests/ASTMatchers/Dynamic
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-12-22 00:07:40 +0000
committerdim <dim@FreeBSD.org>2013-12-22 00:07:40 +0000
commit952eddef9aff85b1e92626e89baaf7a360e2ac85 (patch)
treedf8df0b0067b381eab470a3b8f28d14a552a6340 /unittests/ASTMatchers/Dynamic
parentea266cad53e3d49771fa38103913d3ec7a166694 (diff)
downloadFreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.zip
FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.tar.gz
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):
https://llvm.org/svn/llvm-project/cfe/branches/release_34@197841
Diffstat (limited to 'unittests/ASTMatchers/Dynamic')
-rw-r--r--unittests/ASTMatchers/Dynamic/CMakeLists.txt7
-rw-r--r--unittests/ASTMatchers/Dynamic/Makefile20
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp238
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp347
-rw-r--r--unittests/ASTMatchers/Dynamic/VariantValueTest.cpp144
5 files changed, 756 insertions, 0 deletions
diff --git a/unittests/ASTMatchers/Dynamic/CMakeLists.txt b/unittests/ASTMatchers/Dynamic/CMakeLists.txt
new file mode 100644
index 0000000..eb9fa54
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_clang_unittest(DynamicASTMatchersTests
+ VariantValueTest.cpp
+ ParserTest.cpp
+ RegistryTest.cpp)
+
+target_link_libraries(DynamicASTMatchersTests
+ gtest gtest_main clangASTMatchers clangDynamicASTMatchers clangTooling)
diff --git a/unittests/ASTMatchers/Dynamic/Makefile b/unittests/ASTMatchers/Dynamic/Makefile
new file mode 100644
index 0000000..66b183c
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/Makefile
@@ -0,0 +1,20 @@
+##===- unittests/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../../..
+
+TESTNAME = DynamicASTMatchers
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewriteCore.a clangRewriteFrontend.a clangParse.a clangSema.a \
+ clangAnalysis.a clangEdit.a clangAST.a clangASTMatchers.a \
+ clangLex.a clangBasic.a clangDynamicASTMatchers.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
new file mode 100644
index 0000000..f19ec51
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -0,0 +1,238 @@
+//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "gtest/gtest.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+class MockSema : public Parser::Sema {
+public:
+ virtual ~MockSema() {}
+
+ uint64_t expectMatcher(StringRef MatcherName) {
+ ast_matchers::internal::Matcher<Stmt> M = stmt();
+ ExpectedMatchers.insert(std::make_pair(MatcherName, M));
+ return M.getID();
+ }
+
+ void parse(StringRef Code) {
+ Diagnostics Error;
+ VariantValue Value;
+ Parser::parseExpression(Code, this, &Value, &Error);
+ Values.push_back(Value);
+ Errors.push_back(Error.toStringFull());
+ }
+
+ VariantMatcher actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
+ Matchers.push_back(ToStore);
+ return VariantMatcher::SingleMatcher(
+ ExpectedMatchers.find(MatcherName)->second);
+ }
+
+ struct MatcherInfo {
+ StringRef MatcherName;
+ SourceRange NameRange;
+ std::vector<ParserValue> Args;
+ std::string BoundID;
+ };
+
+ std::vector<std::string> Errors;
+ std::vector<VariantValue> Values;
+ std::vector<MatcherInfo> Matchers;
+ std::map<std::string, ast_matchers::internal::Matcher<Stmt> >
+ ExpectedMatchers;
+};
+
+TEST(ParserTest, ParseUnsigned) {
+ MockSema Sema;
+ Sema.parse("0");
+ Sema.parse("123");
+ Sema.parse("0x1f");
+ Sema.parse("12345678901");
+ Sema.parse("1a1");
+ EXPECT_EQ(5U, Sema.Values.size());
+ EXPECT_EQ(0U, Sema.Values[0].getUnsigned());
+ EXPECT_EQ(123U, Sema.Values[1].getUnsigned());
+ EXPECT_EQ(31U, Sema.Values[2].getUnsigned());
+ EXPECT_EQ("1:1: Error parsing unsigned token: <12345678901>", Sema.Errors[3]);
+ EXPECT_EQ("1:1: Error parsing unsigned token: <1a1>", Sema.Errors[4]);
+}
+
+TEST(ParserTest, ParseString) {
+ MockSema Sema;
+ Sema.parse("\"Foo\"");
+ Sema.parse("\"\"");
+ Sema.parse("\"Baz");
+ EXPECT_EQ(3ULL, Sema.Values.size());
+ EXPECT_EQ("Foo", Sema.Values[0].getString());
+ EXPECT_EQ("", Sema.Values[1].getString());
+ EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]);
+}
+
+bool matchesRange(const SourceRange &Range, unsigned StartLine,
+ unsigned EndLine, unsigned StartColumn, unsigned EndColumn) {
+ EXPECT_EQ(StartLine, Range.Start.Line);
+ EXPECT_EQ(EndLine, Range.End.Line);
+ EXPECT_EQ(StartColumn, Range.Start.Column);
+ EXPECT_EQ(EndColumn, Range.End.Column);
+ return Range.Start.Line == StartLine && Range.End.Line == EndLine &&
+ Range.Start.Column == StartColumn && Range.End.Column == EndColumn;
+}
+
+llvm::Optional<DynTypedMatcher> getSingleMatcher(const VariantValue &Value) {
+ llvm::Optional<DynTypedMatcher> Result =
+ Value.getMatcher().getSingleMatcher();
+ EXPECT_TRUE(Result.hasValue());
+ return Result;
+}
+
+TEST(ParserTest, ParseMatcher) {
+ MockSema Sema;
+ const uint64_t ExpectedFoo = Sema.expectMatcher("Foo");
+ const uint64_t ExpectedBar = Sema.expectMatcher("Bar");
+ const uint64_t ExpectedBaz = Sema.expectMatcher("Baz");
+ Sema.parse(" Foo ( Bar ( 17), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") ");
+ for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) {
+ EXPECT_EQ("", Sema.Errors[i]);
+ }
+
+ EXPECT_EQ(1ULL, Sema.Values.size());
+ EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID());
+
+ EXPECT_EQ(3ULL, Sema.Matchers.size());
+ const MockSema::MatcherInfo Bar = Sema.Matchers[0];
+ EXPECT_EQ("Bar", Bar.MatcherName);
+ EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 17));
+ EXPECT_EQ(1ULL, Bar.Args.size());
+ EXPECT_EQ(17U, Bar.Args[0].Value.getUnsigned());
+
+ const MockSema::MatcherInfo Baz = Sema.Matchers[1];
+ EXPECT_EQ("Baz", Baz.MatcherName);
+ EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 19, 10));
+ EXPECT_EQ(1ULL, Baz.Args.size());
+ EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString());
+
+ const MockSema::MatcherInfo Foo = Sema.Matchers[2];
+ EXPECT_EQ("Foo", Foo.MatcherName);
+ EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
+ EXPECT_EQ(2ULL, Foo.Args.size());
+ EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID());
+ EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID());
+ EXPECT_EQ("Yo!", Foo.BoundID);
+}
+
+using ast_matchers::internal::Matcher;
+
+TEST(ParserTest, FullParserTest) {
+ Diagnostics Error;
+ llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
+ "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"
+ " hasOperatorName(\"+\"))))",
+ &Error));
+ EXPECT_EQ("", Error.toStringFull());
+ Matcher<Decl> M = VarDecl->unconditionalConvertTo<Decl>();
+ EXPECT_TRUE(matches("int x = 1 + false;", M));
+ EXPECT_FALSE(matches("int x = true + 1;", M));
+ EXPECT_FALSE(matches("int x = 1 - false;", M));
+ EXPECT_FALSE(matches("int x = true - 1;", M));
+
+ llvm::Optional<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
+ "functionDecl(hasParameter(1, hasName(\"x\")))", &Error));
+ EXPECT_EQ("", Error.toStringFull());
+ M = HasParameter->unconditionalConvertTo<Decl>();
+
+ EXPECT_TRUE(matches("void f(int a, int x);", M));
+ EXPECT_FALSE(matches("void f(int x, int a);", M));
+
+ EXPECT_TRUE(!Parser::parseMatcherExpression(
+ "hasInitializer(\n binaryOperator(hasLHS(\"A\")))",
+ &Error).hasValue());
+ EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
+ "2:5: Error parsing argument 1 for matcher binaryOperator.\n"
+ "2:20: Error building matcher hasLHS.\n"
+ "2:27: Incorrect type for arg 1. "
+ "(Expected = Matcher<Expr>) != (Actual = String)",
+ Error.toStringFull());
+}
+
+std::string ParseWithError(StringRef Code) {
+ Diagnostics Error;
+ VariantValue Value;
+ Parser::parseExpression(Code, &Value, &Error);
+ return Error.toStringFull();
+}
+
+std::string ParseMatcherWithError(StringRef Code) {
+ Diagnostics Error;
+ Parser::parseMatcherExpression(Code, &Error);
+ return Error.toStringFull();
+}
+
+TEST(ParserTest, Errors) {
+ EXPECT_EQ(
+ "1:5: Error parsing matcher. Found token <123> while looking for '('.",
+ ParseWithError("Foo 123"));
+ EXPECT_EQ(
+ "1:9: Error parsing matcher. Found token <123> while looking for ','.",
+ ParseWithError("Foo(\"A\" 123)"));
+ EXPECT_EQ(
+ "1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
+ ParseWithError("Foo("));
+ EXPECT_EQ("1:1: End of code found while looking for token.",
+ ParseWithError(""));
+ EXPECT_EQ("Input value is not a matcher expression.",
+ ParseMatcherWithError("\"A\""));
+ EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n"
+ "1:5: Invalid token <(> found when looking for a value.",
+ ParseWithError("Foo(("));
+ EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a"));
+ EXPECT_EQ("1:11: Malformed bind() expression.",
+ ParseWithError("isArrow().biind"));
+ EXPECT_EQ("1:15: Malformed bind() expression.",
+ ParseWithError("isArrow().bind"));
+ EXPECT_EQ("1:16: Malformed bind() expression.",
+ ParseWithError("isArrow().bind(foo"));
+ EXPECT_EQ("1:21: Malformed bind() expression.",
+ ParseWithError("isArrow().bind(\"foo\""));
+ EXPECT_EQ("1:1: Error building matcher isArrow.\n"
+ "1:1: Matcher does not support binding.",
+ ParseWithError("isArrow().bind(\"foo\")"));
+ EXPECT_EQ("Input value has unresolved overloaded type: "
+ "Matcher<DoStmt|ForStmt|WhileStmt>",
+ ParseMatcherWithError("hasBody(stmt())"));
+}
+
+TEST(ParserTest, OverloadErrors) {
+ EXPECT_EQ("1:1: Error building matcher callee.\n"
+ "1:8: Candidate 1: Incorrect type for arg 1. "
+ "(Expected = Matcher<Stmt>) != (Actual = String)\n"
+ "1:8: Candidate 2: Incorrect type for arg 1. "
+ "(Expected = Matcher<Decl>) != (Actual = String)",
+ ParseWithError("callee(\"A\")"));
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
new file mode 100644
index 0000000..e716484
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -0,0 +1,347 @@
+//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "../ASTMatchersTest.h"
+#include "clang/ASTMatchers/Dynamic/Registry.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using ast_matchers::internal::Matcher;
+
+class RegistryTest : public ::testing::Test {
+public:
+ std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
+ std::vector<ParserValue> Args(const VariantValue &Arg1) {
+ std::vector<ParserValue> Out(1);
+ Out[0].Value = Arg1;
+ return Out;
+ }
+ std::vector<ParserValue> Args(const VariantValue &Arg1,
+ const VariantValue &Arg2) {
+ std::vector<ParserValue> Out(2);
+ Out[0].Value = Arg1;
+ Out[1].Value = Arg2;
+ return Out;
+ }
+
+ VariantMatcher constructMatcher(StringRef MatcherName,
+ Diagnostics *Error = NULL) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ const VariantMatcher Out =
+ Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Out;
+ }
+
+ VariantMatcher constructMatcher(StringRef MatcherName,
+ const VariantValue &Arg1,
+ Diagnostics *Error = NULL) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ const VariantMatcher Out = Registry::constructMatcher(
+ MatcherName, SourceRange(), Args(Arg1), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Out;
+ }
+
+ VariantMatcher constructMatcher(StringRef MatcherName,
+ const VariantValue &Arg1,
+ const VariantValue &Arg2,
+ Diagnostics *Error = NULL) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ const VariantMatcher Out = Registry::constructMatcher(
+ MatcherName, SourceRange(), Args(Arg1, Arg2), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Out;
+ }
+};
+
+TEST_F(RegistryTest, CanConstructNoArgs) {
+ Matcher<Stmt> IsArrowValue = constructMatcher(
+ "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
+ Matcher<Stmt> BoolValue =
+ constructMatcher("boolLiteral").getTypedMatcher<Stmt>();
+
+ const std::string ClassSnippet = "struct Foo { int x; };\n"
+ "Foo *foo = new Foo;\n"
+ "int i = foo->x;\n";
+ const std::string BoolSnippet = "bool Foo = true;\n";
+
+ EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
+ EXPECT_TRUE(matches(BoolSnippet, BoolValue));
+ EXPECT_FALSE(matches(ClassSnippet, BoolValue));
+ EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
+}
+
+TEST_F(RegistryTest, ConstructWithSimpleArgs) {
+ Matcher<Decl> Value = constructMatcher(
+ "namedDecl", constructMatcher("hasName", std::string("X")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("class X {};", Value));
+ EXPECT_FALSE(matches("int x;", Value));
+
+ Value = functionDecl(constructMatcher("parameterCountIs", 2)
+ .getTypedMatcher<FunctionDecl>());
+ EXPECT_TRUE(matches("void foo(int,int);", Value));
+ EXPECT_FALSE(matches("void foo(int);", Value));
+}
+
+TEST_F(RegistryTest, ConstructWithMatcherArgs) {
+ Matcher<Decl> HasInitializerSimple = constructMatcher(
+ "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
+ .getTypedMatcher<Decl>();
+ Matcher<Decl> HasInitializerComplex = constructMatcher(
+ "varDecl",
+ constructMatcher("hasInitializer", constructMatcher("callExpr")))
+ .getTypedMatcher<Decl>();
+
+ std::string code = "int i;";
+ EXPECT_FALSE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
+
+ code = "int i = 1;";
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
+
+ code = "int y(); int i = y();";
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_TRUE(matches(code, HasInitializerComplex));
+
+ Matcher<Decl> HasParameter =
+ functionDecl(constructMatcher(
+ "hasParameter", 1, constructMatcher("hasName", std::string("x")))
+ .getTypedMatcher<FunctionDecl>());
+ EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
+ EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
+}
+
+TEST_F(RegistryTest, OverloadedMatchers) {
+ Matcher<Stmt> CallExpr0 = constructMatcher(
+ "callExpr",
+ constructMatcher("callee", constructMatcher("memberExpr",
+ constructMatcher("isArrow"))))
+ .getTypedMatcher<Stmt>();
+
+ Matcher<Stmt> CallExpr1 = constructMatcher(
+ "callExpr",
+ constructMatcher(
+ "callee",
+ constructMatcher("methodDecl",
+ constructMatcher("hasName", std::string("x")))))
+ .getTypedMatcher<Stmt>();
+
+ std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
+ EXPECT_FALSE(matches(Code, CallExpr0));
+ EXPECT_TRUE(matches(Code, CallExpr1));
+
+ Code = "class Z { public: void z() { this->z(); } };";
+ EXPECT_TRUE(matches(Code, CallExpr0));
+ EXPECT_FALSE(matches(Code, CallExpr1));
+}
+
+TEST_F(RegistryTest, PolymorphicMatchers) {
+ const VariantMatcher IsDefinition = constructMatcher("isDefinition");
+ Matcher<Decl> Var =
+ constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
+ Matcher<Decl> Class =
+ constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
+ Matcher<Decl> Func =
+ constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("int a;", Var));
+ EXPECT_FALSE(matches("extern int a;", Var));
+ EXPECT_TRUE(matches("class A {};", Class));
+ EXPECT_FALSE(matches("class A;", Class));
+ EXPECT_TRUE(matches("void f(){};", Func));
+ EXPECT_FALSE(matches("void f();", Func));
+
+ Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
+ Matcher<Decl> RecordDecl = constructMatcher(
+ "recordDecl", constructMatcher("hasName", std::string("Foo")),
+ VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
+
+ EXPECT_TRUE(matches("int Foo;", Anything));
+ EXPECT_TRUE(matches("class Foo {};", Anything));
+ EXPECT_TRUE(matches("void Foo(){};", Anything));
+ EXPECT_FALSE(matches("int Foo;", RecordDecl));
+ EXPECT_TRUE(matches("class Foo {};", RecordDecl));
+ EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
+
+ Matcher<Stmt> ConstructExpr = constructMatcher(
+ "constructExpr",
+ constructMatcher(
+ "hasDeclaration",
+ constructMatcher(
+ "methodDecl",
+ constructMatcher(
+ "ofClass", constructMatcher("hasName", std::string("Foo"))))))
+ .getTypedMatcher<Stmt>();
+ EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
+ EXPECT_TRUE(
+ matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
+}
+
+TEST_F(RegistryTest, TemplateArgument) {
+ Matcher<Decl> HasTemplateArgument = constructMatcher(
+ "classTemplateSpecializationDecl",
+ constructMatcher(
+ "hasAnyTemplateArgument",
+ constructMatcher("refersToType",
+ constructMatcher("asString", std::string("int")))))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
+ HasTemplateArgument));
+ EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
+ HasTemplateArgument));
+}
+
+TEST_F(RegistryTest, TypeTraversal) {
+ Matcher<Type> M = constructMatcher(
+ "pointerType",
+ constructMatcher("pointee", constructMatcher("isConstQualified"),
+ constructMatcher("isInteger"))).getTypedMatcher<Type>();
+ EXPECT_FALSE(matches("int *a;", M));
+ EXPECT_TRUE(matches("int const *b;", M));
+
+ M = constructMatcher(
+ "arrayType",
+ constructMatcher("hasElementType", constructMatcher("builtinType")))
+ .getTypedMatcher<Type>();
+ EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
+ EXPECT_TRUE(matches("int b[7];", M));
+}
+
+TEST_F(RegistryTest, CXXCtorInitializer) {
+ Matcher<Decl> CtorDecl = constructMatcher(
+ "constructorDecl",
+ constructMatcher(
+ "hasAnyConstructorInitializer",
+ constructMatcher("forField",
+ constructMatcher("hasName", std::string("foo")))))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
+ EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
+ EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
+}
+
+TEST_F(RegistryTest, Adaptative) {
+ Matcher<Decl> D = constructMatcher(
+ "recordDecl",
+ constructMatcher(
+ "has",
+ constructMatcher("recordDecl",
+ constructMatcher("hasName", std::string("X")))))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("class X {};", D));
+ EXPECT_TRUE(matches("class Y { class X {}; };", D));
+ EXPECT_FALSE(matches("class Y { class Z {}; };", D));
+
+ Matcher<Stmt> S = constructMatcher(
+ "forStmt",
+ constructMatcher(
+ "hasDescendant",
+ constructMatcher("varDecl",
+ constructMatcher("hasName", std::string("X")))))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
+ EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
+ EXPECT_FALSE(matches("void foo() { for(;;); }", S));
+ EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
+
+ S = constructMatcher(
+ "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
+ EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
+}
+
+TEST_F(RegistryTest, VariadicOp) {
+ Matcher<Decl> D = constructMatcher(
+ "anyOf",
+ constructMatcher("recordDecl",
+ constructMatcher("hasName", std::string("Foo"))),
+ constructMatcher("namedDecl",
+ constructMatcher("hasName", std::string("foo"))))
+ .getTypedMatcher<Decl>();
+
+ EXPECT_TRUE(matches("void foo(){}", D));
+ EXPECT_TRUE(matches("struct Foo{};", D));
+ EXPECT_FALSE(matches("int i = 0;", D));
+
+ D = constructMatcher(
+ "allOf", constructMatcher("recordDecl"),
+ constructMatcher(
+ "namedDecl",
+ constructMatcher("anyOf",
+ constructMatcher("hasName", std::string("Foo")),
+ constructMatcher("hasName", std::string("Bar")))))
+ .getTypedMatcher<Decl>();
+
+ EXPECT_FALSE(matches("void foo(){}", D));
+ EXPECT_TRUE(matches("struct Foo{};", D));
+ EXPECT_FALSE(matches("int i = 0;", D));
+ EXPECT_TRUE(matches("class Bar{};", D));
+ EXPECT_FALSE(matches("class OtherBar{};", D));
+}
+
+TEST_F(RegistryTest, Errors) {
+ // Incorrect argument count.
+ OwningPtr<Diagnostics> Error(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
+ EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
+ EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
+ Error->toString());
+
+ // Bad argument type
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = String)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"),
+ constructMatcher("parameterCountIs", 3),
+ Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = Matcher<FunctionDecl>)",
+ Error->toString());
+
+ // Bad argument type with variadic.
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull());
+ EXPECT_EQ(
+ "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher(
+ "recordDecl",
+ constructMatcher("allOf",
+ constructMatcher("isDerivedFrom", std::string("FOO")),
+ constructMatcher("isArrow")),
+ Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 1. "
+ "(Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
+ Error->toString());
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
new file mode 100644
index 0000000..d2b8a58
--- /dev/null
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -0,0 +1,144 @@
+//===- unittest/ASTMatchers/Dynamic/VariantValueTest.cpp - VariantValue 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/ASTMatchers/Dynamic/VariantValue.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace dynamic {
+namespace {
+
+using ast_matchers::internal::DynTypedMatcher;
+using ast_matchers::internal::Matcher;
+
+TEST(VariantValueTest, Unsigned) {
+ const unsigned kUnsigned = 17;
+ VariantValue Value = kUnsigned;
+
+ EXPECT_TRUE(Value.isUnsigned());
+ EXPECT_EQ(kUnsigned, Value.getUnsigned());
+
+ EXPECT_FALSE(Value.isString());
+ EXPECT_FALSE(Value.isMatcher());
+}
+
+TEST(VariantValueTest, String) {
+ const ::std::string kString = "string";
+ VariantValue Value = kString;
+
+ EXPECT_TRUE(Value.isString());
+ EXPECT_EQ(kString, Value.getString());
+ EXPECT_EQ("String", Value.getTypeAsString());
+
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+}
+
+TEST(VariantValueTest, DynTypedMatcher) {
+ VariantValue Value = VariantMatcher::SingleMatcher(stmt());
+
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isString());
+
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
+ EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
+
+ // Can only convert to compatible matchers.
+ Value = VariantMatcher::SingleMatcher(recordDecl());
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
+
+ Value = VariantMatcher::SingleMatcher(ignoringImpCasts(expr()));
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<Stmt>());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<Expr>());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<IntegerLiteral>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<GotoStmt>());
+ EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
+}
+
+TEST(VariantValueTest, Assignment) {
+ VariantValue Value = std::string("A");
+ EXPECT_TRUE(Value.isString());
+ EXPECT_EQ("A", Value.getString());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("String", Value.getTypeAsString());
+
+ Value = VariantMatcher::SingleMatcher(recordDecl());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isString());
+ EXPECT_TRUE(Value.isMatcher());
+ EXPECT_TRUE(Value.getMatcher().hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
+
+ Value = 17;
+ EXPECT_TRUE(Value.isUnsigned());
+ EXPECT_EQ(17U, Value.getUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isString());
+
+ Value = VariantValue();
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isString());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("Nothing", Value.getTypeAsString());
+}
+
+TEST(VariantValueTest, Matcher) {
+ EXPECT_TRUE(matches("class X {};", VariantValue(VariantMatcher::SingleMatcher(
+ recordDecl(hasName("X"))))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ EXPECT_TRUE(
+ matches("int x;", VariantValue(VariantMatcher::SingleMatcher(varDecl()))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ EXPECT_TRUE(
+ matches("int foo() { return 1 + 1; }",
+ VariantValue(VariantMatcher::SingleMatcher(functionDecl()))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ // Can't get the wrong matcher.
+ EXPECT_FALSE(VariantValue(VariantMatcher::SingleMatcher(varDecl()))
+ .getMatcher()
+ .hasTypedMatcher<Stmt>());
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(_MSC_VER)
+ // Trying to get the wrong matcher fails an assertion in Matcher<T>. We don't
+ // do this test when building with MSVC because its debug C runtime prints the
+ // assertion failure message as a wide string, which gtest doesn't understand.
+ EXPECT_DEATH(VariantValue(VariantMatcher::SingleMatcher(varDecl()))
+ .getMatcher()
+ .getTypedMatcher<Stmt>(),
+ "hasTypedMatcher");
+#endif
+
+ EXPECT_FALSE(matches(
+ "int x;", VariantValue(VariantMatcher::SingleMatcher(functionDecl()))
+ .getMatcher()
+ .getTypedMatcher<Decl>()));
+ EXPECT_FALSE(
+ matches("int foo() { return 1 + 1; }",
+ VariantValue(VariantMatcher::SingleMatcher(declRefExpr()))
+ .getMatcher()
+ .getTypedMatcher<Stmt>()));
+}
+
+} // end anonymous namespace
+} // end namespace dynamic
+} // end namespace ast_matchers
+} // end namespace clang
OpenPOWER on IntegriCloud