RegistryTest.cpp revision b80aad8d30340cdd47ecb6a5bafe46cf5e47cfe9
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 16namespace clang { 17namespace ast_matchers { 18namespace dynamic { 19namespace { 20 21using ast_matchers::internal::Matcher; 22 23class RegistryTest : public ::testing::Test { 24public: 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 73TEST_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 90TEST_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 103TEST_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 132TEST_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 156TEST_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 184TEST_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 198TEST_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 214TEST_F(RegistryTest, CXXCtorInitializer) { 215 Matcher<Decl> CtorDecl = constructMatcher( 216 "constructorDecl", 217 constructMatcher( 218 "hasAnyConstructorInitializer", 219 constructMatcher("forField", 220 constructMatcher("hasName", std::string("foo"))))) 221 .getTypedMatcher<Decl>(); 222 EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); 223 EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); 224 EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl)); 225} 226 227TEST_F(RegistryTest, Adaptative) { 228 Matcher<Decl> D = constructMatcher( 229 "recordDecl", 230 constructMatcher( 231 "has", 232 constructMatcher("recordDecl", 233 constructMatcher("hasName", std::string("X"))))) 234 .getTypedMatcher<Decl>(); 235 EXPECT_TRUE(matches("class X {};", D)); 236 EXPECT_TRUE(matches("class Y { class X {}; };", D)); 237 EXPECT_FALSE(matches("class Y { class Z {}; };", D)); 238 239 Matcher<Stmt> S = constructMatcher( 240 "forStmt", 241 constructMatcher( 242 "hasDescendant", 243 constructMatcher("varDecl", 244 constructMatcher("hasName", std::string("X"))))) 245 .getTypedMatcher<Stmt>(); 246 EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); 247 EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); 248 EXPECT_FALSE(matches("void foo() { for(;;); }", S)); 249 EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S)); 250 251 S = constructMatcher( 252 "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt"))) 253 .getTypedMatcher<Stmt>(); 254 EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S)); 255 EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); 256} 257 258TEST_F(RegistryTest, VariadicOp) { 259 Matcher<Decl> D = constructMatcher( 260 "anyOf", 261 constructMatcher("recordDecl", 262 constructMatcher("hasName", std::string("Foo"))), 263 constructMatcher("namedDecl", 264 constructMatcher("hasName", std::string("foo")))) 265 .getTypedMatcher<Decl>(); 266 267 EXPECT_TRUE(matches("void foo(){}", D)); 268 EXPECT_TRUE(matches("struct Foo{};", D)); 269 EXPECT_FALSE(matches("int i = 0;", D)); 270 271 D = constructMatcher( 272 "allOf", constructMatcher("recordDecl"), 273 constructMatcher( 274 "namedDecl", 275 constructMatcher("anyOf", 276 constructMatcher("hasName", std::string("Foo")), 277 constructMatcher("hasName", std::string("Bar"))))) 278 .getTypedMatcher<Decl>(); 279 280 EXPECT_FALSE(matches("void foo(){}", D)); 281 EXPECT_TRUE(matches("struct Foo{};", D)); 282 EXPECT_FALSE(matches("int i = 0;", D)); 283 EXPECT_TRUE(matches("class Bar{};", D)); 284 EXPECT_FALSE(matches("class OtherBar{};", D)); 285} 286 287TEST_F(RegistryTest, Errors) { 288 // Incorrect argument count. 289 OwningPtr<Diagnostics> Error(new Diagnostics()); 290 EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull()); 291 EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", 292 Error->toString()); 293 Error.reset(new Diagnostics()); 294 EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull()); 295 EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", 296 Error->toString()); 297 298 // Bad argument type 299 Error.reset(new Diagnostics()); 300 EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull()); 301 EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != " 302 "(Actual = String)", 303 Error->toString()); 304 Error.reset(new Diagnostics()); 305 EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"), 306 constructMatcher("parameterCountIs", 3), 307 Error.get()).isNull()); 308 EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != " 309 "(Actual = Matcher<FunctionDecl>)", 310 Error->toString()); 311 312 // Bad argument type with variadic. 313 Error.reset(new Diagnostics()); 314 EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull()); 315 EXPECT_EQ( 316 "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", 317 Error->toString()); 318 Error.reset(new Diagnostics()); 319 EXPECT_TRUE(constructMatcher( 320 "recordDecl", 321 constructMatcher("allOf", 322 constructMatcher("isDerivedFrom", std::string("FOO")), 323 constructMatcher("isArrow")), 324 Error.get()).isNull()); 325 EXPECT_EQ("Incorrect type for arg 1. " 326 "(Expected = Matcher<CXXRecordDecl>) != " 327 "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)", 328 Error->toString()); 329} 330 331} // end anonymous namespace 332} // end namespace dynamic 333} // end namespace ast_matchers 334} // end namespace clang 335