jbangert updated this revision to Diff 94297.
jbangert added a comment.
Fix command line tool.
https://reviews.llvm.org/D29622
Files:
clang-query/CMakeLists.txt
clang-query/QueryReplace.cpp
clang-query/QueryReplace.h
clang-query/replace-tool/CMakeLists.txt
clang-query/replace-tool/ClangQueryReplace.cpp
test/CMakeLists.txt
test/clang-query/replacement.c
Index: test/clang-query/replacement.c
===================================================================
--- /dev/null
+++ test/clang-query/replacement.c
@@ -0,0 +1,5 @@
+// RUN: cp %s %t.c
+// RUN: clang-query-replace --spec '{Query: "varDecl(hasName(\"version\"), hasInitializer(integerLiteral().bind(\"init\"))).bind(\"decl\")", FromId: "decl", ToTemplate: "string version = \"$$-${init}\""}' %t.c --
+// RUN: FileCheck --match-full-lines %s < %t.c
+int version = 4;
+// CHECK: string version = "$-4";
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -44,6 +44,7 @@
clang-include-fixer
clang-move
clang-query
+ clang-query-replace
clang-rename
clang-reorder-fields
clang-tidy
Index: clang-query/replace-tool/ClangQueryReplace.cpp
===================================================================
--- /dev/null
+++ clang-query/replace-tool/ClangQueryReplace.cpp
@@ -0,0 +1,85 @@
+//===---- ClangQueryReplace.cpp - clang-query-replace tool ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool automatically modifies source files based on AST matchers.
+//
+// A given AST matcher is applied to the source, and a bound node in
+// this matcher is replaced by the result of substituting the text
+// corresponding to other bound nodes into a string template.
+//
+// For example:
+// clang-query-replace --spec <<SPEC foo.c
+// Query: 'varDecl(hasName("version"),
+// hasInitializer(integerLiteral().bind("init")))
+// .bind("decl")',
+// FromId: 'decl',
+// ToTemplate: 'string version = "$$-${init}";' }
+// SPEC
+//
+// If foo.c contains this:
+//
+// int version = 5;
+// void bar() { long version = 9; }
+//
+// it will be replaced with:
+// string version = "$-5";
+// void bar() { string version = "$-9"; }
+// ===---------------------------------------------------------------------===//
+
+#include "QueryReplace.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Signals.h"
+
+#include <fstream>
+#include <string>
+#include <system_error>
+
+using namespace clang;
+using namespace clang::query;
+using namespace llvm;
+
+using std::error_code;
+using clang::tooling::CommonOptionsParser;
+
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::OptionCategory ClangQueryCategory("clang-query-replace options");
+
+static cl::list<std::string> Commands("spec",
+ cl::desc("YAML action specification"),
+ cl::value_desc("spec"),
+ cl::cat(ClangQueryCategory));
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+ CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory);
+ if (Commands.empty()) {
+ llvm::errs() << "Must specify at least one --spec \n";
+ return 1;
+ }
+
+ tooling::RefactoringTool Refactor(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+
+ QueryReplaceTool Tool(Refactor.getReplacements());
+ for (auto &SpecYaml : Commands) {
+
+ llvm::Expected<QueryReplaceSpec> Spec =
+ QueryReplaceSpec::parseFromYAML(SpecYaml);
+ if (llvm::Error Error = Spec.takeError())
+ llvm::report_fatal_error(std::move(Error), false);
+ if (llvm::Error Error = Tool.addOperation(*Spec))
+ llvm::report_fatal_error(std::move(Error), false);
+ }
+
+ return Refactor.runAndSave(tooling::newFrontendActionFactory(&Tool).get());
+}
Index: clang-query/replace-tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-query/replace-tool/CMakeLists.txt
@@ -0,0 +1,14 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-query-replace ClangQueryReplace.cpp)
+target_link_libraries(clang-query-replace
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDynamicASTMatchers
+ clangFrontend
+ clangQuery
+ clangTooling
+ )
+
+install(TARGETS clang-query-replace RUNTIME DESTINATION bin)
\ No newline at end of file
Index: clang-query/QueryReplace.h
===================================================================
--- /dev/null
+++ clang-query/QueryReplace.h
@@ -0,0 +1,58 @@
+//===--- QueryReplace.h - clang-query-replace ----------------------*- 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_QUERYREPLACE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERYREPLACE_H
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/Tooling/RefactoringCallbacks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace query {
+/// \brief Describes an AST query and replace operation.
+struct QueryReplaceSpec {
+ static llvm::Expected<QueryReplaceSpec> parseFromYAML(llvm::StringRef Spec);
+ /// \brief clang-query style matcher expression
+ std::string Query;
+
+ /// \brief The node bound to this identifier will be replaced by the
+ /// result of evaluating the template below.
+ std::string FromId;
+
+ /// \brief Replacement template. ${identifier} will be replaced by the text of
+ /// the node bound to the identifier, and $$ by a literal '$'.
+ std::string ToTemplate;
+};
+
+class QueryReplaceTool {
+public:
+ QueryReplaceTool(
+ std::map<std::string, tooling::Replacements> &FileToReplaces);
+ llvm::Error addOperation(QueryReplaceSpec &spec);
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ struct ReplaceOp {
+ ast_matchers::dynamic::DynTypedMatcher Matcher;
+ std::unique_ptr<tooling::RefactoringCallback> Callback;
+ };
+ std::vector<ReplaceOp> Operations;
+
+ tooling::ASTMatchRefactorer Refactorer;
+};
+} // namespace query
+} // namespace clang
+#endif
Index: clang-query/QueryReplace.cpp
===================================================================
--- /dev/null
+++ clang-query/QueryReplace.cpp
@@ -0,0 +1,88 @@
+//===--- QueryReplace.cpp - clang-query-replace --------------------------*- C++
+//-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "QueryReplace.h"
+#include "QueryParser.h"
+#include "QuerySession.h"
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/RefactoringCallbacks.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using clang::query::QueryReplaceSpec;
+using clang::ast_matchers::MatchFinder;
+using clang::ast_type_traits::DynTypedNode;
+using clang::tooling::ReplaceNodeWithTemplate;
+using llvm::Error;
+using llvm::Expected;
+using llvm::StringError;
+using llvm::StringRef;
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<clang::query::QueryReplaceSpec> {
+ static void mapping(IO &IO, clang::query::QueryReplaceSpec &Op) {
+ IO.mapRequired("Query", Op.Query);
+ IO.mapRequired("FromId", Op.FromId);
+ IO.mapRequired("ToTemplate", Op.ToTemplate);
+ }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace clang {
+namespace query {
+
+Expected<QueryReplaceSpec> QueryReplaceSpec::parseFromYAML(StringRef Spec) {
+ llvm::yaml::Input Input(Spec);
+ QueryReplaceSpec Op;
+ Input >> Op;
+ if (Input.error())
+ return llvm::errorCodeToError(Input.error());
+ return Op;
+}
+
+QueryReplaceTool::QueryReplaceTool(
+ std::map<std::string, tooling::Replacements> &FileToReplaces)
+ : Refactorer(FileToReplaces) {}
+
+Error QueryReplaceTool::addOperation(clang::query::QueryReplaceSpec &Spec) {
+ ast_matchers::dynamic::Diagnostics Diag;
+ // FIXME: Support query sessions (for interactive use).
+ auto Matcher = ast_matchers::dynamic::Parser::parseMatcherExpression(
+ Spec.Query, nullptr, nullptr, &Diag);
+ if (!Matcher) {
+ return llvm::make_error<StringError>(
+ StringRef("Cannot parse Query:") + Diag.toStringFull(),
+ std::make_error_code(std::errc::bad_message));
+ }
+ auto Operation =
+ ReplaceNodeWithTemplate::create(Spec.FromId, Spec.ToTemplate);
+ if (!Operation)
+ return Operation.takeError();
+ Operations.emplace_back(ReplaceOp{Matcher.getValue(), std::move(*Operation)});
+
+ Refactorer.addDynamicMatcher(Operations.back().Matcher,
+ Operations.back().Callback.get());
+ return Error::success();
+}
+
+std::unique_ptr<ASTConsumer> QueryReplaceTool::newASTConsumer() {
+ return Refactorer.newASTConsumer();
+}
+} // namespace query
+} // namespace clang
Index: clang-query/CMakeLists.txt
===================================================================
--- clang-query/CMakeLists.txt
+++ clang-query/CMakeLists.txt
@@ -6,6 +6,9 @@
add_clang_library(clangQuery
Query.cpp
QueryParser.cpp
+ QueryReplace.cpp
+ QueryReplace.h
+
LINK_LIBS
clangAST
@@ -16,3 +19,4 @@
)
add_subdirectory(tool)
+add_subdirectory(replace-tool)
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits