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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to