Skip to content

✨🛠️ Утилита для рефакторинга C++ на основе Clang LibTooling. Автоматически исправляет "запахи кода", такие как отсутствующие virtual деструкторы и спецификатор override.

Notifications You must be signed in to change notification settings

nmaks2012/RefactorTool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


C++ Refactoring Tool на базе Clang

Это утилита командной строки, разработанная на основе библиотеки Clang LibTooling. Она предназначена для автоматического анализа и исправления распространенных ошибок и "запахов кода" (code smells) в проектах на C++. Инструмент напрямую модифицирует исходные файлы, внося исправления.

Основные возможности

Утилита автоматически находит и исправляет следующие проблемы в коде:

  1. Невиртуальный деструктор в базовом классе: Если у класса есть наследники, но его деструктор не объявлен как virtual, утилита добавит это ключевое слово. Это помогает избежать неопределенного поведения и утечек памяти при полиморфном удалении объектов.

  2. Отсутствие override у переопределенных методов: Если метод в классе-наследнике переопределяет виртуальный метод из базового класса, но не помечен как override, утилита добавит этот спецификатор. Это повышает читаемость кода и позволяет компилятору выполнять дополнительные проверки.

  3. Избыточное копирование в range-for циклах: Если в range-for цикле используется константная переменная пользовательского типа (не фундаментального) без ссылки (const T obj : ...), утилита добавит ссылку (const T& obj : ...), чтобы избежать дорогостоящих операций копирования.

Среда разработки (Dev Container)

Проект настроен для использования Visual Studio Code Dev Containers. Это рекомендуемый способ работы, так как он предоставляет полностью настроенную и изолированную среду разработки в Docker, что исключает проблемы с зависимостями и различиями между операционными системами.

Среда включает в себя:

  • ОС: Ubuntu 25.04
  • Компиляторы: GCC 15, Clang 20
  • Система сборки: CMake
  • Ключевые зависимости: LLVM 20 и Clang 20 (включая libclang, clang-tools, clangd)
  • Инструменты: gdb, git, perf (linux-tools)
  • Интеграция с VS Code: Автоматически устанавливаются расширения для C++, CMake, clangd и отладки.

Начало работы с Dev Container

  1. Установите необходимое ПО:

  2. Откройте проект:

    • Клонируйте этот репозиторий.
    • Откройте папку с проектом в VS Code.
    • VS Code автоматически обнаружит файлы .devcontainer и в правом нижнем углу появится уведомление с предложением "Reopen in Container". Нажмите на эту кнопку.
  3. Ожидайте сборки:

    • При первом запуске Docker соберет образ контейнера согласно инструкциям из Dockerfile. Это может занять несколько минут.
    • После сборки VS Code подключится к контейнеру, и вы окажетесь внутри полностью готовой к работе среды.

Сборка проекта

Способ 1: Внутри Dev Container (Рекомендуемый)

После того как вы открыли проект в контейнере, все зависимости уже установлены.

  1. Откройте терминал в VS Code (Ctrl+`` ). Вы уже будете находиться внутри контейнера.

  2. Запустите CMake для конфигурации проекта: Путь к Clang/LLVM 20 в контейнере известен, поэтому мы можем явно его указать.

    cmake -B build -DClang_DIR=/usr/lib/llvm-20/lib/cmake/clang
  3. Соберите проект:

    cmake --build build

    Исполняемый файл утилиты будет находиться в build/refactor_tool.

Способ 2: Ручная настройка

Если вы не хотите использовать Dev Container, вам нужно будет установить все зависимости вручную.

  1. Установите зависимости:

    • CMake: версия 3.20 или выше.
    • Компилятор C++: GCC 15+ или Clang 20+.
    • Библиотеки LLVM и Clang: версия 20. Это ключевая зависимость.

    Пример установки для Debian/Ubuntu:

    sudo apt-get update
    sudo apt-get install -y cmake make g++-15
    sudo apt-get install -y llvm-20-dev clang-20 libclang-20-dev
  2. Сконфигурируйте и соберите проект, как описано в шагах 2 и 3 для Dev Container.

Использование

Утилита запускается из командной строки и принимает в качестве аргумента путь к файлу, который нужно проанализировать и исправить.

Синтаксис:

./build/refactor_tool <path-to-source-file> --

Важно: Два дефиса (--) в конце обязательны. Они отделяют аргументы для утилиты от аргументов для компилятора.

Тестирование

Проект включает в себя два вида тестов: модульные тесты и интеграционный скрипт.

1. Модульные тесты (GTest)

Модульные тесты проверяют корректность работы каждого правила рефакторинга в изоляции.

Запуск тестов:

# Убедитесь, что проект собран
cd build
ctest

2. Интеграционные тесты (bash-скрипт)

Скрипт check_refactor.sh запускает утилиту на наборе тестовых файлов (test1.cpp, test2.cpp, test3.cpp) и сравнивает результат с эталонными файлами (test*_ref.cpp).

Запуск скрипта: Находясь в корневой папке проекта, выполните:

# Даем скрипту права на выполнение
cd ..
chmod +x check_refactor.sh
# Запускаем
./check_refactor.sh

Ожидаемый вывод:

===== Результаты тестов =====
Тест tests/tests_data/test1.cpp пройден!
Тест tests/tests_data/test2.cpp пройден!
Тест tests/tests_data/test3.cpp пройден!

Архитектура проекта

Работа утилиты построена на стандартной архитектуре инструментов Clang LibTooling:

FrontendAction -> ASTConsumer -> MatchFinder -> MatchCallback

  1. CodeRefactorAction (ASTFrontendAction): Точка входа. Для каждого обрабатываемого файла она создает ASTConsumer и управляет Rewriter'ом, который отвечает за внесение изменений в код.

  2. ComplexConsumer (ASTConsumer): Регистрирует все правила поиска (матчеры) в MatchFinder и связывает их с обработчиком RefactorHandler.

  3. RefactorHandler (MatchFinder::MatchCallback): Содержит основную логику. Метод run этого класса вызывается каждый раз, когда MatchFinder находит в AST узел, соответствующий одному из правил. Именно здесь происходит анализ узла и применение изменений через Rewriter.

Демонстрация эффективности

Все команды ниже предполагается выполнять внутри настроенной среды (Dev Container).

1. Исправление утечек памяти (AddressSanitizer)

Проблема: В файле leak_example.cpp удаление объекта Derived через указатель на Base приводит к утечке памяти, так как деструктор Base не виртуальный.

cd build/

До рефакторинга:

# Компилируем с ASan
g++ -g -fsanitize=address -o leak_before ../tests/tests_data/leak_example.cpp
./leak_before  # ASan сообщит об утечке 4000 байт

После рефакторинга:

./refactor_tool ../tests/tests_data/leak_example.cpp --
g++ -g -fsanitize=address -o leak_after ../tests/tests_data/leak_example.cpp
./leak_after   # Программа завершается без ошибок

2. Улучшение производительности (perf)

Проблема: В файле perf_example.cpp происходит избыточное копирование тяжелых объектов в цикле range-for.

cd build/

До рефакторинга:

g++ -O2 -g -o perf_before ../tests/tests_data/perf_example.cpp
# perf требует запуска с правами sudo
sudo perf record ./perf_before
sudo perf report # Отчет покажет высокое потребление CPU функциями копирования

После рефакторинга:

./refactor_tool ../tests/tests_data/perf_example.cpp --
g++ -O2 -g -o perf_after ../tests/tests_data/perf_example.cpp
sudo perf record ./perf_after # Программа выполнится значительно быстрее
sudo perf report # Функции копирования исчезнут из топа

About

✨🛠️ Утилита для рефакторинга C++ на основе Clang LibTooling. Автоматически исправляет "запахи кода", такие как отсутствующие virtual деструкторы и спецификатор override.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published