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