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