diff options
author | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
commit | 952eddef9aff85b1e92626e89baaf7a360e2ac85 (patch) | |
tree | df8df0b0067b381eab470a3b8f28d14a552a6340 /unittests/ASTMatchers/Dynamic/RegistryTest.cpp | |
parent | ea266cad53e3d49771fa38103913d3ec7a166694 (diff) | |
download | FreeBSD-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/RegistryTest.cpp')
-rw-r--r-- | unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
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 |