brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.1 KiB · e414587 Raw
409 lines · cpp
1//===---- QueryParserTest.cpp - clang-query test --------------------------===//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 "QueryParser.h"10#include "Query.h"11#include "QuerySession.h"12#include "llvm/LineEditor/LineEditor.h"13#include "gtest/gtest.h"14 15using namespace clang;16using namespace clang::query;17 18class QueryParserTest : public ::testing::Test {19protected:20  QueryParserTest() : QS(llvm::ArrayRef<std::unique_ptr<ASTUnit>>()) {}21  QueryRef parse(StringRef Code) { return QueryParser::parse(Code, QS); }22 23  QuerySession QS;24};25 26TEST_F(QueryParserTest, NoOp) {27  QueryRef Q = parse("");28  EXPECT_TRUE(isa<NoOpQuery>(Q));29 30  Q = parse("\n");31  EXPECT_TRUE(isa<NoOpQuery>(Q));32}33 34TEST_F(QueryParserTest, Invalid) {35  QueryRef Q = parse("foo");36  ASSERT_TRUE(isa<InvalidQuery>(Q));37  EXPECT_EQ("unknown command: foo", cast<InvalidQuery>(Q)->ErrStr);38}39 40TEST_F(QueryParserTest, Help) {41  QueryRef Q = parse("help");42  ASSERT_TRUE(isa<HelpQuery>(Q));43 44  Q = parse("help me");45  ASSERT_TRUE(isa<InvalidQuery>(Q));46  EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);47}48 49TEST_F(QueryParserTest, Quit) {50  QueryRef Q = parse("quit");51  ASSERT_TRUE(isa<QuitQuery>(Q));52 53  Q = parse("q");54  ASSERT_TRUE(isa<QuitQuery>(Q));55 56  Q = parse("quit me");57  ASSERT_TRUE(isa<InvalidQuery>(Q));58  EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);59}60 61TEST_F(QueryParserTest, Set) {62 63  QueryRef Q = parse("set");64  ASSERT_TRUE(isa<InvalidQuery>(Q));65  EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);66 67  Q = parse("set foo bar");68  ASSERT_TRUE(isa<InvalidQuery>(Q));69  EXPECT_EQ("unknown variable: 'foo'", cast<InvalidQuery>(Q)->ErrStr);70 71  Q = parse("set output");72  ASSERT_TRUE(isa<InvalidQuery>(Q));73  EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''",74            cast<InvalidQuery>(Q)->ErrStr);75 76  Q = parse("set bind-root true foo");77  ASSERT_TRUE(isa<InvalidQuery>(Q));78  EXPECT_EQ("unexpected extra input: ' foo'", cast<InvalidQuery>(Q)->ErrStr);79 80  Q = parse("set output foo");81  ASSERT_TRUE(isa<InvalidQuery>(Q));82  EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'",83            cast<InvalidQuery>(Q)->ErrStr);84 85  Q = parse("set output dump");86  ASSERT_TRUE(isa<SetExclusiveOutputQuery >(Q));87  EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var);88 89  Q = parse("set output detailed-ast");90  ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));91  EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var);92 93  Q = parse("enable output detailed-ast");94  ASSERT_TRUE(isa<EnableOutputQuery>(Q));95  EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<EnableOutputQuery>(Q)->Var);96 97  Q = parse("enable");98  ASSERT_TRUE(isa<InvalidQuery>(Q));99  EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);100 101  Q = parse("disable output detailed-ast");102  ASSERT_TRUE(isa<DisableOutputQuery>(Q));103  EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<DisableOutputQuery>(Q)->Var);104 105  Q = parse("set bind-root foo");106  ASSERT_TRUE(isa<InvalidQuery>(Q));107  EXPECT_EQ("expected 'true' or 'false', got 'foo'",108            cast<InvalidQuery>(Q)->ErrStr);109 110  Q = parse("set bind-root true");111  ASSERT_TRUE(isa<SetQuery<bool> >(Q));112  EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var);113  EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value);114 115  Q = parse("set traversal AsIs");116  ASSERT_TRUE(isa<SetQuery<TraversalKind>>(Q));117  EXPECT_EQ(&QuerySession::TK, cast<SetQuery<TraversalKind>>(Q)->Var);118  EXPECT_EQ(TK_AsIs, cast<SetQuery<TraversalKind>>(Q)->Value);119 120  Q = parse("set traversal NotATraversal");121  ASSERT_TRUE(isa<InvalidQuery>(Q));122  EXPECT_EQ("expected traversal kind, got 'NotATraversal'",123            cast<InvalidQuery>(Q)->ErrStr);124}125 126TEST_F(QueryParserTest, Match) {127  QueryRef Q = parse("match decl()");128  ASSERT_TRUE(isa<MatchQuery>(Q));129  EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Decl>());130 131  Q = parse("m stmt()");132  ASSERT_TRUE(isa<MatchQuery>(Q));133  EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Stmt>());134}135 136TEST_F(QueryParserTest, LetUnlet) {137  QueryRef Q = parse("let foo decl()");138  ASSERT_TRUE(isa<LetQuery>(Q));139  EXPECT_EQ("foo", cast<LetQuery>(Q)->Name);140  EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher());141  EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>());142 143  Q = parse("l foo decl()");144  ASSERT_TRUE(isa<LetQuery>(Q));145  EXPECT_EQ("foo", cast<LetQuery>(Q)->Name);146  EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher());147  EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>());148 149  Q = parse("let bar \"str\"");150  ASSERT_TRUE(isa<LetQuery>(Q));151  EXPECT_EQ("bar", cast<LetQuery>(Q)->Name);152  EXPECT_TRUE(cast<LetQuery>(Q)->Value.isString());153  EXPECT_EQ("str", cast<LetQuery>(Q)->Value.getString());154 155  Q = parse("let");156  ASSERT_TRUE(isa<InvalidQuery>(Q));157  EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);158 159  Q = parse("unlet x");160  ASSERT_TRUE(isa<LetQuery>(Q));161  EXPECT_EQ("x", cast<LetQuery>(Q)->Name);162  EXPECT_FALSE(cast<LetQuery>(Q)->Value.hasValue());163 164  Q = parse("unlet");165  ASSERT_TRUE(isa<InvalidQuery>(Q));166  EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);167 168  Q = parse("unlet x bad_data");169  ASSERT_TRUE(isa<InvalidQuery>(Q));170  EXPECT_EQ("unexpected extra input: ' bad_data'",171            cast<InvalidQuery>(Q)->ErrStr);172}173 174TEST_F(QueryParserTest, Comment) {175  QueryRef Q = parse("# let foo decl()");176  ASSERT_TRUE(isa<NoOpQuery>(Q));177 178  Q = parse("let foo decl() # creates a decl() matcher called foo");179  ASSERT_TRUE(isa<LetQuery>(Q));180 181  Q = parse("set bind-root false # reduce noise");182  ASSERT_TRUE(isa<SetQuery<bool>>(Q));183}184 185TEST_F(QueryParserTest, Complete) {186  std::vector<llvm::LineEditor::Completion> Comps =187      QueryParser::complete("", 0, QS);188  ASSERT_EQ(9u, Comps.size());189  EXPECT_EQ("help ", Comps[0].TypedText);190  EXPECT_EQ("help", Comps[0].DisplayText);191  EXPECT_EQ("let ", Comps[1].TypedText);192  EXPECT_EQ("let", Comps[1].DisplayText);193  EXPECT_EQ("match ", Comps[2].TypedText);194  EXPECT_EQ("match", Comps[2].DisplayText);195  EXPECT_EQ("quit ", Comps[3].TypedText);196  EXPECT_EQ("quit", Comps[3].DisplayText);197  EXPECT_EQ("set ", Comps[4].TypedText);198  EXPECT_EQ("set", Comps[4].DisplayText);199  EXPECT_EQ("enable ", Comps[5].TypedText);200  EXPECT_EQ("enable", Comps[5].DisplayText);201  EXPECT_EQ("disable ", Comps[6].TypedText);202  EXPECT_EQ("disable", Comps[6].DisplayText);203  EXPECT_EQ("unlet ", Comps[7].TypedText);204  EXPECT_EQ("unlet", Comps[7].DisplayText);205  EXPECT_EQ("file ", Comps[8].TypedText);206  EXPECT_EQ("file", Comps[8].DisplayText);207 208  Comps = QueryParser::complete("set o", 5, QS);209  ASSERT_EQ(1u, Comps.size());210  EXPECT_EQ("utput ", Comps[0].TypedText);211  EXPECT_EQ("output", Comps[0].DisplayText);212 213  Comps = QueryParser::complete("set t", 5, QS);214  ASSERT_EQ(1u, Comps.size());215  EXPECT_EQ("raversal ", Comps[0].TypedText);216  EXPECT_EQ("traversal", Comps[0].DisplayText);217 218  Comps = QueryParser::complete("enable ", 7, QS);219  ASSERT_EQ(1u, Comps.size());220  EXPECT_EQ("output ", Comps[0].TypedText);221  EXPECT_EQ("output", Comps[0].DisplayText);222 223  Comps = QueryParser::complete("enable output ", 14, QS);224  ASSERT_EQ(4u, Comps.size());225 226  EXPECT_EQ("diag ", Comps[0].TypedText);227  EXPECT_EQ("diag", Comps[0].DisplayText);228  EXPECT_EQ("print ", Comps[1].TypedText);229  EXPECT_EQ("print", Comps[1].DisplayText);230  EXPECT_EQ("detailed-ast ", Comps[2].TypedText);231  EXPECT_EQ("detailed-ast", Comps[2].DisplayText);232  EXPECT_EQ("dump ", Comps[3].TypedText);233  EXPECT_EQ("dump", Comps[3].DisplayText);234 235  Comps = QueryParser::complete("set traversal ", 14, QS);236  ASSERT_EQ(2u, Comps.size());237 238  EXPECT_EQ("AsIs ", Comps[0].TypedText);239  EXPECT_EQ("AsIs", Comps[0].DisplayText);240  EXPECT_EQ("IgnoreUnlessSpelledInSource ", Comps[1].TypedText);241  EXPECT_EQ("IgnoreUnlessSpelledInSource", Comps[1].DisplayText);242 243  Comps = QueryParser::complete("match while", 11, QS);244  ASSERT_EQ(1u, Comps.size());245  EXPECT_EQ("Stmt(", Comps[0].TypedText);246  EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)",247            Comps[0].DisplayText);248 249  Comps = QueryParser::complete("m", 1, QS);250  ASSERT_EQ(1u, Comps.size());251  EXPECT_EQ("atch ", Comps[0].TypedText);252  EXPECT_EQ("match", Comps[0].DisplayText);253 254  Comps = QueryParser::complete("l", 1, QS);255  ASSERT_EQ(1u, Comps.size());256  EXPECT_EQ("et ", Comps[0].TypedText);257  EXPECT_EQ("let", Comps[0].DisplayText);258}259 260TEST_F(QueryParserTest, Multiline) {261 262  // Single string with multiple commands263  QueryRef Q = parse(R"matcher(264set bind-root false265set output dump266    )matcher");267 268  ASSERT_TRUE(isa<SetQuery<bool>>(Q));269 270  Q = parse(Q->RemainingContent);271  ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));272 273  // Missing newline274  Q = parse(R"matcher(275set bind-root false set output dump276    )matcher");277 278  ASSERT_TRUE(isa<InvalidQuery>(Q));279  EXPECT_EQ("unexpected extra input: ' set output dump\n    '",280            cast<InvalidQuery>(Q)->ErrStr);281 282  // Commands which do their own parsing283  Q = parse(R"matcher(284let fn functionDecl(hasName("foo"))285match callExpr(callee(functionDecl()))286    )matcher");287 288  ASSERT_TRUE(isa<LetQuery>(Q));289 290  Q = parse(Q->RemainingContent);291  ASSERT_TRUE(isa<MatchQuery>(Q));292 293  // Multi-line matcher294  Q = parse(R"matcher(295match callExpr(callee(296    functionDecl().bind("fn")297    ))298 299    )matcher");300 301  ASSERT_TRUE(isa<MatchQuery>(Q));302 303  // Comment locations304  Q = parse(R"matcher(305#nospacecomment306# Leading comment307match callExpr ( # Trailing comment308            # Comment alone on line309 310            callee(311            functionDecl(312            ).bind(313            "fn"314            )315            )) # Comment trailing close316# Comment after match317    )matcher");318 319  ASSERT_TRUE(isa<MatchQuery>(Q));320 321  // \r\n322  Q = parse("set bind-root false\r\nset output dump");323 324  ASSERT_TRUE(isa<SetQuery<bool>>(Q));325 326  Q = parse(Q->RemainingContent);327  ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));328 329  // Leading and trailing space in lines330  Q = parse("  set bind-root false  \r\n  set output dump  ");331 332  ASSERT_TRUE(isa<SetQuery<bool>>(Q));333 334  Q = parse(Q->RemainingContent);335  ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));336 337  // Incomplete commands338  Q = parse("set\nbind-root false");339 340  ASSERT_TRUE(isa<InvalidQuery>(Q));341  EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);342 343  Q = parse("set bind-root\nfalse");344 345  ASSERT_TRUE(isa<InvalidQuery>(Q));346  EXPECT_EQ("expected 'true' or 'false', got ''",347            cast<InvalidQuery>(Q)->ErrStr);348 349  Q = parse(R"matcher(350match callExpr351(352)353    )matcher");354 355  ASSERT_TRUE(isa<InvalidQuery>(Q));356  EXPECT_EQ("1:9: Error parsing matcher. Found token <NewLine> "357            "while looking for '('.",358            cast<InvalidQuery>(Q)->ErrStr);359 360  Q = parse("let someMatcher\nm parmVarDecl()");361 362  ASSERT_TRUE(isa<InvalidQuery>(Q));363  EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",364            cast<InvalidQuery>(Q)->ErrStr);365 366  Q = parse("\nm parmVarDecl()\nlet someMatcher\nm parmVarDecl()");367 368  ASSERT_TRUE(isa<MatchQuery>(Q));369  Q = parse(Q->RemainingContent);370 371  ASSERT_TRUE(isa<InvalidQuery>(Q));372  EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",373            cast<InvalidQuery>(Q)->ErrStr);374 375  Q = parse("\nlet someMatcher\n");376 377  ASSERT_TRUE(isa<InvalidQuery>(Q));378  EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",379            cast<InvalidQuery>(Q)->ErrStr);380 381  Q = parse("\nm parmVarDecl()\nlet someMatcher\n");382 383  ASSERT_TRUE(isa<MatchQuery>(Q));384  Q = parse(Q->RemainingContent);385 386  ASSERT_TRUE(isa<InvalidQuery>(Q));387  EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",388            cast<InvalidQuery>(Q)->ErrStr);389 390  Q = parse(R"matcher(391 392let Construct parmVarDecl()393 394m parmVarDecl(395    Construct396)397)matcher");398 399  ASSERT_TRUE(isa<LetQuery>(Q));400  {401    llvm::raw_null_ostream NullOutStream;402    dyn_cast<LetQuery>(Q)->run(NullOutStream, QS);403  }404 405  Q = parse(Q->RemainingContent);406 407  ASSERT_TRUE(isa<MatchQuery>(Q));408}409