[clang-tools-extra] r194227 - Introduce clang-query tool.
Peter Collingbourne
peter at pcc.me.uk
Thu Nov 7 16:08:23 PST 2013
Author: pcc
Date: Thu Nov 7 18:08:23 2013
New Revision: 194227
URL: http://llvm.org/viewvc/llvm-project?rev=194227&view=rev
Log:
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
Added:
clang-tools-extra/trunk/clang-query/
clang-tools-extra/trunk/clang-query/CMakeLists.txt
clang-tools-extra/trunk/clang-query/Makefile
- copied, changed from r194081, clang-tools-extra/trunk/unittests/Makefile
clang-tools-extra/trunk/clang-query/Query.cpp
clang-tools-extra/trunk/clang-query/Query.h
clang-tools-extra/trunk/clang-query/QueryParser.cpp
clang-tools-extra/trunk/clang-query/QueryParser.h
clang-tools-extra/trunk/clang-query/QuerySession.h
clang-tools-extra/trunk/clang-query/tool/
clang-tools-extra/trunk/clang-query/tool/CMakeLists.txt
clang-tools-extra/trunk/clang-query/tool/ClangQuery.cpp
clang-tools-extra/trunk/test/clang-query/
clang-tools-extra/trunk/test/clang-query/Inputs/
clang-tools-extra/trunk/test/clang-query/Inputs/foo.script
clang-tools-extra/trunk/test/clang-query/errors.c
clang-tools-extra/trunk/test/clang-query/function-decl.c
clang-tools-extra/trunk/unittests/clang-query/
clang-tools-extra/trunk/unittests/clang-query/CMakeLists.txt
clang-tools-extra/trunk/unittests/clang-query/Makefile
clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp
clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp
Modified:
clang-tools-extra/trunk/CMakeLists.txt
clang-tools-extra/trunk/Makefile
clang-tools-extra/trunk/test/CMakeLists.txt
clang-tools-extra/trunk/test/lit.cfg
clang-tools-extra/trunk/test/lit.site.cfg.in
clang-tools-extra/trunk/unittests/CMakeLists.txt
clang-tools-extra/trunk/unittests/Makefile
Modified: clang-tools-extra/trunk/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/CMakeLists.txt?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/CMakeLists.txt Thu Nov 7 18:08:23 2013
@@ -1,5 +1,8 @@
+check_library_exists(edit el_init "" HAVE_LIBEDIT)
+
add_subdirectory(clang-apply-replacements)
add_subdirectory(clang-modernize)
+add_subdirectory(clang-query)
add_subdirectory(clang-tidy)
add_subdirectory(modularize)
add_subdirectory(pp-trace)
Modified: clang-tools-extra/trunk/Makefile
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/Makefile?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/Makefile (original)
+++ clang-tools-extra/trunk/Makefile Thu Nov 7 18:08:23 2013
@@ -12,7 +12,8 @@ CLANG_LEVEL := ../..
include $(CLANG_LEVEL)/../../Makefile.config
PARALLEL_DIRS := remove-cstr-calls tool-template modularize pp-trace
-DIRS := clang-apply-replacements clang-modernize clang-tidy unittests
+DIRS := clang-apply-replacements clang-modernize clang-tidy clang-query \
+ unittests
include $(CLANG_LEVEL)/Makefile
Added: clang-tools-extra/trunk/clang-query/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/CMakeLists.txt?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-query/CMakeLists.txt Thu Nov 7 18:08:23 2013
@@ -0,0 +1,13 @@
+add_clang_library(clangQuery
+ Query.cpp
+ QueryParser.cpp
+ )
+target_link_libraries(clangQuery
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDynamicASTMatchers
+ clangFrontend
+ )
+
+add_subdirectory(tool)
Copied: clang-tools-extra/trunk/clang-query/Makefile (from r194081, clang-tools-extra/trunk/unittests/Makefile)
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/Makefile?p2=clang-tools-extra/trunk/clang-query/Makefile&p1=clang-tools-extra/trunk/unittests/Makefile&r1=194081&r2=194227&rev=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/Makefile (original)
+++ clang-tools-extra/trunk/clang-query/Makefile Thu Nov 7 18:08:23 2013
@@ -1,4 +1,4 @@
-##===- tools/extra/test/Unit/Makefile ----------------------*- Makefile -*-===##
+##===- tools/extra/clang-query/Makefile --------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -8,8 +8,7 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../../..
+LIBRARYNAME := clangQuery
include $(CLANG_LEVEL)/../../Makefile.config
-PARALLEL_DIRS := clang-apply-replacements clang-modernize clang-tidy
-
include $(CLANG_LEVEL)/Makefile
Added: clang-tools-extra/trunk/clang-query/Query.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/Query.cpp?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/Query.cpp (added)
+++ clang-tools-extra/trunk/clang-query/Query.cpp Thu Nov 7 18:08:23 2013
@@ -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
Added: clang-tools-extra/trunk/clang-query/Query.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/Query.h?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/Query.h (added)
+++ clang-tools-extra/trunk/clang-query/Query.h Thu Nov 7 18:08:23 2013
@@ -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
Added: clang-tools-extra/trunk/clang-query/QueryParser.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/QueryParser.cpp?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/QueryParser.cpp (added)
+++ clang-tools-extra/trunk/clang-query/QueryParser.cpp Thu Nov 7 18:08:23 2013
@@ -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
Added: clang-tools-extra/trunk/clang-query/QueryParser.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/QueryParser.h?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/QueryParser.h (added)
+++ clang-tools-extra/trunk/clang-query/QueryParser.h Thu Nov 7 18:08:23 2013
@@ -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
Added: clang-tools-extra/trunk/clang-query/QuerySession.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/QuerySession.h?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/QuerySession.h (added)
+++ clang-tools-extra/trunk/clang-query/QuerySession.h Thu Nov 7 18:08:23 2013
@@ -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
Added: clang-tools-extra/trunk/clang-query/tool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/tool/CMakeLists.txt?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/tool/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/clang-query/tool/CMakeLists.txt Thu Nov 7 18:08:23 2013
@@ -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()
Added: clang-tools-extra/trunk/clang-query/tool/ClangQuery.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/tool/ClangQuery.cpp?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-query/tool/ClangQuery.cpp (added)
+++ clang-tools-extra/trunk/clang-query/tool/ClangQuery.cpp Thu Nov 7 18:08:23 2013
@@ -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;
+}
Modified: clang-tools-extra/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/CMakeLists.txt?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/test/CMakeLists.txt Thu Nov 7 18:08:23 2013
@@ -38,6 +38,10 @@ set(CLANG_TOOLS_TEST_DEPS
ExtraToolsUnitTests
)
+if(HAVE_LIBEDIT)
+ list(APPEND CLANG_TOOLS_TEST_DEPS clang-query)
+endif()
+
add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${CLANG_TOOLS_TEST_DEPS}
Added: clang-tools-extra/trunk/test/clang-query/Inputs/foo.script
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-query/Inputs/foo.script?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-query/Inputs/foo.script (added)
+++ clang-tools-extra/trunk/test/clang-query/Inputs/foo.script Thu Nov 7 18:08:23 2013
@@ -0,0 +1,2 @@
+foo
+bar
Added: clang-tools-extra/trunk/test/clang-query/errors.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-query/errors.c?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-query/errors.c (added)
+++ clang-tools-extra/trunk/test/clang-query/errors.c Thu Nov 7 18:08:23 2013
@@ -0,0 +1,11 @@
+// RUN: not clang-query -c foo -c bar %s -- | FileCheck %s
+// RUN: not clang-query -f %S/Inputs/foo.script %s -- | FileCheck %s
+// RUN: not clang-query -f %S/Inputs/nonexistent.script %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT %s
+// RUN: not clang-query -c foo -f foo %s -- 2>&1 | FileCheck --check-prefix=CHECK-BOTH %s
+// REQUIRES: libedit
+
+// CHECK: unknown command: foo
+// CHECK-NOT: unknown command: bar
+
+// CHECK-NONEXISTENT: cannot open {{.*}}nonexistent.script
+// CHECK-BOTH: cannot specify both -c and -f
Added: clang-tools-extra/trunk/test/clang-query/function-decl.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-query/function-decl.c?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-query/function-decl.c (added)
+++ clang-tools-extra/trunk/test/clang-query/function-decl.c Thu Nov 7 18:08:23 2013
@@ -0,0 +1,5 @@
+// RUN: clang-query -c "match functionDecl()" %s -- | FileCheck %s
+// REQUIRES: libedit
+
+// CHECK: function-decl.c:5:1: note: "root" binds here
+void foo(void) {}
Modified: clang-tools-extra/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/lit.cfg?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/lit.cfg (original)
+++ clang-tools-extra/trunk/test/lit.cfg Thu Nov 7 18:08:23 2013
@@ -229,3 +229,6 @@ if platform.system() not in ['Windows']
# ANSI escape sequences in non-dumb terminal
if platform.system() not in ['Windows']:
config.available_features.add('ansi-escape-sequences')
+
+if config.have_libedit == "1":
+ config.available_features.add('libedit')
Modified: clang-tools-extra/trunk/test/lit.site.cfg.in
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/lit.site.cfg.in?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/lit.site.cfg.in (original)
+++ clang-tools-extra/trunk/test/lit.site.cfg.in Thu Nov 7 18:08:23 2013
@@ -7,6 +7,7 @@ config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
config.clang_tools_binary_dir = "@CLANG_TOOLS_BINARY_DIR@"
config.target_triple = "@TARGET_TRIPLE@"
+config.have_libedit = "@HAVE_LIBEDIT@"
# Support substitution of the tools and libs dirs with user parameters. This is
# used when we can't determine the tool dir at configuration time.
Modified: clang-tools-extra/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/CMakeLists.txt?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/CMakeLists.txt Thu Nov 7 18:08:23 2013
@@ -7,4 +7,5 @@ endfunction()
add_subdirectory(clang-apply-replacements)
add_subdirectory(clang-modernize)
+add_subdirectory(clang-query)
add_subdirectory(clang-tidy)
Modified: clang-tools-extra/trunk/unittests/Makefile
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/Makefile?rev=194227&r1=194226&r2=194227&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/Makefile (original)
+++ clang-tools-extra/trunk/unittests/Makefile Thu Nov 7 18:08:23 2013
@@ -10,6 +10,6 @@
CLANG_LEVEL := ../../..
include $(CLANG_LEVEL)/../../Makefile.config
-PARALLEL_DIRS := clang-apply-replacements clang-modernize clang-tidy
+PARALLEL_DIRS := clang-apply-replacements clang-modernize clang-query clang-tidy
include $(CLANG_LEVEL)/Makefile
Added: clang-tools-extra/trunk/unittests/clang-query/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-query/CMakeLists.txt?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-query/CMakeLists.txt (added)
+++ clang-tools-extra/trunk/unittests/clang-query/CMakeLists.txt Thu Nov 7 18:08:23 2013
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-query
+ )
+
+add_extra_unittest(ClangQueryTests
+ QueryEngineTest.cpp
+ QueryParserTest.cpp
+ )
+
+target_link_libraries(ClangQueryTests
+ clangASTMatchers
+ clangQuery
+ clangTooling
+ )
Added: clang-tools-extra/trunk/unittests/clang-query/Makefile
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-query/Makefile?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-query/Makefile (added)
+++ clang-tools-extra/trunk/unittests/clang-query/Makefile Thu Nov 7 18:08:23 2013
@@ -0,0 +1,24 @@
+##===- unittests/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 = ../../../..
+include $(CLANG_LEVEL)/../../Makefile.config
+
+TESTNAME = ClangQuery
+LINK_COMPONENTS := asmparser bitreader support MC MCParser option \
+ TransformUtils
+USEDLIBS = clangQuery.a clangTooling.a clangFrontend.a clangSerialization.a \
+ clangDriver.a clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
+ clangAST.a clangASTMatchers.a clangDynamicASTMatchers.a clangLex.a \
+ clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
+MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../clang-query
+include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
Added: clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-query/QueryEngineTest.cpp Thu Nov 7 18:08:23 2013
@@ -0,0 +1,110 @@
+//===---- QueryTest.cpp - clang-query test --------------------------------===//
+//
+// 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/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::dynamic;
+using namespace clang::query;
+using namespace clang::tooling;
+
+TEST(Query, Basic) {
+ OwningPtr<ASTUnit> FooAST(
+ buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}", "foo.cc"));
+ ASSERT_TRUE(FooAST.get());
+ OwningPtr<ASTUnit> BarAST(
+ buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}", "bar.cc"));
+ ASSERT_TRUE(BarAST.get());
+
+ ASTUnit *ASTs[] = { FooAST.get(), BarAST.get() };
+
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ QuerySession S(ASTs);
+
+ DynTypedMatcher FnMatcher = functionDecl();
+ DynTypedMatcher FooMatcher = functionDecl(hasName("foo1"));
+
+ EXPECT_TRUE(NoOpQuery().run(OS, S));
+
+ EXPECT_EQ("", OS.str());
+
+ Str.clear();
+
+ EXPECT_FALSE(InvalidQuery("Parse error").run(OS, S));
+
+ EXPECT_EQ("Parse error\n", OS.str());
+
+ Str.clear();
+
+ EXPECT_TRUE(HelpQuery().run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("Available commands:") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(MatchQuery(FnMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("foo.cc:2:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("bar.cc:1:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("bar.cc:2:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("4 matches.") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(MatchQuery(FooMatcher).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(
+ SetQuery<OutputKind>(&QuerySession::OutKind, OK_Print).run(OS, S));
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") !=
+ std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(SetQuery<OutputKind>(&QuerySession::OutKind, OK_Dump).run(OS, S));
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(SetQuery<bool>(&QuerySession::BindRoot, false).run(OS, S));
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("No bindings.") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_FALSE(MatchQuery(isArrow()).run(OS, S));
+
+ EXPECT_EQ("Not a valid top-level matcher.\n", OS.str());
+}
Added: clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp?rev=194227&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-query/QueryParserTest.cpp Thu Nov 7 18:08:23 2013
@@ -0,0 +1,87 @@
+//===---- QueryParserTest.cpp - clang-query test --------------------------===//
+//
+// 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 "gtest/gtest.h"
+
+using namespace clang;
+using namespace clang::query;
+
+TEST(QueryParser, NoOp) {
+ QueryRef Q = ParseQuery("");
+ EXPECT_TRUE(isa<NoOpQuery>(Q));
+
+ Q = ParseQuery("\n");
+ EXPECT_TRUE(isa<NoOpQuery>(Q));
+}
+
+TEST(QueryParser, Invalid) {
+ QueryRef Q = ParseQuery("foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unknown command: foo", cast<InvalidQuery>(Q)->ErrStr);
+}
+
+TEST(QueryParser, Help) {
+ QueryRef Q = ParseQuery("help");
+ ASSERT_TRUE(isa<HelpQuery>(Q));
+
+ Q = ParseQuery("help me");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);
+}
+
+TEST(QueryParser, Set) {
+ QueryRef Q = ParseQuery("set");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = ParseQuery("set foo bar");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unknown variable: 'foo'", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = ParseQuery("set output");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected variable value", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = ParseQuery("set bind-root true foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unexpected extra input: ' foo'", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = ParseQuery("set output foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected 'diag', 'print' or 'dump', got 'foo'",
+ cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = ParseQuery("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 = ParseQuery("set bind-root foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected 'true' or 'false', got 'foo'",
+ cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = ParseQuery("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 = ParseQuery("match decl()");
+ ASSERT_TRUE(isa<MatchQuery>(Q));
+ EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Decl>());
+
+ Q = ParseQuery("m stmt()");
+ ASSERT_TRUE(isa<MatchQuery>(Q));
+ EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Stmt>());
+}
More information about the cfe-commits
mailing list