summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt30
-rw-r--r--compile_commands.json8
-rw-r--r--main.cc29
-rwxr-xr-xreplace.sh5
-rw-r--r--replaceFunctionCall.cpp164
6 files changed, 237 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..378eac2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..9840a6f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.15)
+# Set the C++ standard for the entire project
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+find_package(Clang REQUIRED)
+include(
+ "/home/aotrix/development/clang_AST/llvm-project/clang/cmake/modules/AddClang.cmake"
+)
+set(LLVM_LINK_COMPONENTS FrontendOpenMP Support)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LLVM_CMAKE_DIR}")
+
+# import LLVM CMake functions
+include(AddLLVM)
+
+add_clang_executable(replace-function-call
+ replaceFunctionCall.cpp
+)
+
+clang_target_link_libraries(replace-function-call
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangTransformer
+ clangFrontend
+ clangTooling
+ clangToolingRefactoring
+)
diff --git a/compile_commands.json b/compile_commands.json
new file mode 100644
index 0000000..4b63725
--- /dev/null
+++ b/compile_commands.json
@@ -0,0 +1,8 @@
+[
+{
+ "directory": "/home/aotrix/development/clang_AST/replaceFunctionCall/build",
+ "command": "/usr/bin/c++ -std=gnu++20 -fno-exceptions -funwind-tables -o CMakeFiles/replace-function-call.dir/replaceFunctionCall.cpp.o -c /home/aotrix/development/clang_AST/replaceFunctionCall/replaceFunctionCall.cpp -I/usr/lib/gcc/x86_64-pc-linux-gnu/16/include",
+ "file": "/home/aotrix/development/clang_AST/replaceFunctionCall/replaceFunctionCall.cpp",
+ "output": "CMakeFiles/replace-function-call.dir/replaceFunctionCall.cpp.o"
+}
+]
diff --git a/main.cc b/main.cc
new file mode 100644
index 0000000..ef15e6e
--- /dev/null
+++ b/main.cc
@@ -0,0 +1,29 @@
+#include <iostream>
+
+bool displayHello()
+{
+ bool result;
+ std::cin >> result;
+ return result;
+}
+
+bool coucouEveryone()
+{
+ bool result;
+ std::cin >> result;
+ return result;
+}
+
+int main()
+{
+ if (displayHello())
+ {
+ coucouEveryone();
+ }
+ if (!displayHello())
+ {
+ std::cout << "Mouhahahaha I am a villain!\n";
+ }
+ int abc;
+ return 0;
+}
diff --git a/replace.sh b/replace.sh
new file mode 100755
index 0000000..a0746ac
--- /dev/null
+++ b/replace.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+echo "Replacing calls..."
+./build/replace-function-call $1
+clang-tidy $1 -checks=-*,readability-simplify-boolean-expr -fix >/dev/null 2>&1
+echo "Done."
diff --git a/replaceFunctionCall.cpp b/replaceFunctionCall.cpp
new file mode 100644
index 0000000..3e0d4cb
--- /dev/null
+++ b/replaceFunctionCall.cpp
@@ -0,0 +1,164 @@
+//===---- tools/extra/ToolTemplate.cpp - Template for refactoring tool ----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an empty refactoring tool using the clang tooling.
+// The goal is to lower the "barrier to entry" for writing refactoring tools.
+//
+// Usage:
+// tool-template <cmake-output-dir> <file1> <file2> ...
+//
+// Where <cmake-output-dir> is a CMake build directory in which a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this output).
+//
+// <file1> ... specify the paths of files in the CMake source tree. This path
+// is looked up in the compile command database. If the path of a file is
+// absolute, it needs to point into CMake's source tree. If the path is
+// relative, the current working directory needs to be in the CMake source
+// tree and the file must be in a subdirectory of the current working
+// directory. "./" prefixes in the relative files will be automatically
+// removed, but the rest of a relative path must be a suffix of a path in
+// the compile command line database.
+//
+// For example, to use tool-template on all files in a subtree of the
+// source tree, use:
+//
+// /path/in/subtree $ find . -name '*.cpp'|
+// xargs tool-template /path/to/build
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/Tooling.h"
+#include "clang/Tooling/Transformer/RewriteRule.h"
+#include "clang/Tooling/Transformer/Stencil.h"
+#include "clang/Tooling/Transformer/Transformer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace llvm;
+using ::clang::Rewriter;
+using ::clang::tooling::Transformer;
+using ::clang::transformer::cat;
+using ::clang::transformer::makeRule;
+using ::clang::transformer::member;
+using ::clang::transformer::name;
+using ::clang::transformer::node;
+
+bool applySourceChanges(const AtomicChanges& Replacements)
+{
+ std::set<std::string> Files;
+ for (const auto& Change : Replacements)
+ Files.insert(Change.getFilePath());
+ // FIXME: Add automatic formatting support as well.
+ tooling::ApplyChangesSpec Spec;
+ // FIXME: We should probably cleanup the result by default as well.
+ Spec.Cleanup = false;
+ for (const auto& File : Files)
+ {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
+ llvm::MemoryBuffer::getFile(File);
+ if (!BufferErr)
+ {
+ llvm::errs() << "error: failed to open " << File << " for rewriting\n";
+ return true;
+ }
+ auto Result =
+ tooling::applyAtomicChanges(File, (*BufferErr)->getBuffer(), Replacements, Spec);
+ if (!Result)
+ {
+ llvm::errs() << toString(Result.takeError());
+ return true;
+ }
+
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::OF_Text);
+ if (EC)
+ {
+ llvm::errs() << EC.message() << "\n";
+ return true;
+ }
+ OS << *Result;
+ continue;
+ }
+ return false;
+}
+
+// Set up the command line options
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::OptionCategory ToolTemplateCategory("tool-template options");
+
+int main(int argc,
+ const char** argv)
+{
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ llvm::Expected<CommonOptionsParser> OptionsParser =
+ CommonOptionsParser::create(argc, argv, ToolTemplateCategory);
+
+ if (!OptionsParser)
+ {
+ llvm::errs() << OptionsParser.takeError();
+ return -1;
+ }
+
+ StandaloneToolExecutor Executor(std::move(OptionsParser.get()));
+
+ std::string ArgId = "arg";
+
+ // auto Rule = makeRule(
+ // callExpr(callee(functionDecl(hasName("AwesomeFunc"))),
+ // hasArgument(0, expr(hasType(pointerType())).bind(ArgId))),
+ // changeTo(node(ArgId), transformer::maybeDeref(ArgId)));
+
+ auto functionToRemove = functionDecl(matchesName("displayHello"));
+ auto Rule = makeRule(callExpr(callee(functionToRemove)), changeTo(cat("true")));
+
+ AtomicChanges AllChanges;
+
+ Transformer TransformerInstance(
+ Rule,
+ [&AllChanges](Expected<llvm::MutableArrayRef<AtomicChange>> Changes)
+ {
+ if (!Changes)
+ {
+ llvm::errs() << Changes.takeError();
+ }
+ AllChanges.insert(AllChanges.end(), std::make_move_iterator(Changes->begin()),
+ std::make_move_iterator(Changes->end()));
+ });
+
+ clang::ast_matchers::MatchFinder MatchFinder;
+ TransformerInstance.registerMatchers(&MatchFinder);
+
+ auto Err = Executor.execute(newFrontendActionFactory(&MatchFinder));
+ if (Err)
+ {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ }
+
+ applySourceChanges(AllChanges);
+}