| 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-exception |
| 6 | // |
| 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 | |
| 17 | namespace clang { |
| 18 | namespace ast_matchers { |
| 19 | namespace dynamic { |
| 20 | namespace { |
| 21 | |
| 22 | class MockSema : public Parser::Sema { |
| 23 | public: |
| 24 | ~MockSema() override {} |
| 25 | |
| 26 | uint64_t expectMatcher(StringRef MatcherName) { |
| 27 | // Optimizations on the matcher framework make simple matchers like |
| 28 | // '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(x: std::make_pair(x: std::string(MatcherName), y&: 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::MatcherDescriptorPtr |
| 40 | 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, S: this, Value: &Value, Error: &Error); |
| 50 | Values.push_back(x: Value); |
| 51 | Errors.push_back(x: Error.toStringFull()); |
| 52 | } |
| 53 | |
| 54 | std::optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) override { |
| 55 | const ExpectedMatchersTy::value_type *Matcher = |
| 56 | &*ExpectedMatchers.find(x: 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 = {.MatcherName: Matcher->first, .NameRange: NameRange, .Args: Args, |
| 68 | .BoundID: std::string(BindID)}; |
| 69 | Matchers.push_back(x: ToStore); |
| 70 | return VariantMatcher::SingleMatcher(Matcher: 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 | |
| 88 | TEST(ParserTest, ParseBoolean) { |
| 89 | MockSema Sema; |
| 90 | Sema.parse(Code: "true" ); |
| 91 | Sema.parse(Code: "false" ); |
| 92 | EXPECT_EQ(2U, Sema.Values.size()); |
| 93 | EXPECT_TRUE(Sema.Values[0].getBoolean()); |
| 94 | EXPECT_FALSE(Sema.Values[1].getBoolean()); |
| 95 | } |
| 96 | |
| 97 | TEST(ParserTest, ParseDouble) { |
| 98 | MockSema Sema; |
| 99 | Sema.parse(Code: "1.0" ); |
| 100 | Sema.parse(Code: "2.0f" ); |
| 101 | Sema.parse(Code: "34.56e-78" ); |
| 102 | Sema.parse(Code: "4.E+6" ); |
| 103 | Sema.parse(Code: "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 | |
| 112 | TEST(ParserTest, ParseUnsigned) { |
| 113 | MockSema Sema; |
| 114 | Sema.parse(Code: "0" ); |
| 115 | Sema.parse(Code: "123" ); |
| 116 | Sema.parse(Code: "0x1f" ); |
| 117 | Sema.parse(Code: "12345678901" ); |
| 118 | Sema.parse(Code: "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 | |
| 127 | TEST(ParserTest, ParseString) { |
| 128 | MockSema Sema; |
| 129 | Sema.parse(Code: "\"Foo\"" ); |
| 130 | Sema.parse(Code: "\"\"" ); |
| 131 | Sema.parse(Code: "\"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 | |
| 138 | bool 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 | |
| 148 | std::optional<DynTypedMatcher> getSingleMatcher(const VariantValue &Value) { |
| 149 | std::optional<DynTypedMatcher> Result = Value.getMatcher().getSingleMatcher(); |
| 150 | EXPECT_TRUE(Result); |
| 151 | return Result; |
| 152 | } |
| 153 | |
| 154 | TEST(ParserTest, ParseMatcher) { |
| 155 | MockSema Sema; |
| 156 | const uint64_t ExpectedFoo = Sema.expectMatcher(MatcherName: "Foo" ); |
| 157 | const uint64_t ExpectedBar = Sema.expectMatcher(MatcherName: "Bar" ); |
| 158 | const uint64_t ExpectedBaz = Sema.expectMatcher(MatcherName: "Baz" ); |
| 159 | Sema.parse(Code: " 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 | |
| 193 | TEST(ParserTest, ParseComment) { |
| 194 | MockSema Sema; |
| 195 | Sema.expectMatcher(MatcherName: "Foo" ); |
| 196 | Sema.parse(Code: " 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(Code: "Foo(#) " ); |
| 204 | |
| 205 | EXPECT_EQ("1:4: Error parsing matcher. Found end-of-code while looking for ')'." , Sema.Errors[1]); |
| 206 | } |
| 207 | |
| 208 | using ast_matchers::internal::Matcher; |
| 209 | |
| 210 | Parser::NamedValueMap getTestNamedValues() { |
| 211 | Parser::NamedValueMap Values; |
| 212 | Values["nameX" ] = llvm::StringRef("x" ); |
| 213 | Values["hasParamA" ] = VariantMatcher::SingleMatcher( |
| 214 | Matcher: functionDecl(hasParameter(N: 0, InnerMatcher: hasName(Name: "a" )))); |
| 215 | return Values; |
| 216 | } |
| 217 | |
| 218 | TEST(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(MatcherCode&: Code, Error: &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(MatcherCode&: Code, S: nullptr, NamedValues: nullptr, Error: &Error)); |
| 236 | EXPECT_EQ("" , Error.toStringFull()); |
| 237 | Matcher<Stmt> MCastStmt = |
| 238 | traverse(TK: TK_AsIs, InnerMatcher: 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(MatcherCode&: Code, Error: &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(MatcherCode&: Code, S: nullptr, NamedValues: &NamedValues, Error: &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(MatcherCode&: Code, S: nullptr, NamedValues: nullptr, Error: &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(MatcherCode&: Code, S: nullptr, NamedValues: nullptr, Error: &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 | |
| 290 | TEST(ParserTest, VariadicMatchTest) { |
| 291 | Diagnostics Error; |
| 292 | |
| 293 | StringRef Code = |
| 294 | "stmt(objcMessageExpr(hasAnySelector(\"methodA\", \"methodB:\")))" ; |
| 295 | std::optional<DynTypedMatcher> OM( |
| 296 | Parser::parseMatcherExpression(MatcherCode&: Code, Error: &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 | |
| 303 | std::string ParseWithError(StringRef Code) { |
| 304 | Diagnostics Error; |
| 305 | VariantValue Value; |
| 306 | Parser::parseExpression(Code, Value: &Value, Error: &Error); |
| 307 | return Error.toStringFull(); |
| 308 | } |
| 309 | |
| 310 | std::string ParseMatcherWithError(StringRef Code) { |
| 311 | Diagnostics Error; |
| 312 | Parser::parseMatcherExpression(MatcherCode&: Code, Error: &Error); |
| 313 | return Error.toStringFull(); |
| 314 | } |
| 315 | |
| 316 | TEST(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 | |
| 404 | TEST(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 | |
| 413 | TEST(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 comment |
| 429 | hasName("foo") # Internal comment |
| 430 | # Internal comment |
| 431 | ) |
| 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(), |
| 463 | decl()))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.bind |
| 480 | ("paramName") |
| 481 | )matcher" ; |
| 482 | M = Parser::parseMatcherExpression(MatcherCode&: Code, S: nullptr, NamedValues: &NamedValues, Error: &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(MatcherCode&: Code, S: nullptr, NamedValues: &NamedValues, Error: &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(varDecl |
| 505 | () |
| 506 | )matcher" ; |
| 507 | M = Parser::parseMatcherExpression(MatcherCode&: Code, S: nullptr, NamedValues: nullptr, Error: &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 numbers |
| 515 | { |
| 516 | Diagnostics Error; |
| 517 | |
| 518 | Code = R"matcher(varDecl( |
| 519 | doesNotExist() |
| 520 | ) |
| 521 | )matcher" ; |
| 522 | M = Parser::parseMatcherExpression(MatcherCode&: Code, S: nullptr, NamedValues: nullptr, Error: &Error); |
| 523 | EXPECT_FALSE(M); |
| 524 | StringRef Expected = R"error(1:1: Error parsing argument 1 for matcher varDecl. |
| 525 | 2:3: Matcher not found: doesNotExist)error" ; |
| 526 | EXPECT_EQ(Expected, Error.toStringFull()); |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | TEST(ParserTest, CompletionRegistry) { |
| 531 | StringRef Code = "while" ; |
| 532 | std::vector<MatcherCompletion> Comps = Parser::completeExpression(Code, CompletionOffset: 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, CompletionOffset: 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, CompletionOffset: 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, CompletionOffset: 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, CompletionOffset: 12); |
| 563 | ASSERT_EQ(1u, Comps.size()); |
| 564 | EXPECT_EQ("tmt" , Comps[0].TypedText); |
| 565 | EXPECT_EQ("ifStmt" , Comps[0].MatcherDecl); |
| 566 | } |
| 567 | |
| 568 | TEST(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, CompletionOffset: Code.size(), S: nullptr, NamedValues: &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, CompletionOffset: Code.size(), S: nullptr, NamedValues: &NamedValues); |
| 581 | EXPECT_LT(0u, Comps.size()); |
| 582 | |
| 583 | // Can complete names and registry together. |
| 584 | Code = "functionDecl(hasP" ; |
| 585 | Comps = Parser::completeExpression(Code, CompletionOffset: Code.size(), S: nullptr, NamedValues: &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 | |
| 603 | TEST(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(MatcherCode&: Code, S: nullptr, NamedValues: &NamedValues, Error: &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(MatcherCode&: Code, S: nullptr, NamedValues: &NamedValues, Error: &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 namespace |
| 641 | } // end namespace dynamic |
| 642 | } // end namespace ast_matchers |
| 643 | } // end namespace clang |
| 644 | |