Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,18 @@
set(LLVM_LINK_COMPONENTS
lineeditor
support
)
add_clang_library(clangQuery
Query.cpp
QueryParser.cpp
LINK_LIBS
clangAST
clangASTMatchers
clangBasic
clangDynamicASTMatchers
clangFrontend
)
add_subdirectory(tool)

View File

@@ -0,0 +1,146 @@
//===---- Query.cpp - clang-query query -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Query.h"
#include "QuerySession.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang::ast_matchers;
using namespace clang::ast_matchers::dynamic;
namespace clang {
namespace query {
Query::~Query() {}
bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
OS << ErrStr << "\n";
return false;
}
bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
return true;
}
bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
OS << "Available commands:\n\n"
" match MATCHER, m MATCHER "
"Match the loaded ASTs against the given matcher.\n"
" let NAME MATCHER, l NAME MATCHER "
"Give a matcher expression a name, to be used later\n"
" "
"as part of other expressions.\n"
" set bind-root (true|false) "
"Set whether to bind the root matcher to \"root\".\n"
" set output (diag|print|dump) "
"Set whether to print bindings as diagnostics,\n"
" "
"AST pretty prints or AST dumps.\n"
" quit "
"Terminates the query session.\n\n";
return true;
}
bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
QS.Terminate = true;
return true;
}
namespace {
struct CollectBoundNodes : MatchFinder::MatchCallback {
std::vector<BoundNodes> &Bindings;
CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
void run(const MatchFinder::MatchResult &Result) override {
Bindings.push_back(Result.Nodes);
}
};
} // namespace
bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
unsigned MatchCount = 0;
for (auto &AST : QS.ASTs) {
MatchFinder Finder;
std::vector<BoundNodes> Matches;
DynTypedMatcher MaybeBoundMatcher = Matcher;
if (QS.BindRoot) {
llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
if (M)
MaybeBoundMatcher = *M;
}
CollectBoundNodes Collect(Matches);
if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
OS << "Not a valid top-level matcher.\n";
return false;
}
Finder.matchAST(AST->getASTContext());
for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
OS << "\nMatch #" << ++MatchCount << ":\n\n";
for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
++BI) {
switch (QS.OutKind) {
case OK_Diag: {
clang::SourceRange R = BI->second.getSourceRange();
if (R.isValid()) {
TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
&AST->getDiagnostics().getDiagnosticOptions());
TD.emitDiagnostic(
FullSourceLoc(R.getBegin(), AST->getSourceManager()),
DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
CharSourceRange::getTokenRange(R), None);
}
break;
}
case OK_Print: {
OS << "Binding for \"" << BI->first << "\":\n";
BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
OS << "\n";
break;
}
case OK_Dump: {
OS << "Binding for \"" << BI->first << "\":\n";
BI->second.dump(OS, AST->getSourceManager());
OS << "\n";
break;
}
}
}
if (MI->getMap().empty())
OS << "No bindings.\n";
}
}
OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
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;
#endif
} // namespace query
} // namespace clang

View File

@@ -0,0 +1,136 @@
//===--- Query.h - clang-query ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include <string>
namespace clang {
namespace query {
enum OutputKind { OK_Diag, OK_Print, OK_Dump };
enum QueryKind {
QK_Invalid,
QK_NoOp,
QK_Help,
QK_Let,
QK_Match,
QK_SetBool,
QK_SetOutputKind,
QK_Quit
};
class QuerySession;
struct Query : llvm::RefCountedBase<Query> {
Query(QueryKind Kind) : Kind(Kind) {}
virtual ~Query();
/// Perform the query on \p QS and print output to \p OS.
///
/// \return false if an error occurs, otherwise return true.
virtual bool run(llvm::raw_ostream &OS, QuerySession &QS) const = 0;
const QueryKind Kind;
};
typedef llvm::IntrusiveRefCntPtr<Query> QueryRef;
/// Any query which resulted in a parse error. The error message is in ErrStr.
struct InvalidQuery : Query {
InvalidQuery(const Twine &ErrStr) : Query(QK_Invalid), ErrStr(ErrStr.str()) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
std::string ErrStr;
static bool classof(const Query *Q) { return Q->Kind == QK_Invalid; }
};
/// No-op query (i.e. a blank line).
struct NoOpQuery : Query {
NoOpQuery() : Query(QK_NoOp) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
static bool classof(const Query *Q) { return Q->Kind == QK_NoOp; }
};
/// Query for "help".
struct HelpQuery : Query {
HelpQuery() : Query(QK_Help) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
static bool classof(const Query *Q) { return Q->Kind == QK_Help; }
};
/// Query for "quit".
struct QuitQuery : Query {
QuitQuery() : Query(QK_Quit) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
static bool classof(const Query *Q) { return Q->Kind == QK_Quit; }
};
/// Query for "match MATCHER".
struct MatchQuery : Query {
MatchQuery(const ast_matchers::dynamic::DynTypedMatcher &Matcher)
: Query(QK_Match), Matcher(Matcher) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
ast_matchers::dynamic::DynTypedMatcher Matcher;
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> {
static const QueryKind value = QK_SetBool;
};
template <> struct SetQueryKind<OutputKind> {
static const QueryKind value = QK_SetOutputKind;
};
/// Query for "set VAR VALUE".
template <typename T> struct SetQuery : Query {
SetQuery(T QuerySession::*Var, T Value)
: Query(SetQueryKind<T>::value), Var(Var), Value(Value) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override {
QS.*Var = Value;
return true;
}
static bool classof(const Query *Q) {
return Q->Kind == SetQueryKind<T>::value;
}
T QuerySession::*Var;
T Value;
};
} // namespace query
} // namespace clang
#endif

View File

@@ -0,0 +1,278 @@
//===---- QueryParser.cpp - clang-query command parser --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "QueryParser.h"
#include "Query.h"
#include "QuerySession.h"
#include "clang/ASTMatchers/Dynamic/Parser.h"
#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include <set>
using namespace llvm;
using namespace clang::ast_matchers::dynamic;
namespace clang {
namespace query {
// Lex any amount of whitespace followed by a "word" (any sequence of
// non-whitespace characters) from the start of region [Begin,End). If no word
// is found before End, return StringRef(). Begin is adjusted to exclude the
// lexed region.
StringRef QueryParser::lexWord() {
while (true) {
if (Begin == End)
return StringRef(Begin, 0);
if (!isWhitespace(*Begin))
break;
++Begin;
}
const char *WordBegin = Begin;
while (true) {
++Begin;
if (Begin == End || isWhitespace(*Begin))
return StringRef(WordBegin, Begin - WordBegin);
}
}
// This is the StringSwitch-alike used by lexOrCompleteWord below. See that
// function for details.
template <typename T> struct QueryParser::LexOrCompleteWord {
StringSwitch<T> Switch;
QueryParser *P;
StringRef Word;
// Set to the completion point offset in Word, or StringRef::npos if
// completion point not in Word.
size_t WordCompletionPos;
LexOrCompleteWord(QueryParser *P, StringRef Word, size_t WCP)
: Switch(Word), P(P), Word(Word), WordCompletionPos(WCP) {}
template <unsigned N>
LexOrCompleteWord &Case(const char (&S)[N], const T &Value,
bool IsCompletion = true) {
StringRef CaseStr(S, N - 1);
if (WordCompletionPos == StringRef::npos)
Switch.Case(S, Value);
else if (N != 1 && IsCompletion && WordCompletionPos <= CaseStr.size() &&
CaseStr.substr(0, WordCompletionPos) ==
Word.substr(0, WordCompletionPos))
P->Completions.push_back(LineEditor::Completion(
(CaseStr.substr(WordCompletionPos) + " ").str(), CaseStr));
return *this;
}
T Default(const T &Value) const { return Switch.Default(Value); }
};
// Lexes a word and stores it in Word. Returns a LexOrCompleteWord<T> object
// that can be used like a llvm::StringSwitch<T>, but adds cases as possible
// completions if the lexed word contains the completion point.
template <typename T>
QueryParser::LexOrCompleteWord<T>
QueryParser::lexOrCompleteWord(StringRef &Word) {
Word = lexWord();
size_t WordCompletionPos = StringRef::npos;
if (CompletionPos && CompletionPos <= Word.data() + Word.size()) {
if (CompletionPos < Word.data())
WordCompletionPos = 0;
else
WordCompletionPos = CompletionPos - Word.data();
}
return LexOrCompleteWord<T>(this, Word, WordCompletionPos);
}
QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
StringRef ValStr;
unsigned Value = lexOrCompleteWord<unsigned>(ValStr)
.Case("false", 0)
.Case("true", 1)
.Default(~0u);
if (Value == ~0u) {
return new InvalidQuery("expected 'true' or 'false', got '" + ValStr + "'");
}
return new SetQuery<bool>(Var, Value);
}
QueryRef QueryParser::parseSetOutputKind() {
StringRef ValStr;
unsigned OutKind = lexOrCompleteWord<unsigned>(ValStr)
.Case("diag", OK_Diag)
.Case("print", OK_Print)
.Case("dump", OK_Dump)
.Default(~0u);
if (OutKind == ~0u) {
return new InvalidQuery("expected 'diag', 'print' or 'dump', got '" +
ValStr + "'");
}
return new SetQuery<OutputKind>(&QuerySession::OutKind, OutputKind(OutKind));
}
QueryRef QueryParser::endQuery(QueryRef Q) {
const char *Extra = Begin;
if (!lexWord().empty())
return new InvalidQuery("unexpected extra input: '" +
StringRef(Extra, End - Extra) + "'");
return Q;
}
namespace {
enum ParsedQueryKind {
PQK_Invalid,
PQK_NoOp,
PQK_Help,
PQK_Let,
PQK_Match,
PQK_Set,
PQK_Unlet,
PQK_Quit
};
enum ParsedQueryVariable { PQV_Invalid, PQV_Output, PQV_BindRoot };
QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
std::string ErrStr;
llvm::raw_string_ostream OS(ErrStr);
Diag.printToStreamFull(OS);
return new InvalidQuery(OS.str());
}
} // namespace
QueryRef QueryParser::completeMatcherExpression() {
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
StringRef(Begin, End - Begin), CompletionPos - Begin, nullptr,
&QS.NamedValues);
for (auto 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)
.Case("quit", PQK_Quit)
.Default(PQK_Invalid);
switch (QKind) {
case PQK_NoOp:
return new NoOpQuery;
case PQK_Help:
return endQuery(new HelpQuery);
case PQK_Quit:
return endQuery(new QuitQuery);
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), nullptr,
&QS.NamedValues, &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), nullptr, &QS.NamedValues, &Diag);
if (!Matcher) {
return makeInvalidQueryFromDiagnostics(Diag);
}
return new MatchQuery(*Matcher);
}
case PQK_Set: {
StringRef VarStr;
ParsedQueryVariable Var = lexOrCompleteWord<ParsedQueryVariable>(VarStr)
.Case("output", PQV_Output)
.Case("bind-root", PQV_BindRoot)
.Default(PQV_Invalid);
if (VarStr.empty())
return new InvalidQuery("expected variable name");
if (Var == PQV_Invalid)
return new InvalidQuery("unknown variable: '" + VarStr + "'");
QueryRef Q;
switch (Var) {
case PQV_Output:
Q = parseSetOutputKind();
break;
case PQV_BindRoot:
Q = parseSetBool(&QuerySession::BindRoot);
break;
case PQV_Invalid:
llvm_unreachable("Invalid query kind");
}
return endQuery(Q);
}
case PQK_Unlet: {
StringRef Name = lexWord();
if (Name.empty())
return new InvalidQuery("expected variable name");
return endQuery(new LetQuery(Name, VariantValue()));
}
case PQK_Invalid:
return new InvalidQuery("unknown command: " + CommandStr);
}
llvm_unreachable("Invalid query kind");
}
QueryRef QueryParser::parse(StringRef Line, const QuerySession &QS) {
return QueryParser(Line, QS).doParse();
}
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();
return P.Completions;
}
} // namespace query
} // namespace clang

View File

@@ -0,0 +1,71 @@
//===--- QueryParser.h - clang-query ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H
#include "Query.h"
#include "QuerySession.h"
#include "llvm/LineEditor/LineEditor.h"
#include <cstddef>
namespace clang {
namespace query {
class QuerySession;
class QueryParser {
public:
/// Parse \a Line as a query.
///
/// \return A QueryRef representing the query, which may be an InvalidQuery.
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, const QuerySession &QS);
private:
QueryParser(StringRef Line, const QuerySession &QS)
: Begin(Line.begin()), End(Line.end()), CompletionPos(nullptr), QS(QS) {}
StringRef lexWord();
template <typename T> struct LexOrCompleteWord;
template <typename T> LexOrCompleteWord<T> lexOrCompleteWord(StringRef &Str);
QueryRef parseSetBool(bool QuerySession::*Var);
QueryRef parseSetOutputKind();
QueryRef completeMatcherExpression();
QueryRef endQuery(QueryRef Q);
/// \brief Parse [\p Begin,\p End).
///
/// \return A reference to the parsed query object, which may be an
/// \c InvalidQuery if a parse error occurs.
QueryRef doParse();
const char *Begin;
const char *End;
const char *CompletionPos;
std::vector<llvm::LineEditor::Completion> Completions;
const QuerySession &QS;
};
} // namespace query
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H

View File

@@ -0,0 +1,40 @@
//===--- QuerySession.h - clang-query ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
#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 {
class ASTUnit;
namespace query {
/// Represents the state for a particular clang-query session.
class QuerySession {
public:
QuerySession(llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs)
: ASTs(ASTs), OutKind(OK_Diag), BindRoot(true), Terminate(false) {}
llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs;
OutputKind OutKind;
bool BindRoot;
bool Terminate;
llvm::StringMap<ast_matchers::dynamic::VariantValue> NamedValues;
};
} // namespace query
} // namespace clang
#endif

View File

@@ -0,0 +1,15 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_clang_executable(clang-query ClangQuery.cpp)
target_link_libraries(clang-query
PRIVATE
clangAST
clangASTMatchers
clangBasic
clangDynamicASTMatchers
clangFrontend
clangQuery
clangTooling
)
install(TARGETS clang-query RUNTIME DESTINATION bin)

View File

@@ -0,0 +1,116 @@
//===---- ClangQuery.cpp - clang-query tool -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool is for interactive exploration of the Clang AST using AST matchers.
// It currently allows the user to enter a matcher at an interactive prompt and
// view the resulting bindings as diagnostics, AST pretty prints or AST dumps.
// Example session:
//
// $ cat foo.c
// void foo(void) {}
// $ clang-query foo.c --
// clang-query> match functionDecl()
//
// Match #1:
//
// foo.c:1:1: note: "root" binds here
// void foo(void) {}
// ^~~~~~~~~~~~~~~~~
// 1 match.
//
//===----------------------------------------------------------------------===//
#include "Query.h"
#include "QueryParser.h"
#include "QuerySession.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/LineEditor/LineEditor.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Signals.h"
#include <fstream>
#include <string>
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::ast_matchers::dynamic;
using namespace clang::query;
using namespace clang::tooling;
using namespace llvm;
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::OptionCategory ClangQueryCategory("clang-query options");
static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),
cl::value_desc("command"),
cl::cat(ClangQueryCategory));
static cl::list<std::string> CommandFiles("f",
cl::desc("Read commands from file"),
cl::value_desc("file"),
cl::cat(ClangQueryCategory));
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory);
if (!Commands.empty() && !CommandFiles.empty()) {
llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";
return 1;
}
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
std::vector<std::unique_ptr<ASTUnit>> ASTs;
if (Tool.buildASTs(ASTs) != 0)
return 1;
QuerySession QS(ASTs);
if (!Commands.empty()) {
for (auto I = Commands.begin(), E = Commands.end(); I != E; ++I) {
QueryRef Q = QueryParser::parse(*I, QS);
if (!Q->run(llvm::outs(), QS))
return 1;
}
} else if (!CommandFiles.empty()) {
for (auto I = CommandFiles.begin(), E = CommandFiles.end(); I != E; ++I) {
std::ifstream Input(I->c_str());
if (!Input.is_open()) {
llvm::errs() << argv[0] << ": cannot open " << *I << "\n";
return 1;
}
while (Input.good()) {
std::string Line;
std::getline(Input, Line);
QueryRef Q = QueryParser::parse(Line, QS);
if (!Q->run(llvm::outs(), QS))
return 1;
}
}
} else {
LineEditor LE("clang-query");
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, QS);
Q->run(llvm::outs(), QS);
llvm::outs().flush();
if (QS.Terminate)
break;
}
}
return 0;
}