Home | History | Annotate | Download | only in Dynamic
      1 //===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===-----------------------------------------------------------------------===//
      9 
     10 #include <vector>
     11 
     12 #include "../ASTMatchersTest.h"
     13 #include "clang/ASTMatchers/Dynamic/Registry.h"
     14 #include "gtest/gtest.h"
     15 
     16 namespace clang {
     17 namespace ast_matchers {
     18 namespace dynamic {
     19 namespace {
     20 
     21 using ast_matchers::internal::Matcher;
     22 
     23 class RegistryTest : public ::testing::Test {
     24 public:
     25   std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
     26   std::vector<ParserValue> Args(const VariantValue &Arg1) {
     27     std::vector<ParserValue> Out(1);
     28     Out[0].Value = Arg1;
     29     return Out;
     30   }
     31   std::vector<ParserValue> Args(const VariantValue &Arg1,
     32                                 const VariantValue &Arg2) {
     33     std::vector<ParserValue> Out(2);
     34     Out[0].Value = Arg1;
     35     Out[1].Value = Arg2;
     36     return Out;
     37   }
     38 
     39   MatcherList constructMatcher(StringRef MatcherName,
     40                                Diagnostics *Error = NULL) {
     41     Diagnostics DummyError;
     42     if (!Error) Error = &DummyError;
     43     const MatcherList Out =
     44         Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error);
     45     EXPECT_EQ("", DummyError.toStringFull());
     46     return Out;
     47   }
     48 
     49   MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
     50                                Diagnostics *Error = NULL) {
     51     Diagnostics DummyError;
     52     if (!Error) Error = &DummyError;
     53     const MatcherList Out = Registry::constructMatcher(
     54         MatcherName, SourceRange(), Args(Arg1), Error);
     55     EXPECT_EQ("", DummyError.toStringFull());
     56     return Out;
     57   }
     58 
     59   MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
     60                                const VariantValue &Arg2,
     61                                Diagnostics *Error = NULL) {
     62     Diagnostics DummyError;
     63     if (!Error) Error = &DummyError;
     64     const MatcherList Out = Registry::constructMatcher(
     65         MatcherName, SourceRange(), Args(Arg1, Arg2), Error);
     66     EXPECT_EQ("", DummyError.toStringFull());
     67     return Out;
     68   }
     69 };
     70 
     71 TEST_F(RegistryTest, CanConstructNoArgs) {
     72   Matcher<Stmt> IsArrowValue = constructMatcher(
     73       "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
     74   Matcher<Stmt> BoolValue =
     75       constructMatcher("boolLiteral").getTypedMatcher<Stmt>();
     76 
     77   const std::string ClassSnippet = "struct Foo { int x; };\n"
     78                                    "Foo *foo = new Foo;\n"
     79                                    "int i = foo->x;\n";
     80   const std::string BoolSnippet = "bool Foo = true;\n";
     81 
     82   EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
     83   EXPECT_TRUE(matches(BoolSnippet, BoolValue));
     84   EXPECT_FALSE(matches(ClassSnippet, BoolValue));
     85   EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
     86 }
     87 
     88 TEST_F(RegistryTest, ConstructWithSimpleArgs) {
     89   Matcher<Decl> Value = constructMatcher(
     90       "namedDecl", constructMatcher("hasName", std::string("X")))
     91       .getTypedMatcher<Decl>();
     92   EXPECT_TRUE(matches("class X {};", Value));
     93   EXPECT_FALSE(matches("int x;", Value));
     94 
     95   Value = functionDecl(constructMatcher("parameterCountIs", 2)
     96                            .getTypedMatcher<FunctionDecl>());
     97   EXPECT_TRUE(matches("void foo(int,int);", Value));
     98   EXPECT_FALSE(matches("void foo(int);", Value));
     99 }
    100 
    101 TEST_F(RegistryTest, ConstructWithMatcherArgs) {
    102   Matcher<Decl> HasInitializerSimple =
    103       constructMatcher("varDecl", constructMatcher("hasInitializer", stmt()))
    104           .getTypedMatcher<Decl>();
    105   Matcher<Decl> HasInitializerComplex = constructMatcher(
    106       "varDecl", constructMatcher("hasInitializer", callExpr()))
    107       .getTypedMatcher<Decl>();
    108 
    109   std::string code = "int i;";
    110   EXPECT_FALSE(matches(code, HasInitializerSimple));
    111   EXPECT_FALSE(matches(code, HasInitializerComplex));
    112 
    113   code = "int i = 1;";
    114   EXPECT_TRUE(matches(code, HasInitializerSimple));
    115   EXPECT_FALSE(matches(code, HasInitializerComplex));
    116 
    117   code = "int y(); int i = y();";
    118   EXPECT_TRUE(matches(code, HasInitializerSimple));
    119   EXPECT_TRUE(matches(code, HasInitializerComplex));
    120 
    121   Matcher<Decl> HasParameter = functionDecl(constructMatcher(
    122       "hasParameter", 1, hasName("x")).getTypedMatcher<FunctionDecl>());
    123   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
    124   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
    125 }
    126 
    127 TEST_F(RegistryTest, OverloadedMatchers) {
    128   Matcher<Stmt> CallExpr0 = constructMatcher(
    129       "callExpr",
    130       constructMatcher("callee", constructMatcher("memberExpr",
    131                                                   constructMatcher("isArrow"))))
    132       .getTypedMatcher<Stmt>();
    133 
    134   Matcher<Stmt> CallExpr1 = constructMatcher(
    135       "callExpr",
    136       constructMatcher(
    137           "callee",
    138           constructMatcher("methodDecl",
    139                            constructMatcher("hasName", std::string("x")))))
    140       .getTypedMatcher<Stmt>();
    141 
    142   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
    143   EXPECT_FALSE(matches(Code, CallExpr0));
    144   EXPECT_TRUE(matches(Code, CallExpr1));
    145 
    146   Code = "class Z { public: void z() { this->z(); } };";
    147   EXPECT_TRUE(matches(Code, CallExpr0));
    148   EXPECT_FALSE(matches(Code, CallExpr1));
    149 }
    150 
    151 TEST_F(RegistryTest, PolymorphicMatchers) {
    152   const MatcherList IsDefinition = constructMatcher("isDefinition");
    153   Matcher<Decl> Var =
    154       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
    155   Matcher<Decl> Class =
    156       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
    157   Matcher<Decl> Func =
    158       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
    159   EXPECT_TRUE(matches("int a;", Var));
    160   EXPECT_FALSE(matches("extern int a;", Var));
    161   EXPECT_TRUE(matches("class A {};", Class));
    162   EXPECT_FALSE(matches("class A;", Class));
    163   EXPECT_TRUE(matches("void f(){};", Func));
    164   EXPECT_FALSE(matches("void f();", Func));
    165 
    166   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
    167   Matcher<Decl> RecordDecl =
    168       constructMatcher("recordDecl", Anything).getTypedMatcher<Decl>();
    169 
    170   EXPECT_TRUE(matches("int a;", Anything));
    171   EXPECT_TRUE(matches("class A {};", Anything));
    172   EXPECT_TRUE(matches("void f(){};", Anything));
    173   // FIXME: A couple of tests have been suppressed.
    174   // I know it'd be bad with _MSC_VER here, though.
    175 #if !defined(_MSC_VER)
    176   EXPECT_FALSE(matches("int a;", RecordDecl));
    177 #endif
    178   EXPECT_TRUE(matches("class A {};", RecordDecl));
    179 #if !defined(_MSC_VER)
    180   EXPECT_FALSE(matches("void f(){};", RecordDecl));
    181 #endif
    182 }
    183 
    184 TEST_F(RegistryTest, TemplateArgument) {
    185   Matcher<Decl> HasTemplateArgument = constructMatcher(
    186       "classTemplateSpecializationDecl",
    187       constructMatcher(
    188           "hasAnyTemplateArgument",
    189           constructMatcher("refersToType",
    190                            constructMatcher("asString", std::string("int")))))
    191       .getTypedMatcher<Decl>();
    192   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
    193                       HasTemplateArgument));
    194   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
    195                        HasTemplateArgument));
    196 }
    197 
    198 TEST_F(RegistryTest, TypeTraversal) {
    199   Matcher<Type> M = constructMatcher(
    200       "pointerType",
    201       constructMatcher("pointee", constructMatcher("isConstQualified"),
    202                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
    203   EXPECT_FALSE(matches("int *a;", M));
    204   EXPECT_TRUE(matches("int const *b;", M));
    205 
    206   M = constructMatcher(
    207       "arrayType",
    208       constructMatcher("hasElementType", constructMatcher("builtinType")))
    209       .getTypedMatcher<Type>();
    210   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
    211   EXPECT_TRUE(matches("int b[7];", M));
    212 }
    213 
    214 TEST_F(RegistryTest, CXXCtorInitializer) {
    215   Matcher<Decl> CtorDecl = constructMatcher(
    216       "constructorDecl",
    217       constructMatcher("hasAnyConstructorInitializer",
    218                        constructMatcher("forField", hasName("foo"))))
    219       .getTypedMatcher<Decl>();
    220   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
    221   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
    222   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
    223 }
    224 
    225 TEST_F(RegistryTest, Adaptative) {
    226   Matcher<Decl> D = constructMatcher(
    227       "recordDecl",
    228       constructMatcher(
    229           "has",
    230           constructMatcher("recordDecl",
    231                            constructMatcher("hasName", std::string("X")))))
    232       .getTypedMatcher<Decl>();
    233   EXPECT_TRUE(matches("class X {};", D));
    234   EXPECT_TRUE(matches("class Y { class X {}; };", D));
    235   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
    236 
    237   Matcher<Stmt> S = constructMatcher(
    238       "forStmt",
    239       constructMatcher(
    240           "hasDescendant",
    241           constructMatcher("varDecl",
    242                            constructMatcher("hasName", std::string("X")))))
    243       .getTypedMatcher<Stmt>();
    244   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
    245   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
    246   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
    247   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
    248 
    249   S = constructMatcher(
    250       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
    251       .getTypedMatcher<Stmt>();
    252   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
    253   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
    254 }
    255 
    256 TEST_F(RegistryTest, Errors) {
    257   // Incorrect argument count.
    258   OwningPtr<Diagnostics> Error(new Diagnostics());
    259   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).empty());
    260   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
    261             Error->toString());
    262   Error.reset(new Diagnostics());
    263   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).empty());
    264   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
    265             Error->toString());
    266 
    267   // Bad argument type
    268   Error.reset(new Diagnostics());
    269   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).empty());
    270   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
    271             "(Actual = String)",
    272             Error->toString());
    273   Error.reset(new Diagnostics());
    274   EXPECT_TRUE(constructMatcher("recordDecl", recordDecl(), parameterCountIs(3),
    275                                Error.get()).empty());
    276   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
    277             "(Actual = Matcher<FunctionDecl>)",
    278             Error->toString());
    279 }
    280 
    281 } // end anonymous namespace
    282 } // end namespace dynamic
    283 } // end namespace ast_matchers
    284 } // end namespace clang
    285