Skip to content

Коробейников Арсений. Лабораторная работа 1. Clang AST. Вариант 4. #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: course-spring-2025
Choose a base branch
from
18 changes: 18 additions & 0 deletions clang/compiler-course/korobeinikov_prefix_var/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
set(Title "PrefixVarPlugin")
set(Student "Korobeinikov_Arseny")
set(Group "FIIT1")
set(TARGET_NAME "${Title}_${Student}_${Group}_ClangAST")

file(GLOB_RECURSE SOURCES *.cpp *.h *.hpp)
add_llvm_library(${TARGET_NAME} MODULE ${SOURCES} PLUGIN_TOOL clang)

if(WIN32 OR CYGWIN)
set(LLVM_LINK_COMPONENTS Support)
clang_target_link_libraries(${TARGET_NAME} PRIVATE
clangAST
clangBasic
clangFrontend
)
endif()

set(CLANG_TEST_DEPS "${TARGET_NAME}" ${CLANG_TEST_DEPS} PARENT_SCOPE)
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/raw_ostream.h"
#include <unordered_map>

namespace {
class PrefixVarVisitor : public clang::RecursiveASTVisitor<PrefixVarVisitor> {
public:
PrefixVarVisitor(clang::ASTContext *context, clang::Rewriter &rewriter)
: m_rewriter(rewriter) {}

bool VisitVarDecl(clang::VarDecl *var) {
if (!var || var->getName().empty()) {
return true;
}
std::string prefix;
if (var->isStaticLocal()) {
prefix = "static_";
} else if (var->isLocalVarDecl()) {
prefix = "local_";
} else if (var->hasGlobalStorage()) {
prefix = "global_";
}

if (!prefix.empty()) {
std::string newName = prefix + var->getNameAsString();
renameVar(var, newName);
m_renamedVars[var] = newName;
}
return true;
}

bool VisitParmVarDecl(clang::ParmVarDecl *param) {
if (!param || param->getName().empty()) {
return true;
}
std::string newName = "param_" + param->getNameAsString();
renameVar(param, newName);
m_renamedVars[param] = newName;
return true;
}

bool VisitDeclRefExpr(clang::DeclRefExpr *expr) {
auto *decl = expr->getDecl();
if (!expr || !decl || decl->getName().empty()) {
return true;
}
if (auto *var = clang::dyn_cast<clang::VarDecl>(decl)) {
auto it = m_renamedVars.find(var);
if (it != m_renamedVars.end()) {
m_rewriter.ReplaceText(expr->getLocation(),
var->getNameAsString().size(), it->second);
}
}
return true;
}

private:
clang::Rewriter &m_rewriter;
std::unordered_map<clang::VarDecl *, std::string> m_renamedVars;

void renameVar(clang::VarDecl *var, const std::string &newName) {
m_rewriter.ReplaceText(var->getLocation(), var->getName().size(), newName);
}
};

class PrefixVarConsumer : public clang::ASTConsumer {
public:
PrefixVarConsumer(clang::ASTContext *context, clang::Rewriter &rewriter)
: m_visitor(context, rewriter), m_rewriter(rewriter) {}

void HandleTranslationUnit(clang::ASTContext &context) override {
m_visitor.TraverseDecl(context.getTranslationUnitDecl());
m_rewriter.getEditBuffer(context.getSourceManager().getMainFileID())
.write(llvm::outs());
}

private:
PrefixVarVisitor m_visitor;
clang::Rewriter &m_rewriter;
};

class PrefixVarAction : public clang::PluginASTAction {
public:
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef) override {
if (m_shouldExit) {
return nullptr;
}

m_rewriter.setSourceMgr(ci.getSourceManager(), ci.getLangOpts());
return std::make_unique<PrefixVarConsumer>(&ci.getASTContext(), m_rewriter);
}

bool ParseArgs(const clang::CompilerInstance &ci,
const std::vector<std::string> &args) override {
for (const auto &arg : args) {
if (arg == "--help") {
llvm::outs() << "PrefixVarPlugin_by_Korobeinikov_Arseny:\n"
<< "This plugin changes names by adding prefixes to "
"variables and parameters.\n";
m_shouldExit = true;
return true;
}
}
return true;
}

private:
clang::Rewriter m_rewriter;
bool m_shouldExit = false;
};
} // namespace

static clang::FrontendPluginRegistry::Add<PrefixVarAction>
X("PrefixVarPlugin_Korobeinikov_Arseny_FIIT1_ClangAST",
"Changes names by adding prefixes to variables and parameters");
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clang_cc1 -load %llvmshlibdir/PrefixVarPlugin_Korobeinikov_Arseny_FIIT1_ClangAST%pluginext -plugin PrefixVarPlugin_Korobeinikov_Arseny_FIIT1_ClangAST -fsyntax-only %s 2>&1 | FileCheck --match-full-lines %s

// CHECK: int global_var1 = 0;
// CHECK-NEXT: int foo(int param_a, int param_b) {
// CHECK-NEXT: static int static_var2 = 0;
// CHECK-NEXT: int local_var3 = 123;
// CHECK-NEXT: ++static_var2;
// CHECK-NEXT: return param_a + param_b + global_var1 + static_var2 + local_var3;
// CHECK-NEXT: }
// CHECK-NEXT: int static global_var4 = 0;

int var1 = 0;
int foo(int a, int b) {
static int var2 = 0;
int var3 = 123;
++var2;
return a + b + var1 + var2 + var3;
}
int static var4 = 0;

// RUN: %clang_cc1 -load %llvmshlibdir/PrefixVarPlugin_Korobeinikov_Arseny_FIIT1_ClangAST%pluginext -plugin PrefixVarPlugin_Korobeinikov_Arseny_FIIT1_ClangAST -plugin-arg-PrefixVarPlugin_Korobeinikov_Arseny_FIIT1_ClangAST --help -fsyntax-only %s 2>&1 | FileCheck --match-full-lines %s --check-prefix=CHECK-HELP
// CHECK-HELP: PrefixVarPlugin_by_Korobeinikov_Arseny:
// CHECK-HELP-NEXT: This plugin changes names by adding prefixes to variables and parameters.
Loading