644 lines · cpp
1//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser unit tests -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===-------------------------------------------------------------------===//8 9#include "../ASTMatchersTest.h"10#include "clang/ASTMatchers/Dynamic/Parser.h"11#include "clang/ASTMatchers/Dynamic/Registry.h"12#include "gtest/gtest.h"13#include <optional>14#include <string>15#include <vector>16 17namespace clang {18namespace ast_matchers {19namespace dynamic {20namespace {21 22class MockSema : public Parser::Sema {23public:24 ~MockSema() override {}25 26 uint64_t expectMatcher(StringRef MatcherName) {27 // Optimizations on the matcher framework make simple matchers like28 // 'stmt()' to be all the same matcher.29 // Use a more complex expression to prevent that.30 ast_matchers::internal::Matcher<Stmt> M = stmt(stmt(), stmt());31 ExpectedMatchers.insert(std::make_pair(std::string(MatcherName), M));32 return M.getID().second;33 }34 35 bool isBuilderMatcher(MatcherCtor) const override { return false; }36 37 ASTNodeKind nodeMatcherType(MatcherCtor) const override { return {}; }38 39 internal::MatcherDescriptorPtr40 buildMatcherCtor(MatcherCtor, SourceRange NameRange,41 ArrayRef<ParserValue> Args,42 Diagnostics *Error) const override {43 return internal::MatcherDescriptorPtr{nullptr};44 }45 46 void parse(StringRef Code) {47 Diagnostics Error;48 VariantValue Value;49 Parser::parseExpression(Code, this, &Value, &Error);50 Values.push_back(Value);51 Errors.push_back(Error.toStringFull());52 }53 54 std::optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) override {55 const ExpectedMatchersTy::value_type *Matcher =56 &*ExpectedMatchers.find(std::string(MatcherName));57 return reinterpret_cast<MatcherCtor>(Matcher);58 }59 60 VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,61 SourceRange NameRange,62 StringRef BindID,63 ArrayRef<ParserValue> Args,64 Diagnostics *Error) override {65 const ExpectedMatchersTy::value_type *Matcher =66 reinterpret_cast<const ExpectedMatchersTy::value_type *>(Ctor);67 MatcherInfo ToStore = {Matcher->first, NameRange, Args,68 std::string(BindID)};69 Matchers.push_back(ToStore);70 return VariantMatcher::SingleMatcher(Matcher->second);71 }72 73 struct MatcherInfo {74 StringRef MatcherName;75 SourceRange NameRange;76 std::vector<ParserValue> Args;77 std::string BoundID;78 };79 80 std::vector<std::string> Errors;81 std::vector<VariantValue> Values;82 std::vector<MatcherInfo> Matchers;83 typedef std::map<std::string, ast_matchers::internal::Matcher<Stmt> >84 ExpectedMatchersTy;85 ExpectedMatchersTy ExpectedMatchers;86};87 88TEST(ParserTest, ParseBoolean) {89 MockSema Sema;90 Sema.parse("true");91 Sema.parse("false");92 EXPECT_EQ(2U, Sema.Values.size());93 EXPECT_TRUE(Sema.Values[0].getBoolean());94 EXPECT_FALSE(Sema.Values[1].getBoolean());95}96 97TEST(ParserTest, ParseDouble) {98 MockSema Sema;99 Sema.parse("1.0");100 Sema.parse("2.0f");101 Sema.parse("34.56e-78");102 Sema.parse("4.E+6");103 Sema.parse("1");104 EXPECT_EQ(5U, Sema.Values.size());105 EXPECT_EQ(1.0, Sema.Values[0].getDouble());106 EXPECT_EQ("1:1: Error parsing numeric literal: <2.0f>", Sema.Errors[1]);107 EXPECT_EQ(34.56e-78, Sema.Values[2].getDouble());108 EXPECT_EQ(4e+6, Sema.Values[3].getDouble());109 EXPECT_FALSE(Sema.Values[4].isDouble());110}111 112TEST(ParserTest, ParseUnsigned) {113 MockSema Sema;114 Sema.parse("0");115 Sema.parse("123");116 Sema.parse("0x1f");117 Sema.parse("12345678901");118 Sema.parse("1a1");119 EXPECT_EQ(5U, Sema.Values.size());120 EXPECT_EQ(0U, Sema.Values[0].getUnsigned());121 EXPECT_EQ(123U, Sema.Values[1].getUnsigned());122 EXPECT_EQ(31U, Sema.Values[2].getUnsigned());123 EXPECT_EQ("1:1: Error parsing numeric literal: <12345678901>", Sema.Errors[3]);124 EXPECT_EQ("1:1: Error parsing numeric literal: <1a1>", Sema.Errors[4]);125}126 127TEST(ParserTest, ParseString) {128 MockSema Sema;129 Sema.parse("\"Foo\"");130 Sema.parse("\"\"");131 Sema.parse("\"Baz");132 EXPECT_EQ(3ULL, Sema.Values.size());133 EXPECT_EQ("Foo", Sema.Values[0].getString());134 EXPECT_EQ("", Sema.Values[1].getString());135 EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]);136}137 138bool matchesRange(SourceRange Range, unsigned StartLine,139 unsigned EndLine, unsigned StartColumn, unsigned EndColumn) {140 EXPECT_EQ(StartLine, Range.Start.Line);141 EXPECT_EQ(EndLine, Range.End.Line);142 EXPECT_EQ(StartColumn, Range.Start.Column);143 EXPECT_EQ(EndColumn, Range.End.Column);144 return Range.Start.Line == StartLine && Range.End.Line == EndLine &&145 Range.Start.Column == StartColumn && Range.End.Column == EndColumn;146}147 148std::optional<DynTypedMatcher> getSingleMatcher(const VariantValue &Value) {149 std::optional<DynTypedMatcher> Result = Value.getMatcher().getSingleMatcher();150 EXPECT_TRUE(Result);151 return Result;152}153 154TEST(ParserTest, ParseMatcher) {155 MockSema Sema;156 const uint64_t ExpectedFoo = Sema.expectMatcher("Foo");157 const uint64_t ExpectedBar = Sema.expectMatcher("Bar");158 const uint64_t ExpectedBaz = Sema.expectMatcher("Baz");159 Sema.parse(" Foo ( Bar ( 17), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") ");160 for (const auto &E : Sema.Errors) {161 EXPECT_EQ("", E);162 }163 164 EXPECT_NE(ExpectedFoo, ExpectedBar);165 EXPECT_NE(ExpectedFoo, ExpectedBaz);166 EXPECT_NE(ExpectedBar, ExpectedBaz);167 168 EXPECT_EQ(1ULL, Sema.Values.size());169 EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID().second);170 171 EXPECT_EQ(3ULL, Sema.Matchers.size());172 const MockSema::MatcherInfo Bar = Sema.Matchers[0];173 EXPECT_EQ("Bar", Bar.MatcherName);174 EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 17));175 EXPECT_EQ(1ULL, Bar.Args.size());176 EXPECT_EQ(17U, Bar.Args[0].Value.getUnsigned());177 178 const MockSema::MatcherInfo Baz = Sema.Matchers[1];179 EXPECT_EQ("Baz", Baz.MatcherName);180 EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 19, 10));181 EXPECT_EQ(1ULL, Baz.Args.size());182 EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString());183 184 const MockSema::MatcherInfo Foo = Sema.Matchers[2];185 EXPECT_EQ("Foo", Foo.MatcherName);186 EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));187 EXPECT_EQ(2ULL, Foo.Args.size());188 EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID().second);189 EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID().second);190 EXPECT_EQ("Yo!", Foo.BoundID);191}192 193TEST(ParserTest, ParseComment) {194 MockSema Sema;195 Sema.expectMatcher("Foo");196 Sema.parse(" Foo() # Bar() ");197 for (const auto &E : Sema.Errors) {198 EXPECT_EQ("", E);199 }200 201 EXPECT_EQ(1ULL, Sema.Matchers.size());202 203 Sema.parse("Foo(#) ");204 205 EXPECT_EQ("1:4: Error parsing matcher. Found end-of-code while looking for ')'.", Sema.Errors[1]);206}207 208using ast_matchers::internal::Matcher;209 210Parser::NamedValueMap getTestNamedValues() {211 Parser::NamedValueMap Values;212 Values["nameX"] = llvm::StringRef("x");213 Values["hasParamA"] = VariantMatcher::SingleMatcher(214 functionDecl(hasParameter(0, hasName("a"))));215 return Values;216}217 218TEST(ParserTest, FullParserTest) {219 Diagnostics Error;220 221 StringRef Code =222 "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"223 " hasOperatorName(\"+\"))))";224 std::optional<DynTypedMatcher> VarDecl(225 Parser::parseMatcherExpression(Code, &Error));226 EXPECT_EQ("", Error.toStringFull());227 Matcher<Decl> M = VarDecl->unconditionalConvertTo<Decl>();228 EXPECT_TRUE(matches("int x = 1 + false;", M));229 EXPECT_FALSE(matches("int x = true + 1;", M));230 EXPECT_FALSE(matches("int x = 1 - false;", M));231 EXPECT_FALSE(matches("int x = true - 1;", M));232 233 Code = "implicitCastExpr(hasCastKind(\"CK_IntegralToBoolean\"))";234 std::optional<DynTypedMatcher> implicitIntBooleanCast(235 Parser::parseMatcherExpression(Code, nullptr, nullptr, &Error));236 EXPECT_EQ("", Error.toStringFull());237 Matcher<Stmt> MCastStmt =238 traverse(TK_AsIs, implicitIntBooleanCast->unconditionalConvertTo<Stmt>());239 EXPECT_TRUE(matches("bool X = 1;", MCastStmt));240 EXPECT_FALSE(matches("bool X = true;", MCastStmt));241 242 Code = "functionDecl(hasParameter(1, hasName(\"x\")))";243 std::optional<DynTypedMatcher> HasParameter(244 Parser::parseMatcherExpression(Code, &Error));245 EXPECT_EQ("", Error.toStringFull());246 M = HasParameter->unconditionalConvertTo<Decl>();247 248 EXPECT_TRUE(matches("void f(int a, int x);", M));249 EXPECT_FALSE(matches("void f(int x, int a);", M));250 251 // Test named values.252 auto NamedValues = getTestNamedValues();253 254 Code = "functionDecl(hasParamA, hasParameter(1, hasName(nameX)))";255 std::optional<DynTypedMatcher> HasParameterWithNamedValues(256 Parser::parseMatcherExpression(Code, nullptr, &NamedValues, &Error));257 EXPECT_EQ("", Error.toStringFull());258 M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();259 260 EXPECT_TRUE(matches("void f(int a, int x);", M));261 EXPECT_FALSE(matches("void f(int x, int a);", M));262 263 Code = "unaryExprOrTypeTraitExpr(ofKind(\"UETT_SizeOf\"))";264 std::optional<DynTypedMatcher> UnaryExprSizeOf(265 Parser::parseMatcherExpression(Code, nullptr, nullptr, &Error));266 EXPECT_EQ("", Error.toStringFull());267 Matcher<Stmt> MStmt = UnaryExprSizeOf->unconditionalConvertTo<Stmt>();268 EXPECT_TRUE(matches("unsigned X = sizeof(int);", MStmt));269 EXPECT_FALSE(matches("unsigned X = alignof(int);", MStmt));270 271 Code =272 R"query(namedDecl(matchesName("^::[ABC]*$", "IgnoreCase | BasicRegex")))query";273 std::optional<DynTypedMatcher> MatchesName(274 Parser::parseMatcherExpression(Code, nullptr, nullptr, &Error));275 EXPECT_EQ("", Error.toStringFull());276 M = MatchesName->unconditionalConvertTo<Decl>();277 EXPECT_TRUE(matches("unsigned AAACCBB;", M));278 EXPECT_TRUE(matches("unsigned aaaccbb;", M));279 280 Code = "hasInitializer(\n binaryOperator(hasLHS(\"A\")))";281 EXPECT_TRUE(!Parser::parseMatcherExpression(Code, &Error));282 EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"283 "2:5: Error parsing argument 1 for matcher binaryOperator.\n"284 "2:20: Error building matcher hasLHS.\n"285 "2:27: Incorrect type for arg 1. "286 "(Expected = Matcher<Expr>) != (Actual = String)",287 Error.toStringFull());288}289 290TEST(ParserTest, VariadicMatchTest) {291 Diagnostics Error;292 293 StringRef Code =294 "stmt(objcMessageExpr(hasAnySelector(\"methodA\", \"methodB:\")))";295 std::optional<DynTypedMatcher> OM(296 Parser::parseMatcherExpression(Code, &Error));297 EXPECT_EQ("", Error.toStringFull());298 auto M = OM->unconditionalConvertTo<Stmt>();299 EXPECT_TRUE(matchesObjC("@interface I @end "300 "void foo(I* i) { [i methodA]; }", M));301}302 303std::string ParseWithError(StringRef Code) {304 Diagnostics Error;305 VariantValue Value;306 Parser::parseExpression(Code, &Value, &Error);307 return Error.toStringFull();308}309 310std::string ParseMatcherWithError(StringRef Code) {311 Diagnostics Error;312 Parser::parseMatcherExpression(Code, &Error);313 return Error.toStringFull();314}315 316TEST(ParserTest, Errors) {317 EXPECT_EQ(318 "1:5: Error parsing matcher. Found token <123> while looking for '('.",319 ParseWithError("Foo 123"));320 EXPECT_EQ(321 "1:1: Matcher not found: Foo\n"322 "1:9: Error parsing matcher. Found token <123> while looking for ','.",323 ParseWithError("Foo(\"A\" 123)"));324 EXPECT_EQ(325 "1:1: Error parsing argument 1 for matcher stmt.\n"326 "1:6: Value not found: someValue",327 ParseWithError("stmt(someValue)"));328 EXPECT_EQ(329 "1:1: Matcher not found: Foo\n"330 "1:4: Error parsing matcher. Found end-of-code while looking for ')'.",331 ParseWithError("Foo("));332 EXPECT_EQ("1:1: End of code found while looking for token.",333 ParseWithError(""));334 EXPECT_EQ("Input value is not a matcher expression.",335 ParseMatcherWithError("\"A\""));336 EXPECT_EQ("1:1: Matcher not found: Foo\n"337 "1:1: Error parsing argument 1 for matcher Foo.\n"338 "1:5: Invalid token <(> found when looking for a value.",339 ParseWithError("Foo(("));340 EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a"));341 EXPECT_EQ("1:11: Period not followed by valid chained call.",342 ParseWithError("isArrow().biind"));343 EXPECT_EQ("1:15: Malformed bind() expression.",344 ParseWithError("isArrow().bind"));345 EXPECT_EQ("1:16: Malformed bind() expression.",346 ParseWithError("isArrow().bind(foo"));347 EXPECT_EQ("1:21: Malformed bind() expression.",348 ParseWithError("isArrow().bind(\"foo\""));349 EXPECT_EQ("1:1: Error building matcher isArrow.\n"350 "1:1: Matcher does not support binding.",351 ParseWithError("isArrow().bind(\"foo\")"));352 EXPECT_EQ("1:1: Error building matcher isArrow.\n"353 "1:11: Matcher does not support with call.",354 ParseWithError("isArrow().with"));355 EXPECT_EQ(356 "1:22: Error parsing matcher. Found token <EOF> while looking for '('.",357 ParseWithError("mapAnyOf(ifStmt).with"));358 EXPECT_EQ(359 "1:22: Error parsing matcher. Found end-of-code while looking for ')'.",360 ParseWithError("mapAnyOf(ifStmt).with("));361 EXPECT_EQ("1:1: Failed to build matcher: mapAnyOf.",362 ParseWithError("mapAnyOf()"));363 EXPECT_EQ("1:1: Error parsing argument 1 for matcher mapAnyOf.\n1:1: Failed "364 "to build matcher: mapAnyOf.",365 ParseWithError("mapAnyOf(\"foo\")"));366 EXPECT_EQ("Input value has unresolved overloaded type: "367 "Matcher<DoStmt|ForStmt|WhileStmt|CXXForRangeStmt|FunctionDecl|"368 "CoroutineBodyStmt>",369 ParseMatcherWithError("hasBody(stmt())"));370 EXPECT_EQ(371 "1:1: Error parsing argument 1 for matcher decl.\n"372 "1:6: Error building matcher hasAttr.\n"373 "1:14: Unknown value 'attr::Fnal' for arg 1; did you mean 'attr::Final'",374 ParseMatcherWithError(R"query(decl(hasAttr("attr::Fnal")))query"));375 EXPECT_EQ("1:1: Error parsing argument 1 for matcher decl.\n"376 "1:6: Error building matcher hasAttr.\n"377 "1:14: Unknown value 'Final' for arg 1; did you mean 'attr::Final'",378 ParseMatcherWithError(R"query(decl(hasAttr("Final")))query"));379 EXPECT_EQ("1:1: Error parsing argument 1 for matcher decl.\n"380 "1:6: Error building matcher hasAttr.\n"381 "1:14: Value not found: unrelated",382 ParseMatcherWithError(R"query(decl(hasAttr("unrelated")))query"));383 EXPECT_EQ(384 "1:1: Error parsing argument 1 for matcher namedDecl.\n"385 "1:11: Error building matcher matchesName.\n"386 "1:33: Unknown value 'Ignorecase' for arg 2; did you mean 'IgnoreCase'",387 ParseMatcherWithError(388 R"query(namedDecl(matchesName("[ABC]*", "Ignorecase")))query"));389 EXPECT_EQ(390 "1:1: Error parsing argument 1 for matcher namedDecl.\n"391 "1:11: Error building matcher matchesName.\n"392 "1:33: Value not found: IgnoreCase & BasicRegex",393 ParseMatcherWithError(394 R"query(namedDecl(matchesName("[ABC]*", "IgnoreCase & BasicRegex")))query"));395 EXPECT_EQ(396 "1:1: Error parsing argument 1 for matcher namedDecl.\n"397 "1:11: Error building matcher matchesName.\n"398 "1:33: Unknown value 'IgnoreCase | Basicregex' for arg 2; did you mean "399 "'IgnoreCase | BasicRegex'",400 ParseMatcherWithError(401 R"query(namedDecl(matchesName("[ABC]*", "IgnoreCase | Basicregex")))query"));402}403 404TEST(ParserTest, OverloadErrors) {405 EXPECT_EQ("1:1: Error building matcher callee.\n"406 "1:8: Candidate 1: Incorrect type for arg 1. "407 "(Expected = Matcher<Stmt>) != (Actual = String)\n"408 "1:8: Candidate 2: Incorrect type for arg 1. "409 "(Expected = Matcher<Decl>) != (Actual = String)",410 ParseWithError("callee(\"A\")"));411}412 413TEST(ParserTest, ParseMultiline) {414 StringRef Code;415 416 std::optional<DynTypedMatcher> M;417 {418 Code = R"matcher(varDecl(419 hasName("foo")420 )421)matcher";422 Diagnostics Error;423 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error));424 }425 426 {427 Code = R"matcher(varDecl(428 # Internal comment429 hasName("foo") # Internal comment430# Internal comment431 )432)matcher";433 Diagnostics Error;434 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error));435 }436 437 {438 Code = R"matcher(decl().bind(439 "paramName")440)matcher";441 Diagnostics Error;442 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error));443 }444 445 {446 Code = R"matcher(decl().bind(447 "paramName"448 )449)matcher";450 Diagnostics Error;451 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error).has_value());452 }453 454 {455 Code = R"matcher(decl(decl()456, decl()))matcher";457 Diagnostics Error;458 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error).has_value());459 }460 461 {462 Code = R"matcher(decl(decl(),463decl()))matcher";464 Diagnostics Error;465 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error).has_value());466 }467 468 {469 Code = "namedDecl(hasName(\"n\"\n))";470 Diagnostics Error;471 EXPECT_TRUE(Parser::parseMatcherExpression(Code, &Error).has_value());472 }473 474 {475 Diagnostics Error;476 477 auto NamedValues = getTestNamedValues();478 479 Code = R"matcher(hasParamA.bind480 ("paramName")481)matcher";482 M = Parser::parseMatcherExpression(Code, nullptr, &NamedValues, &Error);483 EXPECT_FALSE(M);484 EXPECT_EQ("1:15: Malformed bind() expression.", Error.toStringFull());485 }486 487 {488 Diagnostics Error;489 490 auto NamedValues = getTestNamedValues();491 492 Code = R"matcher(hasParamA.493 bind("paramName")494)matcher";495 M = Parser::parseMatcherExpression(Code, nullptr, &NamedValues, &Error);496 EXPECT_FALSE(M);497 EXPECT_EQ("1:11: Period not followed by valid chained call.",498 Error.toStringFull());499 }500 501 {502 Diagnostics Error;503 504 Code = R"matcher(varDecl505()506)matcher";507 M = Parser::parseMatcherExpression(Code, nullptr, nullptr, &Error);508 EXPECT_FALSE(M);509 EXPECT_EQ("1:8: Error parsing matcher. Found token "510 "<NewLine> while looking for '('.",511 Error.toStringFull());512 }513 514 // Correct line/column numbers515 {516 Diagnostics Error;517 518 Code = R"matcher(varDecl(519 doesNotExist()520 )521)matcher";522 M = Parser::parseMatcherExpression(Code, nullptr, nullptr, &Error);523 EXPECT_FALSE(M);524 StringRef Expected = R"error(1:1: Error parsing argument 1 for matcher varDecl.5252:3: Matcher not found: doesNotExist)error";526 EXPECT_EQ(Expected, Error.toStringFull());527 }528}529 530TEST(ParserTest, CompletionRegistry) {531 StringRef Code = "while";532 std::vector<MatcherCompletion> Comps = Parser::completeExpression(Code, 5);533 ASSERT_EQ(1u, Comps.size());534 EXPECT_EQ("Stmt(", Comps[0].TypedText);535 EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)",536 Comps[0].MatcherDecl);537 538 Code = "whileStmt().";539 Comps = Parser::completeExpression(Code, 12);540 ASSERT_EQ(1u, Comps.size());541 EXPECT_EQ("bind(\"", Comps[0].TypedText);542 EXPECT_EQ("bind", Comps[0].MatcherDecl);543 544 Code = "mapAny";545 Comps = Parser::completeExpression(Code, 6);546 ASSERT_EQ(1u, Comps.size());547 EXPECT_EQ("Of(", Comps[0].TypedText);548 EXPECT_EQ("Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> "549 "mapAnyOf(NestedNameSpecifierLoc|QualType|TypeLoc|"550 "NestedNameSpecifier|Decl|Stmt|Type...)",551 Comps[0].MatcherDecl);552 553 Code = "mapAnyOf(ifStmt).";554 Comps = Parser::completeExpression(Code, 17);555 ASSERT_EQ(2u, Comps.size());556 EXPECT_EQ("bind(\"", Comps[0].TypedText);557 EXPECT_EQ("bind", Comps[0].MatcherDecl);558 EXPECT_EQ("with(", Comps[1].TypedText);559 EXPECT_EQ("with", Comps[1].MatcherDecl);560 561 Code = "mapAnyOf(ifS";562 Comps = Parser::completeExpression(Code, 12);563 ASSERT_EQ(1u, Comps.size());564 EXPECT_EQ("tmt", Comps[0].TypedText);565 EXPECT_EQ("ifStmt", Comps[0].MatcherDecl);566}567 568TEST(ParserTest, CompletionNamedValues) {569 // Can complete non-matcher types.570 auto NamedValues = getTestNamedValues();571 StringRef Code = "functionDecl(hasName(";572 std::vector<MatcherCompletion> Comps =573 Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);574 ASSERT_EQ(1u, Comps.size());575 EXPECT_EQ("nameX", Comps[0].TypedText);576 EXPECT_EQ("String nameX", Comps[0].MatcherDecl);577 578 // Can complete if there are names in the expression.579 Code = "cxxMethodDecl(hasName(nameX), ";580 Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);581 EXPECT_LT(0u, Comps.size());582 583 // Can complete names and registry together.584 Code = "functionDecl(hasP";585 Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);586 ASSERT_EQ(3u, Comps.size());587 588 EXPECT_EQ("arameter(", Comps[0].TypedText);589 EXPECT_EQ(590 "Matcher<FunctionDecl> hasParameter(unsigned, Matcher<ParmVarDecl>)",591 Comps[0].MatcherDecl);592 593 EXPECT_EQ("aramA", Comps[1].TypedText);594 EXPECT_EQ("Matcher<Decl> hasParamA", Comps[1].MatcherDecl);595 596 EXPECT_EQ("arent(", Comps[2].TypedText);597 EXPECT_EQ(598 "Matcher<Decl> "599 "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)",600 Comps[2].MatcherDecl);601}602 603TEST(ParserTest, ParseBindOnLet) {604 605 auto NamedValues = getTestNamedValues();606 607 Diagnostics Error;608 609 {610 StringRef Code = "hasParamA.bind(\"parmABinding\")";611 std::optional<DynTypedMatcher> TopLevelLetBinding(612 Parser::parseMatcherExpression(Code, nullptr, &NamedValues, &Error));613 EXPECT_EQ("", Error.toStringFull());614 auto M = TopLevelLetBinding->unconditionalConvertTo<Decl>();615 616 EXPECT_TRUE(matchAndVerifyResultTrue(617 "void foo(int a);", M,618 std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding")));619 EXPECT_TRUE(matchAndVerifyResultFalse(620 "void foo(int b);", M,621 std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding")));622 }623 624 {625 StringRef Code = "functionDecl(hasParamA.bind(\"parmABinding\"))";626 std::optional<DynTypedMatcher> NestedLetBinding(627 Parser::parseMatcherExpression(Code, nullptr, &NamedValues, &Error));628 EXPECT_EQ("", Error.toStringFull());629 auto M = NestedLetBinding->unconditionalConvertTo<Decl>();630 631 EXPECT_TRUE(matchAndVerifyResultTrue(632 "void foo(int a);", M,633 std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding")));634 EXPECT_TRUE(matchAndVerifyResultFalse(635 "void foo(int b);", M,636 std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding")));637 }638}639 640} // end anonymous namespace641} // end namespace dynamic642} // end namespace ast_matchers643} // end namespace clang644