summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-query
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2013-11-08 00:08:23 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2013-11-08 00:08:23 +0000
commit8b1265b353b027d90252f1a23c5c3121ee70f3a1 (patch)
tree4d104d38960d01338209c32d106c9b6a764976e7 /clang-tools-extra/clang-query
parent640830142100ea828ba54b42c68ccc4b3dd1d8ea (diff)
downloadbcm5719-llvm-8b1265b353b027d90252f1a23c5c3121ee70f3a1.tar.gz
bcm5719-llvm-8b1265b353b027d90252f1a23c5c3121ee70f3a1.zip
Introduce clang-query tool.
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. Differential Revision: http://llvm-reviews.chandlerc.com/D2098 llvm-svn: 194227
Diffstat (limited to 'clang-tools-extra/clang-query')
-rw-r--r--clang-tools-extra/clang-query/CMakeLists.txt13
-rw-r--r--clang-tools-extra/clang-query/Makefile14
-rw-r--r--clang-tools-extra/clang-query/Query.cpp131
-rw-r--r--clang-tools-extra/clang-query/Query.h119
-rw-r--r--clang-tools-extra/clang-query/QueryParser.cpp165
-rw-r--r--clang-tools-extra/clang-query/QueryParser.h27
-rw-r--r--clang-tools-extra/clang-query/QuerySession.h36
-rw-r--r--clang-tools-extra/clang-query/tool/CMakeLists.txt11
-rw-r--r--clang-tools-extra/clang-query/tool/ClangQuery.cpp158
9 files changed, 674 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-query/CMakeLists.txt b/clang-tools-extra/clang-query/CMakeLists.txt
new file mode 100644
index 00000000000..92332599075
--- /dev/null
+++ b/clang-tools-extra/clang-query/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_clang_library(clangQuery
+ Query.cpp
+ QueryParser.cpp
+ )
+target_link_libraries(clangQuery
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDynamicASTMatchers
+ clangFrontend
+ )
+
+add_subdirectory(tool)
diff --git a/clang-tools-extra/clang-query/Makefile b/clang-tools-extra/clang-query/Makefile
new file mode 100644
index 00000000000..4d73966511f
--- /dev/null
+++ b/clang-tools-extra/clang-query/Makefile
@@ -0,0 +1,14 @@
+##===- tools/extra/clang-query/Makefile --------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangQuery
+include $(CLANG_LEVEL)/../../Makefile.config
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp
new file mode 100644
index 00000000000..5a46f6f9c17
--- /dev/null
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -0,0 +1,131 @@
+//===---- 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"
+ " 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\n";
+ return true;
+}
+
+namespace {
+
+struct CollectBoundNodes : MatchFinder::MatchCallback {
+ std::vector<BoundNodes> &Bindings;
+ CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
+ void run(const MatchFinder::MatchResult &Result) {
+ Bindings.push_back(Result.Nodes);
+ }
+};
+
+}
+
+bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ unsigned MatchCount = 0;
+
+ for (llvm::ArrayRef<ASTUnit *>::iterator I = QS.ASTs.begin(),
+ E = QS.ASTs.end();
+ I != E; ++I) {
+ ASTUnit *AST = *I;
+ 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 (std::vector<BoundNodes>::iterator MI = Matches.begin(),
+ ME = Matches.end();
+ MI != ME; ++MI) {
+ OS << "\nMatch #" << ++MatchCount << ":\n\n";
+
+ for (BoundNodes::IDToNodeMap::const_iterator 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(
+ R.getBegin(), DiagnosticsEngine::Note,
+ "\"" + BI->first + "\" binds here",
+ ArrayRef<CharSourceRange>(CharSourceRange::getTokenRange(R)),
+ ArrayRef<FixItHint>(), &AST->getSourceManager());
+ }
+ 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;
+}
+
+const QueryKind SetQueryKind<bool>::value;
+const QueryKind SetQueryKind<OutputKind>::value;
+
+} // namespace query
+} // namespace clang
diff --git a/clang-tools-extra/clang-query/Query.h b/clang-tools-extra/clang-query/Query.h
new file mode 100644
index 00000000000..4c8941723b5
--- /dev/null
+++ b/clang-tools-extra/clang-query/Query.h
@@ -0,0 +1,119 @@
+//===--- 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 <string>
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+namespace query {
+
+enum OutputKind {
+ OK_Diag,
+ OK_Print,
+ OK_Dump
+};
+
+enum QueryKind {
+ QK_Invalid,
+ QK_NoOp,
+ QK_Help,
+ QK_Match,
+ QK_SetBool,
+ QK_SetOutputKind
+};
+
+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 LLVM_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 LLVM_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 LLVM_OVERRIDE;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Help; }
+};
+
+/// 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 LLVM_OVERRIDE;
+
+ ast_matchers::dynamic::DynTypedMatcher Matcher;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Match; }
+};
+
+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 LLVM_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
diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp
new file mode 100644
index 00000000000..1e4493e609e
--- /dev/null
+++ b/clang-tools-extra/clang-query/QueryParser.cpp
@@ -0,0 +1,165 @@
+//===---- 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 "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/Basic/CharInfo.h"
+
+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.
+static StringRef LexWord(const char *&Begin, const char *End) {
+ while (true) {
+ if (Begin == End)
+ return StringRef();
+
+ if (!isWhitespace(*Begin))
+ break;
+
+ ++Begin;
+ }
+
+ const char *WordBegin = Begin;
+
+ while (true) {
+ ++Begin;
+
+ if (Begin == End || isWhitespace(*Begin))
+ return StringRef(WordBegin, Begin - WordBegin);
+ }
+}
+
+static QueryRef ParseSetBool(bool QuerySession::*Var, StringRef ValStr) {
+ unsigned Value = StringSwitch<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);
+}
+
+static QueryRef ParseSetOutputKind(StringRef ValStr) {
+ unsigned OutKind = StringSwitch<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));
+}
+
+static QueryRef EndQuery(const char *Begin, const char *End, QueryRef Q) {
+ const char *Extra = Begin;
+ if (!LexWord(Begin, End).empty())
+ return new InvalidQuery("unexpected extra input: '" +
+ StringRef(Extra, End - Extra) + "'");
+ return Q;
+}
+
+enum ParsedQueryKind {
+ PQK_Invalid,
+ PQK_NoOp,
+ PQK_Help,
+ PQK_Match,
+ PQK_Set
+};
+
+enum ParsedQueryVariable {
+ PQV_Invalid,
+ PQV_Output,
+ PQV_BindRoot
+};
+
+QueryRef ParseQuery(StringRef Line) {
+ const char *Begin = Line.data();
+ const char *End = Line.data() + Line.size();
+
+ StringRef CommandStr = LexWord(Begin, End);
+ ParsedQueryKind QKind = StringSwitch<ParsedQueryKind>(CommandStr)
+ .Case("", PQK_NoOp)
+ .Case("help", PQK_Help)
+ .Case("m", PQK_Match)
+ .Case("match", PQK_Match)
+ .Case("set", PQK_Set)
+ .Default(PQK_Invalid);
+
+ switch (QKind) {
+ case PQK_NoOp:
+ return new NoOpQuery;
+
+ case PQK_Help:
+ return EndQuery(Begin, End, new HelpQuery);
+
+ case PQK_Match: {
+ 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_Set: {
+ StringRef VarStr = LexWord(Begin, End);
+ if (VarStr.empty())
+ return new InvalidQuery("expected variable name");
+
+ ParsedQueryVariable Var = StringSwitch<ParsedQueryVariable>(VarStr)
+ .Case("output", PQV_Output)
+ .Case("bind-root", PQV_BindRoot)
+ .Default(PQV_Invalid);
+ if (Var == PQV_Invalid)
+ return new InvalidQuery("unknown variable: '" + VarStr + "'");
+
+ StringRef ValStr = LexWord(Begin, End);
+ if (ValStr.empty())
+ return new InvalidQuery("expected variable value");
+
+ QueryRef Q;
+ switch (Var) {
+ case PQV_Output:
+ Q = ParseSetOutputKind(ValStr);
+ break;
+ case PQV_BindRoot:
+ Q = ParseSetBool(&QuerySession::BindRoot, ValStr);
+ break;
+ case PQV_Invalid:
+ llvm_unreachable("Invalid query kind");
+ }
+
+ return EndQuery(Begin, End, Q);
+ }
+
+ case PQK_Invalid:
+ return new InvalidQuery("unknown command: " + CommandStr);
+ }
+}
+
+} // namespace query
+} // namespace clang
diff --git a/clang-tools-extra/clang-query/QueryParser.h b/clang-tools-extra/clang-query/QueryParser.h
new file mode 100644
index 00000000000..00c95fcf2c8
--- /dev/null
+++ b/clang-tools-extra/clang-query/QueryParser.h
@@ -0,0 +1,27 @@
+//===--- 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"
+
+namespace clang {
+namespace query {
+
+/// \brief Parse \p Line.
+///
+/// \return A reference to the parsed query object, which may be an
+/// \c InvalidQuery if a parse error occurs.
+QueryRef ParseQuery(StringRef Line);
+
+} // namespace query
+} // namespace clang
+
+#endif
diff --git a/clang-tools-extra/clang-query/QuerySession.h b/clang-tools-extra/clang-query/QuerySession.h
new file mode 100644
index 00000000000..002b2b56db5
--- /dev/null
+++ b/clang-tools-extra/clang-query/QuerySession.h
@@ -0,0 +1,36 @@
+//===--- 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 "llvm/ADT/ArrayRef.h"
+#include "Query.h"
+
+namespace clang {
+
+class ASTUnit;
+
+namespace query {
+
+/// Represents the state for a particular clang-query session.
+class QuerySession {
+public:
+ QuerySession(llvm::ArrayRef<ASTUnit *> ASTs)
+ : ASTs(ASTs), OutKind(OK_Diag), BindRoot(true) {}
+
+ llvm::ArrayRef<ASTUnit *> ASTs;
+ OutputKind OutKind;
+ bool BindRoot;
+};
+
+} // namespace query
+} // namespace clang
+
+#endif
diff --git a/clang-tools-extra/clang-query/tool/CMakeLists.txt b/clang-tools-extra/clang-query/tool/CMakeLists.txt
new file mode 100644
index 00000000000..f54c4e67341
--- /dev/null
+++ b/clang-tools-extra/clang-query/tool/CMakeLists.txt
@@ -0,0 +1,11 @@
+if(HAVE_LIBEDIT)
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+ add_clang_executable(clang-query ClangQuery.cpp)
+ target_link_libraries(clang-query
+ edit
+ clangFrontend
+ clangQuery
+ clangTooling
+ )
+endif()
diff --git a/clang-tools-extra/clang-query/tool/ClangQuery.cpp b/clang-tools-extra/clang-query/tool/ClangQuery.cpp
new file mode 100644
index 00000000000..d8b411b43bd
--- /dev/null
+++ b/clang-tools-extra/clang-query/tool/ClangQuery.cpp
@@ -0,0 +1,158 @@
+//===---- 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 "QuerySession.h"
+#include "QueryParser.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include <fstream>
+#include <string>
+
+#include <histedit.h>
+
+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::opt<std::string> BuildPath("b", cl::desc("Specify build path"),
+ cl::value_desc("<path>"));
+
+static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),
+ cl::value_desc("<command>"));
+
+static cl::list<std::string> CommandFiles("f",
+ cl::desc("Read commands from file"),
+ cl::value_desc("<file>"));
+
+static cl::list<std::string> SourcePaths(cl::Positional,
+ cl::desc("<source0> [... <sourceN>]"),
+ cl::OneOrMore);
+
+static char *ReturnPrompt(EditLine *EL) {
+ static char Prompt[] = "clang-query> ";
+ return Prompt;
+}
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ cl::ParseCommandLineOptions(argc, argv);
+
+ if (!Commands.empty() && !CommandFiles.empty()) {
+ llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";
+ return 1;
+ }
+
+ llvm::OwningPtr<CompilationDatabase> Compilations(
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+ if (!Compilations) { // Couldn't find a compilation DB from the command line
+ std::string ErrorMessage;
+ Compilations.reset(
+ !BuildPath.empty() ?
+ CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
+ CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage)
+ );
+
+ // Still no compilation DB? - bail.
+ if (!Compilations)
+ llvm::report_fatal_error(ErrorMessage);
+ }
+
+ ClangTool Tool(*Compilations, SourcePaths);
+ std::vector<ASTUnit *> ASTs;
+ if (Tool.buildASTs(ASTs) != 0)
+ return 1;
+
+ QuerySession QS(ASTs);
+
+ if (!Commands.empty()) {
+ for (cl::list<std::string>::iterator I = Commands.begin(),
+ E = Commands.end();
+ I != E; ++I) {
+ QueryRef Q = ParseQuery(I->c_str());
+ if (!Q->run(llvm::outs(), QS))
+ return 1;
+ }
+ } else if (!CommandFiles.empty()) {
+ for (cl::list<std::string>::iterator 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 = ParseQuery(Line.c_str());
+ if (!Q->run(llvm::outs(), QS))
+ return 1;
+ }
+ }
+ } else {
+ History *Hist = history_init();
+ HistEvent Event;
+ history(Hist, &Event, H_SETSIZE, 100);
+
+ EditLine *EL = el_init("clang-query", stdin, stdout, stderr);
+ el_set(EL, EL_PROMPT, ReturnPrompt);
+ el_set(EL, EL_EDITOR, "emacs");
+ el_set(EL, EL_HIST, history, Hist);
+
+ int Count;
+ while (const char *Line = el_gets(EL, &Count)) {
+ if (Count == 0)
+ break;
+
+ history(Hist, &Event, H_ENTER, Line);
+
+ QueryRef Q = ParseQuery(Line);
+ Q->run(llvm::outs(), QS);
+ }
+
+ history_end(Hist);
+ el_end(EL);
+
+ llvm::outs() << "\n";
+ }
+
+ llvm::DeleteContainerPointers(ASTs);
+
+ return 0;
+}
OpenPOWER on IntegriCloud