Это утилита командной строки, разработанная на основе библиотеки Clang LibTooling. Она предназначена для автоматического анализа и исправления распространенных ошибок и "запахов кода" (code smells) в проектах на C++. Инструмент напрямую модифицирует исходные файлы, внося исправления.
Утилита автоматически находит и исправляет следующие проблемы в коде:
-
Невиртуальный деструктор в базовом классе: Если у класса есть наследники, но его деструктор не объявлен как
virtual
, утилита добавит это ключевое слово. Это помогает избежать неопределенного поведения и утечек памяти при полиморфном удалении объектов. -
Отсутствие
override
у переопределенных методов: Если метод в классе-наследнике переопределяет виртуальный метод из базового класса, но не помечен какoverride
, утилита добавит этот спецификатор. Это повышает читаемость кода и позволяет компилятору выполнять дополнительные проверки. -
Избыточное копирование в range-for циклах: Если в range-for цикле используется константная переменная пользовательского типа (не фундаментального) без ссылки (
const T obj : ...
), утилита добавит ссылку (const T& obj : ...
), чтобы избежать дорогостоящих операций копирования.
Проект настроен для использования 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 и отладки.
-
Установите необходимое ПО:
- Visual Studio Code
- Docker Desktop
- Расширение Dev Containers для VS Code.
-
Откройте проект:
- Клонируйте этот репозиторий.
- Откройте папку с проектом в VS Code.
- VS Code автоматически обнаружит файлы
.devcontainer
и в правом нижнем углу появится уведомление с предложением "Reopen in Container". Нажмите на эту кнопку.
-
Ожидайте сборки:
- При первом запуске Docker соберет образ контейнера согласно инструкциям из
Dockerfile
. Это может занять несколько минут. - После сборки VS Code подключится к контейнеру, и вы окажетесь внутри полностью готовой к работе среды.
- При первом запуске Docker соберет образ контейнера согласно инструкциям из
После того как вы открыли проект в контейнере, все зависимости уже установлены.
-
Откройте терминал в VS Code (
Ctrl+``
). Вы уже будете находиться внутри контейнера. -
Запустите CMake для конфигурации проекта: Путь к Clang/LLVM 20 в контейнере известен, поэтому мы можем явно его указать.
cmake -B build -DClang_DIR=/usr/lib/llvm-20/lib/cmake/clang
-
Соберите проект:
cmake --build build
Исполняемый файл утилиты будет находиться в
build/refactor_tool
.
Если вы не хотите использовать Dev Container, вам нужно будет установить все зависимости вручную.
-
Установите зависимости:
- 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 и 3 для Dev Container.
Утилита запускается из командной строки и принимает в качестве аргумента путь к файлу, который нужно проанализировать и исправить.
Синтаксис:
./build/refactor_tool <path-to-source-file> --
Важно: Два дефиса (--
) в конце обязательны. Они отделяют аргументы для утилиты от аргументов для компилятора.
Проект включает в себя два вида тестов: модульные тесты и интеграционный скрипт.
Модульные тесты проверяют корректность работы каждого правила рефакторинга в изоляции.
Запуск тестов:
# Убедитесь, что проект собран
cd build
ctest
Скрипт 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
-
CodeRefactorAction
(ASTFrontendAction
): Точка входа. Для каждого обрабатываемого файла она создаетASTConsumer
и управляетRewriter
'ом, который отвечает за внесение изменений в код. -
ComplexConsumer
(ASTConsumer
): Регистрирует все правила поиска (матчеры) вMatchFinder
и связывает их с обработчикомRefactorHandler
. -
RefactorHandler
(MatchFinder::MatchCallback
): Содержит основную логику. Методrun
этого класса вызывается каждый раз, когдаMatchFinder
находит в AST узел, соответствующий одному из правил. Именно здесь происходит анализ узла и применение изменений черезRewriter
.
Все команды ниже предполагается выполнять внутри настроенной среды (Dev Container).
Проблема: В файле 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 # Программа завершается без ошибок
Проблема: В файле 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 # Функции копирования исчезнут из топа