diff options
| author | Aotrix <[email protected]> | 2026-09-13 20:18:24 +0200 |
|---|---|---|
| committer | Aotrix <[email protected]> | 2026-09-13 20:21:12 +0200 |
| commit | 9340c1d894dc92d86035226370026408968472ac (patch) | |
| tree | 4c774a6cabffcd63e254f280baa5256653e83cd2 | |
First commit
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | CMakeLists.txt | 30 | ||||
| -rw-r--r-- | compile_commands.json | 8 | ||||
| -rw-r--r-- | main.cc | 29 | ||||
| -rwxr-xr-x | replace.sh | 5 | ||||
| -rw-r--r-- | replaceFunctionCall.cpp | 164 |
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" +} +] @@ -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); +} |
