forked from OSchip/llvm-project
Add new 'let' command to bind arbitrary values into constants.
Summary: Add new 'let' command to bind arbitrary values into constants. These constants can then be used in the matcher expressions. Reviewers: pcc CC: cfe-commits Differential Revision: http://reviews.llvm.org/D3383 llvm-svn: 206984
This commit is contained in:
parent
5a7c364343
commit
1f6066c9ac
|
@ -54,7 +54,7 @@ struct CollectBoundNodes : MatchFinder::MatchCallback {
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
||||
unsigned MatchCount = 0;
|
||||
|
@ -124,6 +124,15 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
||||
if (Value) {
|
||||
QS.NamedValues[Name] = Value;
|
||||
} else {
|
||||
QS.NamedValues.erase(Name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
const QueryKind SetQueryKind<bool>::value;
|
||||
const QueryKind SetQueryKind<OutputKind>::value;
|
||||
|
|
|
@ -28,9 +28,10 @@ enum QueryKind {
|
|||
QK_Invalid,
|
||||
QK_NoOp,
|
||||
QK_Help,
|
||||
QK_Let,
|
||||
QK_Match,
|
||||
QK_SetBool,
|
||||
QK_SetOutputKind
|
||||
QK_SetOutputKind,
|
||||
};
|
||||
|
||||
class QuerySession;
|
||||
|
@ -86,6 +87,17 @@ struct MatchQuery : Query {
|
|||
static bool classof(const Query *Q) { return Q->Kind == QK_Match; }
|
||||
};
|
||||
|
||||
struct LetQuery : Query {
|
||||
LetQuery(StringRef Name, const ast_matchers::dynamic::VariantValue &Value)
|
||||
: Query(QK_Let), Name(Name), Value(Value) {}
|
||||
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
|
||||
|
||||
std::string Name;
|
||||
ast_matchers::dynamic::VariantValue Value;
|
||||
|
||||
static bool classof(const Query *Q) { return Q->Kind == QK_Let; }
|
||||
};
|
||||
|
||||
template <typename T> struct SetQueryKind {};
|
||||
|
||||
template <> struct SetQueryKind<bool> {
|
||||
|
|
|
@ -132,12 +132,16 @@ QueryRef QueryParser::endQuery(QueryRef Q) {
|
|||
return Q;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum ParsedQueryKind {
|
||||
PQK_Invalid,
|
||||
PQK_NoOp,
|
||||
PQK_Help,
|
||||
PQK_Let,
|
||||
PQK_Match,
|
||||
PQK_Set
|
||||
PQK_Set,
|
||||
PQK_Unlet,
|
||||
};
|
||||
|
||||
enum ParsedQueryVariable {
|
||||
|
@ -146,16 +150,52 @@ enum ParsedQueryVariable {
|
|||
PQV_BindRoot
|
||||
};
|
||||
|
||||
QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
|
||||
std::string ErrStr;
|
||||
llvm::raw_string_ostream OS(ErrStr);
|
||||
Diag.printToStreamFull(OS);
|
||||
return new InvalidQuery(OS.str());
|
||||
}
|
||||
|
||||
class QuerySessionSema : public Parser::RegistrySema {
|
||||
public:
|
||||
QuerySessionSema(const QuerySession &QS) : QS(QS) {}
|
||||
|
||||
ast_matchers::dynamic::VariantValue getNamedValue(StringRef Name) override {
|
||||
return QS.NamedValues.lookup(Name);
|
||||
}
|
||||
|
||||
private:
|
||||
const QuerySession &QS;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
QueryRef QueryParser::completeMatcherExpression() {
|
||||
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
|
||||
StringRef(Begin, End - Begin), CompletionPos - Begin);
|
||||
for (std::vector<MatcherCompletion>::iterator I = Comps.begin(),
|
||||
E = Comps.end();
|
||||
I != E; ++I) {
|
||||
Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
|
||||
}
|
||||
return QueryRef();
|
||||
}
|
||||
|
||||
QueryRef QueryParser::doParse() {
|
||||
StringRef CommandStr;
|
||||
ParsedQueryKind QKind = lexOrCompleteWord<ParsedQueryKind>(CommandStr)
|
||||
.Case("", PQK_NoOp)
|
||||
.Case("help", PQK_Help)
|
||||
.Case("m", PQK_Match, /*IsCompletion=*/false)
|
||||
.Case("let", PQK_Let)
|
||||
.Case("match", PQK_Match)
|
||||
.Case("set", PQK_Set)
|
||||
.Case("unlet", PQK_Unlet)
|
||||
.Default(PQK_Invalid);
|
||||
|
||||
QuerySessionSema S(QS);
|
||||
|
||||
switch (QKind) {
|
||||
case PQK_NoOp:
|
||||
return new NoOpQuery;
|
||||
|
@ -163,29 +203,36 @@ QueryRef QueryParser::doParse() {
|
|||
case PQK_Help:
|
||||
return endQuery(new HelpQuery);
|
||||
|
||||
case PQK_Match: {
|
||||
if (CompletionPos) {
|
||||
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
|
||||
StringRef(Begin, End - Begin), CompletionPos - Begin);
|
||||
for (std::vector<MatcherCompletion>::iterator I = Comps.begin(),
|
||||
E = Comps.end();
|
||||
I != E; ++I) {
|
||||
Completions.push_back(
|
||||
LineEditor::Completion(I->TypedText, I->MatcherDecl));
|
||||
}
|
||||
return QueryRef();
|
||||
} else {
|
||||
Diagnostics Diag;
|
||||
Optional<DynTypedMatcher> Matcher =
|
||||
Parser::parseMatcherExpression(StringRef(Begin, End - Begin), &Diag);
|
||||
if (!Matcher) {
|
||||
std::string ErrStr;
|
||||
llvm::raw_string_ostream OS(ErrStr);
|
||||
Diag.printToStreamFull(OS);
|
||||
return new InvalidQuery(OS.str());
|
||||
}
|
||||
return new MatchQuery(*Matcher);
|
||||
case PQK_Let: {
|
||||
StringRef Name = lexWord();
|
||||
|
||||
if (Name.empty())
|
||||
return new InvalidQuery("expected variable name");
|
||||
|
||||
if (CompletionPos)
|
||||
return completeMatcherExpression();
|
||||
|
||||
Diagnostics Diag;
|
||||
ast_matchers::dynamic::VariantValue Value;
|
||||
if (!Parser::parseExpression(StringRef(Begin, End - Begin), &S, &Value,
|
||||
&Diag)) {
|
||||
return makeInvalidQueryFromDiagnostics(Diag);
|
||||
}
|
||||
|
||||
return new LetQuery(Name, Value);
|
||||
}
|
||||
|
||||
case PQK_Match: {
|
||||
if (CompletionPos)
|
||||
return completeMatcherExpression();
|
||||
|
||||
Diagnostics Diag;
|
||||
Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
|
||||
StringRef(Begin, End - Begin), &S, &Diag);
|
||||
if (!Matcher) {
|
||||
return makeInvalidQueryFromDiagnostics(Diag);
|
||||
}
|
||||
return new MatchQuery(*Matcher);
|
||||
}
|
||||
|
||||
case PQK_Set: {
|
||||
|
@ -214,6 +261,15 @@ QueryRef QueryParser::doParse() {
|
|||
return endQuery(Q);
|
||||
}
|
||||
|
||||
case PQK_Unlet: {
|
||||
StringRef Name = lexWord();
|
||||
|
||||
if (Name.empty())
|
||||
return new InvalidQuery("expected variable name");
|
||||
|
||||
return endQuery(new LetQuery(Name, {}));
|
||||
}
|
||||
|
||||
case PQK_Invalid:
|
||||
return new InvalidQuery("unknown command: " + CommandStr);
|
||||
}
|
||||
|
@ -221,13 +277,13 @@ QueryRef QueryParser::doParse() {
|
|||
llvm_unreachable("Invalid query kind");
|
||||
}
|
||||
|
||||
QueryRef QueryParser::parse(StringRef Line) {
|
||||
return QueryParser(Line).doParse();
|
||||
QueryRef QueryParser::parse(StringRef Line, const QuerySession &QS) {
|
||||
return QueryParser(Line, QS).doParse();
|
||||
}
|
||||
|
||||
std::vector<LineEditor::Completion> QueryParser::complete(StringRef Line,
|
||||
size_t Pos) {
|
||||
QueryParser P(Line);
|
||||
std::vector<LineEditor::Completion>
|
||||
QueryParser::complete(StringRef Line, size_t Pos, const QuerySession &QS) {
|
||||
QueryParser P(Line, QS);
|
||||
P.CompletionPos = Line.data() + Pos;
|
||||
|
||||
P.doParse();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H
|
||||
|
||||
#include "Query.h"
|
||||
#include "QuerySession.h"
|
||||
#include "llvm/LineEditor/LineEditor.h"
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -24,19 +25,20 @@ public:
|
|||
/// Parse \a Line as a query.
|
||||
///
|
||||
/// \return A QueryRef representing the query, which may be an InvalidQuery.
|
||||
static QueryRef parse(StringRef Line);
|
||||
static QueryRef parse(StringRef Line, const QuerySession &QS);
|
||||
|
||||
/// Compute a list of completions for \a Line assuming a cursor at
|
||||
/// \param Pos characters past the start of \a Line, ordered from most
|
||||
/// likely to least likely.
|
||||
///
|
||||
/// \return A vector of completions for \a Line.
|
||||
static std::vector<llvm::LineEditor::Completion> complete(StringRef Line,
|
||||
size_t Pos);
|
||||
static std::vector<llvm::LineEditor::Completion>
|
||||
complete(StringRef Line, size_t Pos, const QuerySession &QS);
|
||||
|
||||
private:
|
||||
QueryParser(StringRef Line)
|
||||
: Begin(Line.data()), End(Line.data() + Line.size()), CompletionPos(0) {}
|
||||
QueryParser(StringRef Line, const QuerySession &QS)
|
||||
: Begin(Line.data()), End(Line.data() + Line.size()), CompletionPos(0),
|
||||
QS(QS) {}
|
||||
|
||||
StringRef lexWord();
|
||||
|
||||
|
@ -45,6 +47,7 @@ private:
|
|||
|
||||
QueryRef parseSetBool(bool QuerySession::*Var);
|
||||
QueryRef parseSetOutputKind();
|
||||
QueryRef completeMatcherExpression();
|
||||
|
||||
QueryRef endQuery(QueryRef Q);
|
||||
|
||||
|
@ -59,6 +62,8 @@ private:
|
|||
|
||||
const char *CompletionPos;
|
||||
std::vector<llvm::LineEditor::Completion> Completions;
|
||||
|
||||
const QuerySession &QS;
|
||||
};
|
||||
|
||||
} // namespace query
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
|
||||
|
||||
#include "Query.h"
|
||||
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -28,6 +30,7 @@ public:
|
|||
llvm::ArrayRef<ASTUnit *> ASTs;
|
||||
OutputKind OutKind;
|
||||
bool BindRoot;
|
||||
llvm::StringMap<ast_matchers::dynamic::VariantValue> NamedValues;
|
||||
};
|
||||
|
||||
} // namespace query
|
||||
|
|
|
@ -95,7 +95,7 @@ int main(int argc, const char **argv) {
|
|||
for (cl::list<std::string>::iterator I = Commands.begin(),
|
||||
E = Commands.end();
|
||||
I != E; ++I) {
|
||||
QueryRef Q = QueryParser::parse(I->c_str());
|
||||
QueryRef Q = QueryParser::parse(I->c_str(), QS);
|
||||
if (!Q->run(llvm::outs(), QS))
|
||||
return 1;
|
||||
}
|
||||
|
@ -112,16 +112,18 @@ int main(int argc, const char **argv) {
|
|||
std::string Line;
|
||||
std::getline(Input, Line);
|
||||
|
||||
QueryRef Q = QueryParser::parse(Line.c_str());
|
||||
QueryRef Q = QueryParser::parse(Line.c_str(), QS);
|
||||
if (!Q->run(llvm::outs(), QS))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LineEditor LE("clang-query");
|
||||
LE.setListCompleter(QueryParser::complete);
|
||||
LE.setListCompleter([&QS](StringRef Line, size_t Pos) {
|
||||
return QueryParser::complete(Line, Pos, QS);
|
||||
});
|
||||
while (llvm::Optional<std::string> Line = LE.readLine()) {
|
||||
QueryRef Q = QueryParser::parse(*Line);
|
||||
QueryRef Q = QueryParser::parse(*Line, QS);
|
||||
Q->run(llvm::outs(), QS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Query.h"
|
||||
#include "QueryParser.h"
|
||||
#include "QuerySession.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
|
||||
|
@ -24,20 +25,22 @@ using namespace clang::ast_matchers::dynamic;
|
|||
using namespace clang::query;
|
||||
using namespace clang::tooling;
|
||||
|
||||
TEST(Query, Basic) {
|
||||
std::unique_ptr<ASTUnit> FooAST(
|
||||
buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}", "foo.cc"));
|
||||
ASSERT_TRUE(FooAST.get());
|
||||
std::unique_ptr<ASTUnit> BarAST(
|
||||
buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}", "bar.cc"));
|
||||
ASSERT_TRUE(BarAST.get());
|
||||
class QueryEngineTest : public ::testing::Test {
|
||||
protected:
|
||||
QueryEngineTest() {}
|
||||
|
||||
ASTUnit *ASTs[] = { FooAST.get(), BarAST.get() };
|
||||
std::unique_ptr<ASTUnit> FooAST{
|
||||
buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}", "foo.cc")};
|
||||
std::unique_ptr<ASTUnit> BarAST{
|
||||
buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}", "bar.cc")};
|
||||
ASTUnit *ASTs[2]{FooAST.get(), BarAST.get()};
|
||||
QuerySession S{ASTs};
|
||||
|
||||
std::string Str;
|
||||
llvm::raw_string_ostream OS(Str);
|
||||
QuerySession S(ASTs);
|
||||
llvm::raw_string_ostream OS{Str};
|
||||
};
|
||||
|
||||
TEST_F(QueryEngineTest, Basic) {
|
||||
DynTypedMatcher FnMatcher = functionDecl();
|
||||
DynTypedMatcher FooMatcher = functionDecl(hasName("foo1"));
|
||||
|
||||
|
@ -108,3 +111,28 @@ TEST(Query, Basic) {
|
|||
|
||||
EXPECT_EQ("Not a valid top-level matcher.\n", OS.str());
|
||||
}
|
||||
|
||||
TEST_F(QueryEngineTest, LetAndMatch) {
|
||||
EXPECT_TRUE(QueryParser::parse("let x \"foo1\"", S)->run(OS, S));
|
||||
EXPECT_EQ("", OS.str());
|
||||
Str.clear();
|
||||
|
||||
EXPECT_TRUE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
|
||||
EXPECT_EQ("", OS.str());
|
||||
Str.clear();
|
||||
|
||||
EXPECT_TRUE(QueryParser::parse("match functionDecl(y)", S)->run(OS, S));
|
||||
EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
|
||||
std::string::npos);
|
||||
EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos);
|
||||
Str.clear();
|
||||
|
||||
EXPECT_TRUE(QueryParser::parse("unlet x", S)->run(OS, S));
|
||||
EXPECT_EQ("", OS.str());
|
||||
Str.clear();
|
||||
|
||||
EXPECT_FALSE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
|
||||
EXPECT_EQ("1:2: Error parsing argument 1 for matcher hasName.\n"
|
||||
"1:10: Value not found: x\n", OS.str());
|
||||
Str.clear();
|
||||
}
|
||||
|
|
|
@ -16,95 +16,139 @@
|
|||
using namespace clang;
|
||||
using namespace clang::query;
|
||||
|
||||
TEST(QueryParser, NoOp) {
|
||||
QueryRef Q = QueryParser::parse("");
|
||||
class QueryParserTest : public ::testing::Test {
|
||||
protected:
|
||||
QueryParserTest() {}
|
||||
QueryRef parse(StringRef Code) { return QueryParser::parse(Code, QS); }
|
||||
|
||||
QuerySession QS{llvm::ArrayRef<ASTUnit*>()};
|
||||
};
|
||||
|
||||
TEST_F(QueryParserTest, NoOp) {
|
||||
QueryRef Q = parse("");
|
||||
EXPECT_TRUE(isa<NoOpQuery>(Q));
|
||||
|
||||
Q = QueryParser::parse("\n");
|
||||
Q = parse("\n");
|
||||
EXPECT_TRUE(isa<NoOpQuery>(Q));
|
||||
}
|
||||
|
||||
TEST(QueryParser, Invalid) {
|
||||
QueryRef Q = QueryParser::parse("foo");
|
||||
TEST_F(QueryParserTest, Invalid) {
|
||||
QueryRef Q = parse("foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("unknown command: foo", cast<InvalidQuery>(Q)->ErrStr);
|
||||
}
|
||||
|
||||
TEST(QueryParser, Help) {
|
||||
QueryRef Q = QueryParser::parse("help");
|
||||
TEST_F(QueryParserTest, Help) {
|
||||
QueryRef Q = parse("help");
|
||||
ASSERT_TRUE(isa<HelpQuery>(Q));
|
||||
|
||||
Q = QueryParser::parse("help me");
|
||||
Q = parse("help me");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);
|
||||
}
|
||||
|
||||
TEST(QueryParser, Set) {
|
||||
QueryRef Q = QueryParser::parse("set");
|
||||
TEST_F(QueryParserTest, Set) {
|
||||
QueryRef Q = parse("set");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = QueryParser::parse("set foo bar");
|
||||
Q = parse("set foo bar");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("unknown variable: 'foo'", cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = QueryParser::parse("set output");
|
||||
Q = parse("set output");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected 'diag', 'print' or 'dump', got ''",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = QueryParser::parse("set bind-root true foo");
|
||||
Q = parse("set bind-root true foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("unexpected extra input: ' foo'", cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = QueryParser::parse("set output foo");
|
||||
Q = parse("set output foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected 'diag', 'print' or 'dump', got 'foo'",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = QueryParser::parse("set output dump");
|
||||
Q = parse("set output dump");
|
||||
ASSERT_TRUE(isa<SetQuery<OutputKind> >(Q));
|
||||
EXPECT_EQ(&QuerySession::OutKind, cast<SetQuery<OutputKind> >(Q)->Var);
|
||||
EXPECT_EQ(OK_Dump, cast<SetQuery<OutputKind> >(Q)->Value);
|
||||
|
||||
Q = QueryParser::parse("set bind-root foo");
|
||||
Q = parse("set bind-root foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected 'true' or 'false', got 'foo'",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = QueryParser::parse("set bind-root true");
|
||||
Q = parse("set bind-root true");
|
||||
ASSERT_TRUE(isa<SetQuery<bool> >(Q));
|
||||
EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var);
|
||||
EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value);
|
||||
}
|
||||
|
||||
TEST(QueryParser, Match) {
|
||||
QueryRef Q = QueryParser::parse("match decl()");
|
||||
TEST_F(QueryParserTest, Match) {
|
||||
QueryRef Q = parse("match decl()");
|
||||
ASSERT_TRUE(isa<MatchQuery>(Q));
|
||||
EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Decl>());
|
||||
|
||||
Q = QueryParser::parse("m stmt()");
|
||||
Q = parse("m stmt()");
|
||||
ASSERT_TRUE(isa<MatchQuery>(Q));
|
||||
EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Stmt>());
|
||||
}
|
||||
|
||||
TEST(QueryParser, Complete) {
|
||||
TEST_F(QueryParserTest, LetUnlet) {
|
||||
QueryRef Q = parse("let foo decl()");
|
||||
ASSERT_TRUE(isa<LetQuery>(Q));
|
||||
EXPECT_EQ("foo", cast<LetQuery>(Q)->Name);
|
||||
EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher());
|
||||
EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>());
|
||||
|
||||
Q = parse("let bar \"str\"");
|
||||
ASSERT_TRUE(isa<LetQuery>(Q));
|
||||
EXPECT_EQ("bar", cast<LetQuery>(Q)->Name);
|
||||
EXPECT_TRUE(cast<LetQuery>(Q)->Value.isString());
|
||||
EXPECT_EQ("str", cast<LetQuery>(Q)->Value.getString());
|
||||
|
||||
Q = parse("let");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = parse("unlet x");
|
||||
ASSERT_TRUE(isa<LetQuery>(Q));
|
||||
EXPECT_EQ("x", cast<LetQuery>(Q)->Name);
|
||||
EXPECT_FALSE(cast<LetQuery>(Q)->Value.hasValue());
|
||||
|
||||
Q = parse("unlet");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = parse("unlet x bad_data");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("unexpected extra input: ' bad_data'",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
}
|
||||
|
||||
TEST_F(QueryParserTest, Complete) {
|
||||
std::vector<llvm::LineEditor::Completion> Comps =
|
||||
QueryParser::complete("", 0);
|
||||
ASSERT_EQ(3u, Comps.size());
|
||||
QueryParser::complete("", 0, QS);
|
||||
ASSERT_EQ(5u, Comps.size());
|
||||
EXPECT_EQ("help ", Comps[0].TypedText);
|
||||
EXPECT_EQ("help", Comps[0].DisplayText);
|
||||
EXPECT_EQ("match ", Comps[1].TypedText);
|
||||
EXPECT_EQ("match", Comps[1].DisplayText);
|
||||
EXPECT_EQ("set ", Comps[2].TypedText);
|
||||
EXPECT_EQ("set", Comps[2].DisplayText);
|
||||
EXPECT_EQ("let ", Comps[1].TypedText);
|
||||
EXPECT_EQ("let", Comps[1].DisplayText);
|
||||
EXPECT_EQ("match ", Comps[2].TypedText);
|
||||
EXPECT_EQ("match", Comps[2].DisplayText);
|
||||
EXPECT_EQ("set ", Comps[3].TypedText);
|
||||
EXPECT_EQ("set", Comps[3].DisplayText);
|
||||
EXPECT_EQ("unlet ", Comps[4].TypedText);
|
||||
EXPECT_EQ("unlet", Comps[4].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("set o", 5);
|
||||
Comps = QueryParser::complete("set o", 5, QS);
|
||||
ASSERT_EQ(1u, Comps.size());
|
||||
EXPECT_EQ("utput ", Comps[0].TypedText);
|
||||
EXPECT_EQ("output", Comps[0].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("match while", 11);
|
||||
Comps = QueryParser::complete("match while", 11, QS);
|
||||
ASSERT_EQ(1u, Comps.size());
|
||||
EXPECT_EQ("Stmt(", Comps[0].TypedText);
|
||||
EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)",
|
||||
|
|
Loading…
Reference in New Issue