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