[clang-tools-extra] [NFC][clang] add a clang tool for mlir refactor (PR #75279)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 28 03:13:07 PST 2024
https://github.com/lipracer updated https://github.com/llvm/llvm-project/pull/75279
>From 71ae35b1538201790e5fc7a25d1d7aba7df7913d Mon Sep 17 00:00:00 2001
From: lipracer <lipracer at gmail.com>
Date: Wed, 13 Dec 2023 11:37:12 +0800
Subject: [PATCH] [NFC][clang] add a clang tool for mlir refactor
---
clang-tools-extra/CMakeLists.txt | 1 +
.../mlir-cast-refactor/CMakeLists.txt | 18 ++
.../mlir-cast-refactor/MlirCastRefactor.cpp | 172 ++++++++++++++++++
3 files changed, 191 insertions(+)
create mode 100644 clang-tools-extra/mlir-cast-refactor/CMakeLists.txt
create mode 100644 clang-tools-extra/mlir-cast-refactor/MlirCastRefactor.cpp
diff --git a/clang-tools-extra/CMakeLists.txt b/clang-tools-extra/CMakeLists.txt
index 6a3f741721ee6c..44e4f02dca3326 100644
--- a/clang-tools-extra/CMakeLists.txt
+++ b/clang-tools-extra/CMakeLists.txt
@@ -27,6 +27,7 @@ add_subdirectory(include-cleaner)
add_subdirectory(pp-trace)
add_subdirectory(pseudo)
add_subdirectory(tool-template)
+add_subdirectory(mlir-cast-refactor)
option(CLANG_TOOLS_EXTRA_INCLUDE_DOCS "Generate build targets for the Clang Extra Tools docs."
${LLVM_INCLUDE_DOCS})
diff --git a/clang-tools-extra/mlir-cast-refactor/CMakeLists.txt b/clang-tools-extra/mlir-cast-refactor/CMakeLists.txt
new file mode 100644
index 00000000000000..ebdabf23fc53c3
--- /dev/null
+++ b/clang-tools-extra/mlir-cast-refactor/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_executable(mlirCastRefactor
+ MlirCastRefactor.cpp
+ )
+target_link_libraries(mlirCastRefactor
+ PRIVATE
+ clangAST
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangRewrite
+ clangSerialization
+ clangTooling
+ clangToolingCore
+ clangToolingRefactoring
+ )
\ No newline at end of file
diff --git a/clang-tools-extra/mlir-cast-refactor/MlirCastRefactor.cpp b/clang-tools-extra/mlir-cast-refactor/MlirCastRefactor.cpp
new file mode 100644
index 00000000000000..0ebb48b60940c7
--- /dev/null
+++ b/clang-tools-extra/mlir-cast-refactor/MlirCastRefactor.cpp
@@ -0,0 +1,172 @@
+//===-- MlirCastRefactor.cpp - mlir refactor implementation ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace clang::tooling;
+using namespace llvm;
+
+// Apply a custom category to all command-line options so that they are the
+// only ones displayed.
+static llvm::cl::OptionCategory MyToolCategory("my-tool options");
+static cl::opt<std::string> target_type("target-type",
+ cl::desc("refactoring type name"),
+ cl::value_desc("type name"),
+ cl::ValueRequired, cl::NotHidden,
+ cl::cat(MyToolCategory));
+
+// CommonOptionsParser declares HelpMessage with a description of the common
+// command-line options related to the compilation database and input files.
+// It's nice to have this help message in all tools.
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+
+// A help message for this specific tool can be added afterwards.
+static cl::extrahelp MoreHelp("\nMore help text...\n");
+
+using namespace clang;
+using namespace clang::ast_matchers;
+
+class MemberFunctionCallMatcher : public MatchFinder::MatchCallback {
+public:
+ void run(const MatchFinder::MatchResult &Result) override {
+ if (const CXXMemberCallExpr *MemberCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("memberCall")) {
+ auto objExpr = MemberCall->getImplicitObjectArgument();
+ auto endLoc = MemberCall->getExprLoc();
+
+ auto exprRange = objExpr->getSourceRange();
+
+ SourceLocation StartLoc = objExpr->getBeginLoc();
+
+ const SourceManager &SM = *Result.SourceManager;
+ const char *StartPtr = SM.getCharacterData(StartLoc);
+ const char *EndPtr = SM.getCharacterData(endLoc);
+
+ tooling::AtomicChange change(*Result.SourceManager,
+ MemberCall->getExprLoc());
+ const auto *ME = Result.Nodes.getNodeAs<MemberExpr>("member");
+ size_t dropbackCount = ME->isArrow() ? 2 : 1;
+
+ {
+ auto length = EndPtr - StartPtr;
+ objExprStrings.emplace_back(StartPtr, length);
+ change.replace(*Result.SourceManager, StartLoc, EndPtr - StartPtr, "");
+ }
+
+ {
+ // remove keyword template e.g. obj->template isa<T>
+ auto legalObjStr = StringRef(objExprStrings.back()).rtrim();
+ auto templateLoc = legalObjStr.find("template");
+ if (templateLoc != std::string::npos)
+ legalObjStr = legalObjStr.slice(0, templateLoc);
+
+ // the obj is this when call the member function.
+ if (legalObjStr.empty()) {
+ objExprStrings.back() = "*this";
+ } else {
+ legalObjStr = legalObjStr.drop_back(dropbackCount);
+ objExprStrings.back() =
+ ME->isArrow() ? "*" + legalObjStr.str() : legalObjStr.str();
+ }
+ change.insert(*Result.SourceManager, MemberCall->getRParenLoc(),
+ objExprStrings.back());
+ }
+ changes.push_back(std::move(change));
+ }
+ }
+ SmallVector<tooling::AtomicChange> changes;
+ SmallVector<std::string> objExprStrings;
+};
+
+int main(int argc, const char **argv) {
+ auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory,
+ cl::Optional, nullptr);
+ if (!ExpectedParser) {
+ // Fail gracefully for unsupported options.
+ llvm::errs() << ExpectedParser.takeError();
+ return 1;
+ }
+ CommonOptionsParser &OptionsParser = ExpectedParser.get();
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+
+ MatchFinder Finder;
+
+ auto MemberCallMatcher =
+ cxxMemberCallExpr(
+ callee(memberExpr().bind("member")),
+ callee(cxxMethodDecl(
+ ofClass(hasName(target_type)),
+ hasAnyName("cast", "dyn_cast", "dyn_cast_or_null", "isa"))))
+ .bind("memberCall");
+
+ MemberFunctionCallMatcher memCallExpr;
+ Finder.addMatcher(MemberCallMatcher, &memCallExpr);
+
+ int ExitCode = Tool.run(newFrontendActionFactory(&Finder).get());
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+
+ auto &FileMgr = Tool.getFiles();
+ SourceManager Sources(Diagnostics, FileMgr);
+ Rewriter rewriter(Sources, DefaultLangOptions);
+
+ std::map<std::string, SmallVector<tooling::AtomicChange>> groupChanges;
+ for (auto &change : memCallExpr.changes) {
+ auto filePath = change.getFilePath();
+ groupChanges[filePath].push_back(std::move(change));
+ }
+
+ auto applyOneChange = [](StringRef filePath,
+ ArrayRef<tooling::AtomicChange> changes) {
+ tooling::ApplyChangesSpec Spec;
+ Spec.Cleanup = false;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
+ llvm::MemoryBuffer::getFile(filePath);
+ if (!BufferErr) {
+ llvm::errs() << "error: failed to open " << filePath
+ << " for rewriting\n";
+ return false;
+ }
+ auto Result = tooling::applyAtomicChanges(
+ filePath, (*BufferErr)->getBuffer(), changes, Spec);
+ if (!Result) {
+ llvm::errs() << toString(Result.takeError());
+ return false;
+ }
+
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(filePath, EC, llvm::sys::fs::OF_TextWithCRLF);
+ if (EC) {
+ llvm::errs() << EC.message() << "\n";
+ return false;
+ }
+ OS << *Result;
+ return true;
+ };
+
+ for (auto &change : groupChanges) {
+ if (!applyOneChange(change.first, makeArrayRef(change.second))) {
+ llvm::errs() << "apply file:" << change.first << " fail!";
+ }
+ }
+
+ return ExitCode;
+}
\ No newline at end of file
More information about the cfe-commits
mailing list