- PVSM.RU - https://www.pvsm.ru -

Плагин поиска дублирующегося кода для QtCreator

image

Дублирующийся код осложняет внесение изменений, понимание исходных текстов и их дальнейшее сопровождение. Для того, чтобы избежать дублирования, а также для оценки качества кода и его рефакторинга, в составе некоторых IDE есть встроенные средства для поиска повторяющихся фрагментов кода. Для других IDE написаны плагины. Однако для среды разработки QtCreator до настоящего момента ни встроенных средств, ни плагинов поиска повторов не было.
В статье описывается два решения задачи автоматического поиска дубликатов в данной IDE: с помощью средства интеграции сторонних утилит и с помощью разработанного плагина, который надеюсь будет полезен программистам C++, использующим QtCreator.

1 Интеграция сторонней утилиты поиска повторяющегося кода

Механизм интеграции сторонних утилит — мощное средство расширения функционала QtCreator. Процесс настройки подробно описан в руководстве [1]. В качестве инструмента поиска дубликатов была выбрана консольная утилита simian — Similarity Analyzer [2], которая также будет использоваться и в плагине. Для ее интеграции в QtCreator необходимо выполнить следующие шаги:
1. Установка приложения.
Windows:
Для Windows-систем будем использовать exe-приложение (страница загрузки с сайта автора [3]. Распакуем архив с приложением в нужную вам директорию (например D:/Development/Simian).
Unix-based:
Для запуска в Unix-системах (поддерживающих JRE) simian также реализован в виде Java-приложения. Для некоторых Unix-систем simian можно установить из системы пакетов (например для Arch Linux [4]). Если в системе пакетов этого приложения нет, то необходимо скачать архив с приложением по ссылке [3], распаковать в необходимую директорию (например /usr/share/java/simian/), затем в PATH-директории (например /usr/bin) создать файл «simian», содержащий скрипт запуска приложения:

#!/bin/bash
java -jar /usr/share/java/simian/simian.jar $@

В завершение данному файлу необходимо задать права на выполнение.
2. Добавление внешней утилиты (external tool) в QtCreator
На вкладке External Tools раздела настроек Environment добавляем новую категорию и утилиту (Add Category, Add Tool), пример показан на скриншоте ниже.

Плагин поиска дублирующегося кода для QtCreator

В поле Executable указываем путь к исполняемому файлу программы (или в случае с Unix-based системами вписываем «simian»), в поле Arguments указываем аргументы запуска:

-failOnDuplication- -includes=**/*.cpp -includes=**/*.h -includes=*.cpp -includes=*.h

В поле Working Directory указываем шаблон директории текущего проекта:

%{CurrentProject:Path}

С данными настройками утилита будет искать повторы во всех файлах с расширением .cpp и .h в директории проекта и всех поддиректориях.
Теперь в меню External Tools появилась новая вкладка.

Плагин поиска дублирующегося кода для QtCreator

При выборе элемента меню Check запускается утилита simian и ее вывод перенаправляется в панель сообщений, при этом отображается информация о найденных дубликатах (количество, файлы, строки). Если использовать в аргументах запуска опцию

-reportDuplicateText+

, то также будет выводиться дублируемый код. С полным списком опций запуска simian можно ознакомиться по адресу [5].
Но данное решение автоматизировало лишь запуск утилиты. Открывать файлы с повторами и искать нужные строки приходилось «в ручную». А хотелось, чтобы было как в других плагинах и IDE: двойной щелчок по записи открывает файл исходника, выполняется переход на нужную строку и текст повтора подсвечивается. Тогда было принято решение написать плагин.

2 Плагин поиска дублирующегося кода для QtCreator

Опыта разработки плагинов у меня не было и незаменимую помощь оказали статьи TODO Plugin для QtCreator [6] и Система расширений Qt Creator [7]. Код для открытия файла в редакторе и перехода на нужную строчку я нашел именно в исходниках плагина ToDo. Вообще с документацией по написанию плагинов для QtCreator дела обстоят достаточно плохо. Пришлось относительно долго искать решение задачи подсветки текста повтора. Ответ нашел в исходных текстах плагина для оценки степени покрытия тестами Code Coverage [8]. На мой взгляд, в деле написания плагина для QtCreator главное подспорье – это изучение исходников. В галерее плагинов на сайте Qt Project [9] собраны ссылки на большинство плагинов сторонних разработчиков. Непонятные вопросы также можно задать в irc канале #qt-creator на freenode.net. Если у вас появится идея плагина — обязательно попробуйте его реализовать. Написание плагинов — это увлекательное занятие.

2.1 Сборка и установка плагина

2.1.1 Получение исходников и сборка QtCreator

Исходники QtCreator нам понадобятся для сборки как самой IDE, так и плагинов для нее. Также предполагается, что у вас уже установлен Qt, QtCreator и все необходимые системные переменные настроены. Процедура получения исходников и сборки подробно описана в статье Building Qt Creator from git [10]. После успешного выполнения этого этапа у нас будут 2 директории: qt-creator, в которой расположены исходники и qt-creator-build, где находится собранный QtCreator.
Небольшое отступление:
Таким образом у нас теперь будет два QtCreator'a — один из состава установленного дистрибутива Qt (будем называть его «установленный») и один — собранный из исходников (назовем его «собранный»). Сразу оговорюсь, что в дальнейшем плагин мы будем собирать именно для «собранного» creator'а. Дело в том, что если попытаться использовать бинарные файлы плагина, скомпиллированного для более новой версии QtCreator (полученной из исходников), то возникнет ошибка разрешения зависимостей.

Плагин поиска дублирующегося кода для QtCreator

В данном случае плагины Core и ProjectExplorer должны иметь ту же версию, что и QtCreator. Также сдедует обратить внимание на то, что QtCreator из дистрибутива собран с использованием компиллятора Microsoft Visual Studio C++ compiller. Таким образом, чтобы собрать плагин для QtCreator, установленный вместе с Qt необходимо получить исходники QtCreator определенной ревизии (строка FromRevision в окне About), также необходимо наличие версии Qt для MSVC. Я не буду в дальнейшем описывать сборку под QtCreator, собранный компилятором MSVC и предполагаю, что вы соберете (и в дальнейшем будете использовать в работе) самую свежую версию QtCreator из исходников. Если вы займетесь разработкой плагина, то вам тоже понадобится две сборки QtCreator (не обязательно разные как выше, можно и две одинаковых). В одной разрабатывается и собирается плагин а в другую он копируется и тестируется. Хинт: при разработке плагина, когда он соберется в появившемся окне выберите exe файл QtCreatora, в котором тестируется плагин, тогда QtCreator с плагином будет запускаться автоматически.

Плагин поиска дублирующегося кода для QtCreator

Впрочем, давайте вернемся к плагину.

2.1.2 Получение исходников и сборка плагина Simian

Исходники разработанного плагина размещены на Sourceforge.net: QtCreator Similarity Analysis Plugin [11]. Можно скачать архив с исходниками или загрузить их с git-репозитория. После этого открываем проект (simian.pro) в «установленном» QtCreator. В файле проекта simian.pro понадобится изменить две строчки, указывающих путь к директории с исходниками и сборкой QtCreator на вашем компьютере:

## set the QTC_SOURCE environment variable to override the setting here
QTCREATOR_SOURCES = $$(QTC_SOURCE)
isEmpty(QTCREATOR_SOURCES):QTCREATOR_SOURCES=D:/Sources/QtCreator/qt-creator

## set the QTC_BUILD environment variable to override the setting here
IDE_BUILD_TREE = $$(QTC_BUILD)
isEmpty(IDE_BUILD_TREE):IDE_BUILD_TREE=D:/Sources/QtCreator/qt-creator-build

Альтернативный способ: установить системные переменные QTC_SOURCE и QTC_BUILD.

Собираем релизную версию плагина (Ctrl+R), которая после успешного этапа сборки копируется в

D:SourcesQtCreatorqt-creator-buildlibqtcreatorpluginsSnaSoftware

За копирование плагина именно в папку SnaSoftware отвечает следующая строка в файле проекта simian.pro

PROVIDER = SnaSoftware

В данном случае «Provider» имеет значение «поставщик плагина». Если эту строчку закомментировать, то плагины будут копироваться в директорию «QtProject», что на мой взгляд не совсем правильно (в данной директории располагаются плагины, являющиеся частью QtCreator). Поэтому в качестве значения PROVIDER использован мой никнейм на Хабре.
Теперь можно пробовать плагин в деле.

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

2.2.1 Первоначальная настройка и запуск

Перед тем как натравить плагин на папки с вашими проектами в настройках необходимо указать путь к исполняемому файлу утилиты simian.
В Windows для этого необходимо в диалоговом окне настроек (Tools->Options) в появившемся разделе Simian выбрать exe-файл утилиты с помощью диалога выбора файлов (кнопка Browse... в области Simian Executable Path. Вы также можете внести путь к директории с программой simian в системную переменную PATH, тогда в поле Executable можно просто указать имя exe-файла без расширения (например для удобства запуска в консоли я переименовал файл simian-2.3.34.exe в simian.exe, включил путь к программе в переменную PATH и в текстовом поле использую текст simian).
Для Unix-based систем, если вы уже выполнили шаги по установке утилиты simian из раздела 1, вам также понадобится просто вписать наименование исполняемого скрипта «simian» (напомню, что он должен находиться в PATH-директории).
После сохранения настроек (кнопка Ok или Apply) плагин можно использовать. Для этого необходимо открыть существующий или создать новый проект и запустить поиск повторов. Запуск поиска выполняется либо выбором появившегося после установки плагина пункта меню Tools->Find similarities либо нажатием кнопки на вкладке панели Simian. Если не вносить изменений в настройках приложения, то оно запускается с настройками по-умолчанию.
Для проверки работы плагина создадим новый GUI Qt-проект, в заголовочном файле которого объявим 2 функции и в их реализации запишем одинаковый код, состоящий, из 6-ти (так как по-умолчанию значение настройки Threshold равно 6) одинаковых строчек кода, например:

    int one;
    int two;
    int three;
    int four;
    int five;
    int six;
    int seven;

Теперь выберем в меню QtCreator действие Tools->Find similarities (при этом созданный проект должен быть активным). После анализа исходников появится панель вывода результатов работы плагина (Output Panel), в котором будут ссылки на файлы, в которых обнаружены повторы, кликнув по которым данные файлы будут открываться в редакторе, а фрагменты повторов выделаться цветом:

Плагин поиска дублирующегося кода для QtCreator

Плагин позволяет искать не только точные соответствия фрагментов, но и распознавать в фрагметах различного рода вариации. Для этого необходима дополнительная настройка параметров поиска повторяющегося кода.

2.2.2 Расширенная настройка

Настройки поиска дублирующегося кода находятся в группе Simian Behaviour:

Плагин поиска дублирующегося кода для QtCreator

При изменении настроек в диалоговом окне Options и последующем их сохранении в директории текущего проекта создается текстовый файл настроек simian.ini. Если для текущего проекта используются настройки по-умолчанию, то данный файл не создается. Такой подход хоть и добавляет один лишний файл в директорию проекта, но решают проблему переносимости настроек простым копированием (при последующем открытии окна настроек плагин проверяет наличие данного файла и загружает настройки из него, или же загружает настройки по-умолчанию, если данного файла нет).
Плагин позволяет настроить степень строгости поиска. Очень редко копируемый текст в дальнейшем остается неизменным: модифицируются значения строк, цифровых констант, имена переменных. Однако структура кода обычно остается неизменной. Определить оптимальные настройки для конкретного проекта или требований к качеству (допустимой повторяемости) кода можно путем изменения опций, при этом на одном полюсе располагаются настройки с минимальным значением Threshold (2 строки) и всеми включенными опциями (что допускает в при поиске повторов варьирование значений констант, идентификаторов и д.р), а на другом — с максимально приемлемым значением Threshold и отключенными опциями настроек (что соответствует точному синтаксическому совпадению кода для того, чтобы он считался повтором). Используемые опции и их описание представлены в таблице:

Опция Описание
Threshold Сколько строк должно совпасть, чтобы считать фрагмент повтором (от 2 до 99).
Ignore character case Сравнивать символьные константы без учета регистра ('A' равнозначно 'a')
Ignore characters Полностью игнорировать символьные константы ('A' равнозначно 'Z')
Ignore string case Сравнивать строки без учета регистра («foo» равнозначно «FOO»)
Ignore strings Игнорировать содержимое строк («foo» равнозначно «bar»)
Ignore numbers Игнорировать значение числовых констант (1 равнозначно 2.5)
Ignore identifier case Сравнивать имена идентификаторов без учета регистра (int foo; равнозначно int FOO;)
Ignore identifier case Игнорировать имена идентификаторов (int foo; равнозначно int bar;)
Ignore modifiers Игнорировать модификаторы (public, private, static, etc)
Ignore curly braces Игнорировать фигурные скобки
Ignore overlapping blocks Игнорировать перекрывающиеся блоки
Balance square brackets Учитывать квадратные скобки при переносе строк
Balance parentheses Учитывать скобки при переносе строк

Из представленных настроек лично мне не совсем ясными остались: Ignore overlapping blocks, Balance square brackets и Balance parentheses, поэтому я позволю себе оставить их понимание читателем в качестве домашнего задания.

Заключение

В программировании, впрочем как и в любой профессиональной деятельности, необходимо всегда развиваться. При этом, на мой взгляд, стоит не только изучать новые технологии, паттерны проектирования или приемы программирования, но и совершенствовать свои инструмантальные средства. Иногда достаточно взглянуть на свою любимую IDE и сравнить ее с другой (пусть даже предназначенной для другого языка программирования). Подметив для себя новый и интересный функционал, возможно стоит поискать его среди существующих плагинов, а что-то возможно вам захочется реализовать самому. Надеюсь со временем появится хорошая документация по системе плагинов QtCreator и тогда в нашем распоряжении появится еще больше удобных и полезных инструментов. В следующей статье постараюсь сделать обзор наиболее интересных и полезных из существующих плагинов (с которыми познакомился в процессе написания описанного выше плагина).
В планах по развитию плагина:
1. Сборка и тестирование плагина под Unix-based системами. В статье описаны лишь порядок действия для Unix-систем, который «по идее» должен работать, но на практике не проверялся.
2. Расширение функционала интерфейса (кнопки «свернуть-развернуть список», упорядочивание по количеству файлов/строк повторений, задание цвета выделения текста в настройках и др.).
3. Добавление генерации html файла с отчетом по результатам инспекции.
4. Добавление других утилит поиска дублирующегося кода с возможностью выбора используемых.

Все пожелания, замечания и сообщения об ошибках прошу писать либо в системе тикетов [12], либо в разделе форума Feature Request/Bug Report [13].

Автор: snasoft

Источник [14]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/qt-2/55910

Ссылки в тексте:

[1] руководстве: https://qt-project.org/doc/qtcreator-2.6/creator-editor-external.html

[2] simian — Similarity Analyzer: http://www.harukizaemon.com/simian/

[3] страница загрузки с сайта автора: http://www.harukizaemon.com/simian/get_it_now.html

[4] для Arch Linux: https://aur.archlinux.org/packages/simian/

[5] по адресу: http://www.harukizaemon.com/simian/features.html

[6] TODO Plugin для QtCreator: http://habrahabr.ru/post/101311/

[7] Система расширений Qt Creator: http://habrahabr.ru/post/135289/

[8] Code Coverage: https://github.com/3Hren/QtCreatorCoveragePlugin/wiki

[9] галерее плагинов на сайте Qt Project: http://qt-project.org/wiki/Qt_Creator_Plug-in_Gallery

[10] Building Qt Creator from git: http://qt-project.org/wiki/Building-Qt-Creator-from-Git

[11] QtCreator Similarity Analysis Plugin: http://sourceforge.net/projects/simianplugin/

[12] системе тикетов: http://sourceforge.net/p/simianplugin/tickets/

[13] Feature Request/Bug Report: http://sourceforge.net/p/simianplugin/discussion/features-bugs/

[14] Источник: http://habrahabr.ru/post/213785/