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 VariantMatcher constructMatcher(StringRef MatcherName, 40 Diagnostics *Error = NULL) { 41 Diagnostics DummyError; 42 if (!Error) Error = &DummyError; 43 const VariantMatcher Out = 44 Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error); 45 EXPECT_EQ("", DummyError.toStringFull()); 46 return Out; 47 } 48 49 VariantMatcher constructMatcher(StringRef MatcherName, 50 const VariantValue &Arg1, 51 Diagnostics *Error = NULL) { 52 Diagnostics DummyError; 53 if (!Error) Error = &DummyError; 54 const VariantMatcher Out = Registry::constructMatcher( 55 MatcherName, SourceRange(), Args(Arg1), Error); 56 EXPECT_EQ("", DummyError.toStringFull()); 57 return Out; 58 } 59 60 VariantMatcher constructMatcher(StringRef MatcherName, 61 const VariantValue &Arg1, 62 const VariantValue &Arg2, 63 Diagnostics *Error = NULL) { 64 Diagnostics DummyError; 65 if (!Error) Error = &DummyError; 66 const VariantMatcher Out = Registry::constructMatcher( 67 MatcherName, SourceRange(), Args(Arg1, Arg2), Error); 68 EXPECT_EQ("", DummyError.toStringFull()); 69 return Out; 70 } 71 }; 72 73 TEST_F(RegistryTest, CanConstructNoArgs) { 74 Matcher<Stmt> IsArrowValue = constructMatcher( 75 "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>(); 76 Matcher<Stmt> BoolValue = 77 constructMatcher("boolLiteral").getTypedMatcher<Stmt>(); 78 79 const std::string ClassSnippet = "struct Foo { int x; };\n" 80 "Foo *foo = new Foo;\n" 81 "int i = foo->x;\n"; 82 const std::string BoolSnippet = "bool Foo = true;\n"; 83 84 EXPECT_TRUE(matches(ClassSnippet, IsArrowValue)); 85 EXPECT_TRUE(matches(BoolSnippet, BoolValue)); 86 EXPECT_FALSE(matches(ClassSnippet, BoolValue)); 87 EXPECT_FALSE(matches(BoolSnippet, IsArrowValue)); 88 } 89 90 TEST_F(RegistryTest, ConstructWithSimpleArgs) { 91 Matcher<Decl> Value = constructMatcher( 92 "namedDecl", constructMatcher("hasName", std::string("X"))) 93 .getTypedMatcher<Decl>(); 94 EXPECT_TRUE(matches("class X {};", Value)); 95 EXPECT_FALSE(matches("int x;", Value)); 96 97 Value = functionDecl(constructMatcher("parameterCountIs", 2) 98 .getTypedMatcher<FunctionDecl>()); 99 EXPECT_TRUE(matches("void foo(int,int);", Value)); 100 EXPECT_FALSE(matches("void foo(int);", Value)); 101 } 102 103 TEST_F(RegistryTest, ConstructWithMatcherArgs) { 104 Matcher<Decl> HasInitializerSimple = constructMatcher( 105 "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt"))) 106 .getTypedMatcher<Decl>(); 107 Matcher<Decl> HasInitializerComplex = constructMatcher( 108 "varDecl", 109 constructMatcher("hasInitializer", constructMatcher("callExpr"))) 110 .getTypedMatcher<Decl>(); 111 112 std::string code = "int i;"; 113 EXPECT_FALSE(matches(code, HasInitializerSimple)); 114 EXPECT_FALSE(matches(code, HasInitializerComplex)); 115 116 code = "int i = 1;"; 117 EXPECT_TRUE(matches(code, HasInitializerSimple)); 118 EXPECT_FALSE(matches(code, HasInitializerComplex)); 119 120 code = "int y(); int i = y();"; 121 EXPECT_TRUE(matches(code, HasInitializerSimple)); 122 EXPECT_TRUE(matches(code, HasInitializerComplex)); 123 124 Matcher<Decl> HasParameter = 125 functionDecl(constructMatcher( 126 "hasParameter", 1, constructMatcher("hasName", std::string("x"))) 127 .getTypedMatcher<FunctionDecl>()); 128 EXPECT_TRUE(matches("void f(int a, int x);", HasParameter)); 129 EXPECT_FALSE(matches("void f(int x, int a);", HasParameter)); 130 } 131 132 TEST_F(RegistryTest, OverloadedMatchers) { 133 Matcher<Stmt> CallExpr0 = constructMatcher( 134 "callExpr", 135 constructMatcher("callee", constructMatcher("memberExpr", 136 constructMatcher("isArrow")))) 137 .getTypedMatcher<Stmt>(); 138 139 Matcher<Stmt> CallExpr1 = constructMatcher( 140 "callExpr", 141 constructMatcher( 142 "callee", 143 constructMatcher("methodDecl", 144 constructMatcher("hasName", std::string("x"))))) 145 .getTypedMatcher<Stmt>(); 146 147 std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }"; 148 EXPECT_FALSE(matches(Code, CallExpr0)); 149 EXPECT_TRUE(matches(Code, CallExpr1)); 150 151 Code = "class Z { public: void z() { this->z(); } };"; 152 EXPECT_TRUE(matches(Code, CallExpr0)); 153 EXPECT_FALSE(matches(Code, CallExpr1)); 154 } 155 156 TEST_F(RegistryTest, PolymorphicMatchers) { 157 const VariantMatcher IsDefinition = constructMatcher("isDefinition"); 158 Matcher<Decl> Var = 159 constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>(); 160 Matcher<Decl> Class = 161 constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>(); 162 Matcher<Decl> Func = 163 constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>(); 164 EXPECT_TRUE(matches("int a;", Var)); 165 EXPECT_FALSE(matches("extern int a;", Var)); 166 EXPECT_TRUE(matches("class A {};", Class)); 167 EXPECT_FALSE(matches("class A;", Class)); 168 EXPECT_TRUE(matches("void f(){};", Func)); 169 EXPECT_FALSE(matches("void f();", Func)); 170 171 Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>(); 172 Matcher<Decl> RecordDecl = constructMatcher( 173 "recordDecl", constructMatcher("hasName", std::string("Foo")), 174 VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>(); 175 176 EXPECT_TRUE(matches("int Foo;", Anything)); 177 EXPECT_TRUE(matches("class Foo {};", Anything)); 178 EXPECT_TRUE(matches("void Foo(){};", Anything)); 179 EXPECT_FALSE(matches("int Foo;", RecordDecl)); 180 EXPECT_TRUE(matches("class Foo {};", RecordDecl)); 181 EXPECT_FALSE(matches("void Foo(){};", RecordDecl)); 182 183 Matcher<Stmt> ConstructExpr = constructMatcher( 184 "constructExpr", 185 constructMatcher( 186 "hasDeclaration", 187 constructMatcher( 188 "methodDecl", 189 constructMatcher( 190 "ofClass", constructMatcher("hasName", std::string("Foo")))))) 191 .getTypedMatcher<Stmt>(); 192 EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr)); 193 EXPECT_TRUE( 194 matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr)); 195 } 196 197 TEST_F(RegistryTest, TemplateArgument) { 198 Matcher<Decl> HasTemplateArgument = constructMatcher( 199 "classTemplateSpecializationDecl", 200 constructMatcher( 201 "hasAnyTemplateArgument", 202 constructMatcher("refersToType", 203 constructMatcher("asString", std::string("int"))))) 204 .getTypedMatcher<Decl>(); 205 EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;", 206 HasTemplateArgument)); 207 EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;", 208 HasTemplateArgument)); 209 } 210 211 TEST_F(RegistryTest, TypeTraversal) { 212 Matcher<Type> M = constructMatcher( 213 "pointerType", 214 constructMatcher("pointee", constructMatcher("isConstQualified"), 215 constructMatcher("isInteger"))).getTypedMatcher<Type>(); 216 EXPECT_FALSE(matches("int *a;", M)); 217 EXPECT_TRUE(matches("int const *b;", M)); 218 219 M = constructMatcher( 220 "arrayType", 221 constructMatcher("hasElementType", constructMatcher("builtinType"))) 222 .getTypedMatcher<Type>(); 223 EXPECT_FALSE(matches("struct A{}; A a[7];;", M)); 224 EXPECT_TRUE(matches("int b[7];", M)); 225 } 226 227 TEST_F(RegistryTest, CXXCtorInitializer) { 228 Matcher<Decl> CtorDecl = constructMatcher( 229 "constructorDecl", 230 constructMatcher( 231 "hasAnyConstructorInitializer", 232 constructMatcher("forField", 233 constructMatcher("hasName", std::string("foo"))))) 234 .getTypedMatcher<Decl>(); 235 EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); 236 EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); 237 EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl)); 238 } 239 240 TEST_F(RegistryTest, Adaptative) { 241 Matcher<Decl> D = constructMatcher( 242 "recordDecl", 243 constructMatcher( 244 "has", 245 constructMatcher("recordDecl", 246 constructMatcher("hasName", std::string("X"))))) 247 .getTypedMatcher<Decl>(); 248 EXPECT_TRUE(matches("class X {};", D)); 249 EXPECT_TRUE(matches("class Y { class X {}; };", D)); 250 EXPECT_FALSE(matches("class Y { class Z {}; };", D)); 251 252 Matcher<Stmt> S = constructMatcher( 253 "forStmt", 254 constructMatcher( 255 "hasDescendant", 256 constructMatcher("varDecl", 257 constructMatcher("hasName", std::string("X"))))) 258 .getTypedMatcher<Stmt>(); 259 EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); 260 EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); 261 EXPECT_FALSE(matches("void foo() { for(;;); }", S)); 262 EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S)); 263 264 S = constructMatcher( 265 "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt"))) 266 .getTypedMatcher<Stmt>(); 267 EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S)); 268 EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); 269 } 270 271 TEST_F(RegistryTest, VariadicOp) { 272 Matcher<Decl> D = constructMatcher( 273 "anyOf", 274 constructMatcher("recordDecl", 275 constructMatcher("hasName", std::string("Foo"))), 276 constructMatcher("namedDecl", 277 constructMatcher("hasName", std::string("foo")))) 278 .getTypedMatcher<Decl>(); 279 280 EXPECT_TRUE(matches("void foo(){}", D)); 281 EXPECT_TRUE(matches("struct Foo{};", D)); 282 EXPECT_FALSE(matches("int i = 0;", D)); 283 284 D = constructMatcher( 285 "allOf", constructMatcher("recordDecl"), 286 constructMatcher( 287 "namedDecl", 288 constructMatcher("anyOf", 289 constructMatcher("hasName", std::string("Foo")), 290 constructMatcher("hasName", std::string("Bar"))))) 291 .getTypedMatcher<Decl>(); 292 293 EXPECT_FALSE(matches("void foo(){}", D)); 294 EXPECT_TRUE(matches("struct Foo{};", D)); 295 EXPECT_FALSE(matches("int i = 0;", D)); 296 EXPECT_TRUE(matches("class Bar{};", D)); 297 EXPECT_FALSE(matches("class OtherBar{};", D)); 298 299 D = recordDecl( 300 has(fieldDecl(hasName("Foo"))), 301 constructMatcher( 302 "unless", 303 constructMatcher("namedDecl", 304 constructMatcher("hasName", std::string("Bar")))) 305 .getTypedMatcher<Decl>()); 306 307 EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); 308 EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); 309 } 310 311 TEST_F(RegistryTest, Errors) { 312 // Incorrect argument count. 313 OwningPtr<Diagnostics> Error(new Diagnostics()); 314 EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull()); 315 EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", 316 Error->toString()); 317 Error.reset(new Diagnostics()); 318 EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull()); 319 EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", 320 Error->toString()); 321 Error.reset(new Diagnostics()); 322 EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull()); 323 EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)", 324 Error->toString()); 325 Error.reset(new Diagnostics()); 326 EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(), 327 Error.get()).isNull()); 328 EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)", 329 Error->toString()); 330 331 // Bad argument type 332 Error.reset(new Diagnostics()); 333 EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull()); 334 EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != " 335 "(Actual = String)", 336 Error->toString()); 337 Error.reset(new Diagnostics()); 338 EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"), 339 constructMatcher("parameterCountIs", 3), 340 Error.get()).isNull()); 341 EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != " 342 "(Actual = Matcher<FunctionDecl>)", 343 Error->toString()); 344 345 // Bad argument type with variadic. 346 Error.reset(new Diagnostics()); 347 EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(), 348 Error.get()).isNull()); 349 EXPECT_EQ( 350 "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", 351 Error->toString()); 352 Error.reset(new Diagnostics()); 353 EXPECT_TRUE(constructMatcher( 354 "recordDecl", 355 constructMatcher("allOf", 356 constructMatcher("isDerivedFrom", std::string("FOO")), 357 constructMatcher("isArrow")), 358 Error.get()).isNull()); 359 EXPECT_EQ("Incorrect type for arg 1. " 360 "(Expected = Matcher<CXXRecordDecl>) != " 361 "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)", 362 Error->toString()); 363 } 364 365 } // end anonymous namespace 366 } // end namespace dynamic 367 } // end namespace ast_matchers 368 } // end namespace clang 369