Существуют ли удобные инструменты для автоматической проверки соглашений о кодировании C++ помимо проверки стилей?


Существуют ли хорошие инструменты для автоматической проверки проектов C++ на соответствие соглашениям о кодировании, например:

все брошенные объекты должны быть классами, производными от std:: exception (т. е. throw 42; или throw "runtime error"; будут помечены как ошибки, так же как throw std::string("another runtime error"); или бросание любого другого типа, не производного от std:: exception)

В конце концов я ищу что-то вроде Cppcheck, но с более простым способом добавления новых проверок, чем взлом исходного кода инструмента проверки... Может быть даже что-то с симпатичным небольшим графическим интерфейсом, который позволяет вам настраивать правила, записывать их на диск и использовать набор правил в IDE, такой как Eclipse или сервер непрерывной интеграции, такой как Jenkins.

3 11

3 ответа:

Ключевая проблема "шашек стиля" заключается в том, что стиль подобен искусству: у каждого есть свое мнение о том, что является хорошим стилем, а что нет. Подразумевается, что шашки стиля всегда нужно будет подгонять под местные художественные вкусы.

Чтобы сделать это правильно, нужен полный синтаксический анализатор C++ с доступом к определениям символов, правилам области видимости и, в идеале, различным видам анализа потока. Насколько мне известно, cppcheck, на наш взгляд, не обеспечивает точный анализ или условные обозначения в таблице, поэтому его ошибки проверка не может быть одновременно глубокой и правильной. Я думаю, что Coverity и Fortify предлагают что-то в этом роде, используя переднюю часть EDG; я не знаю, предоставляют ли их инструменты доступ к таблицам символов или анализу потоков данных. Лязг приближается.

Вам также нужен способ написания проверок стиля. Я думаю, что все инструменты предоставляют доступ к AST и, возможно, к таблицам символов, и вы можете передать код своим собственным чекам, ценой глубокого знания AST, что трудно для такого большого языка, как C++. Я подумайте, что Coverity и Fortify имеют некоторую DSL-подобную схему для определения некоторых проверок.

Если вы хотите исправить код, который неверен по стилю, вам нужно что-то, что может изменить представление кода. Скрытность и укрепление не предлагают этого АФАИКА. Я считаю, что Clang действительно предлагает возможность модифицировать AST и регенерировать код; вы все еще должны иметь довольно глубокие знания структуры AST, чтобы закодировать логику взлома дерева и получить ее правильно.

Наше программное обеспечение DMS Инструментарий реинжиниринга и компилятор обеспечивают большую часть этих возможностей. Используя свой интерфейс C++, DMS может анализировать ANSI C++11, GCC4 (с расширениями C++11) и MSVS 2010 (с расширениями C++11), строить AST и таблицы символов с полной информацией о типе. Можно также задать тип произвольного выражения AST node. В настоящее время DMS вычисляет поток управления, но не поток данных для C++.

API AST позволяет процедурно кодировать произвольные проверки или вносить изменения в AST для устранения проблем, а затем prettyprinter DMS может регенерировать полный, компилируемый исходный текст с комментариями и сохраненной литеральной информацией о формате (например., радикс чисел и т. д.). Вы должны знать структуру AST, чтобы сделать это, так же, как и другие инструменты, но это намного проще знать, потому что она изоморфна правилам грамматики DMS C++. Этот компилятор входит в наши c++ грамматики. [DMS использует Парсеры GLR, чтобы сделать это возможным].

Кроме того, можно писать шаблоны и преобразования с использованием языка спецификации правил DMS, используя поверхностный синтаксис самого C++. Можно было бы кодировать OPs "dont throw nonstl exceptions" как

 pattern nonSTLexception(i: IDENTIFIER):statement
   = " throw \i; " if ~derived_from_STD_exception(i);

Материал внутри (мета)кавычек - это исходный код C++ с некоторыми совпадающими с шаблоном эскейпами, например, "\i "относится к заполнителю varible "i", который должен быть идентификатором C++ в соответствии с правилом; все предложение" throw \i; "должно быть" оператором " C++ (нетерминальным в грамматике C++). Само правило в основном выражает синтаксис, чтобы может вызывать семантические проверки (такие как "~is_derived_from_STD_exception"), применяемые к соответствующим поддеревьям (в данном случае к любому "\i").

При написании таких шаблонов вам не нужно знать форму АСТ; шаблон знает ее, и она автоматически соответствует. Если вы когда-либо кодировали AST walkers, вы оцените, насколько это удобно.

Совпадение знает узел AST и, следовательно, точное положение (файл / строка / столбец), которое позволяет легко генерировать отчеты с точной информацией о местоположении.

Вам нужно добавить в DMS пользовательскую подпрограмму "inherits_from_STD_exception", чтобы проверить, что узел дерева идентификаторов, переданный этой подпрограмме, является (по желанию OP) классом, производным от std:: исключение. Для этого необходимо найти "std:: exception" в таблице символов, и проверка того, что запись таблицы символов для узла дерева идентификаторов является классом объявление и транзитивно наследует от других объявлений класса (следуя ссылкам таблицы символов) до тех пор, пока std:: найдена запись в таблице символов исключений.

Правило преобразования DMS-это пара паттернов, в сущности заявляющих: "если вы видитеэто , то замените его нато ".

Мы построили несколько пользовательских шашек стилей с DMS как для COBOL, так и для C++. Это все еще довольно много работы, в основном потому, что C++ - довольно сложный язык, и вы должны тщательно подумать о точном значении вашего чека.

Более сложные проверки и те тесты, которые начинают попадать в глубокий статический анализ требует доступа к информации о контроле и потоке данных. Теперь DMS вычисляет поток управления для C++, и мы работаем над анализом потока данных (мы уже сделали это для Java, IBM Enterprise COBOL и различных диалектов C). Результаты анализа привязываются обратно к узлам AST, так что можно использовать шаблоны для поиска элементов проверки стиля, а затем следовать потокам данных, чтобы связать элементы вместе, если это необходимо.

Когда все сказано и сделано с DMS, (или действительно с любым из других инструментов, которые имеют дело с C++ каким-либо наполовину точным способом), заключается в том, что кодирование дополнительных или сложных проверок стиля вряд ли будет "удобным". Вы должны надеяться на " возможно с хорошей технической подготовкой."

Я запустил ряд инструментов статического анализа в своем текущем проекте, и вот некоторые из ключевых выводов:

  • Я использовал Visual Lint в качестве единой точки входа для запуска всех этих инструментов. VL-это плагин для VS для запуска сторонних инструментов статического анализа и позволяет одним щелчком мыши проложить маршрут от отчета к исходному коду. Помимо поддержки графического интерфейса для выбора между различными уровнями ошибок, о которых сообщается, он также обеспечивает автоматический фоновый анализ (что говорит вам сколько ошибок было исправлено по ходу работы), ручной анализ для одного файла, цветные дисплеи ошибок и средства построения графиков. Установщик VL довольно изящен и чрезвычайно полезен, когда вы пытаетесь добавить новые инструменты статического анализа (он даже помогает вам загрузить Python из ActiveState, если вы хотите использовать Google cpplint и не имеете предустановленного Python!). Вы можете узнать больше о VL здесь: http://www.riverblade.co.uk/products/visual_lint/features.html

  • Из из множества инструментов, которые можно запустить с VL, я выбрал три, которые работают с собственным кодом C++: cppcheck, Google cpplint и Inspirel Vera++. Эти инструменты обладают различными возможностями.

  • Cppcheck: это, вероятно, самый распространенный, и мы все его использовали. Так что я замалчиваю детали. Достаточно сказать, что он ловит ошибки, такие как использование постфиксного инкремента для непримитивных типов, предупреждает об использовании функции size (), когда следует использовать пустую функцию (), Уменьшение области видимости переменных, неправильное имя квалификация членов в определении класса, неправильный порядок инициализации членов класса, пропущенные инициализации, неиспользуемые переменные и т. д. Для нашей кодовой базы cppcheck сообщил об ошибках 6K. Было несколько ложных срабатываний (например, неиспользуемая функция), но они были подавлены. Вы можете узнать больше о cppcheck здесь: http://cppcheck.sourceforge.net/manual.pdf

  • Google cpplint : это инструмент на основе python, который проверяет ваш источник на предмет нарушения стиля. Руководство по стилю, по которому выполняется эта проверка, можно найти здесь: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml (это в основном руководство по стилю C++ от Google). Cpplint произвел ~ 104K ошибок с нашей кодовой базой, из которых большинство ошибок связаны с пробелами (отсутствующими или дополнительными), вкладками, положением скобок и т. д. Некоторые из них, вероятно, стоит исправить: приведения в стиле C, отсутствующие заголовки.

  • Inspirel Vera++: это программируемый инструмент для верификация, анализ и преобразование исходного кода C++. Это похоже на cpplint по функциональности. Список доступных правил можно найти здесь: http://www.inspirel.com/vera/ce/doc/rules/index.html и аналогичный список доступных преобразований можно найти здесь: http://www.inspirel.com/vera/ce/doc/transformations/index.html подробнее о том, как добавить свое собственное правило, можно найти здесь: http://www.inspirel.com/vera/ce/doc/tclapi.html . для нашего проекта, Вера++ нашла около 90 тысяч вопросов (для 20 нечетных правил).

Впредстоящем состоянии: Мануэль Климек из Google интегрирует в основную линию Clang инструмент, который был разработан в Google для запроса и преобразования кода C++.

  • Инфраструктура оснастки уже выстроена, она может пополниться, но уже функционирует. Основная идея заключается в том, что он позволяет вам определять действия и запускать эти действия над выбранными файлами.

  • Google создал простой набор классов и методов C++, чтобы позволить запрос AST в дружественной форме: AST Matcher framework, он разрабатывается и позволит очень точное соответствие в конце концов.

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


Пример сопоставления (, найденного в этом потоке ): цель состоит в том, чтобы найти вызовы перегрузки конструктора std::string формируется из результата std::string::c_str() (с распределителем по умолчанию), поскольку его можно заменить простой копией.

ConstructorCall(
    HasDeclaration(Method(HasName(StringConstructor))),
    ArgumentCountIs(2),
    // The first argument must have the form x.c_str() or p->c_str()
    // where the method is string::c_str(). We can use the copy
    // constructor of string instead (or the compiler might share
    // the string object).
    HasArgument(
        0,
        Id("call", Call(
            Callee(Id("member", MemberExpression())),
            Callee(Method(HasName(StringCStrMethod))),
            On(Id("arg", Expression()))
        ))
    ),
    // The second argument is the alloc object which must not be
    // present explicitly.
    HasArgument(1, DefaultArgument())
)

Это очень перспективный инструмент по сравнению с Ad-hoc, потому что он использует библиотеку Clang compiler AST, поэтому не только гарантируется, что независимо от сложности используемых макросов и шаблонов, пока ваш код компилируется, он может быть проанализирован; но это также означает, что сложные запросы, зависящие от результата разрешения перегрузки, могут быть обработаны. выраженный.

Этот код возвращает фактические узлы AST из библиотеки Clang, поэтому программист может точно найти биты и nits в исходном файле и отредактировать его в соответствии со своими потребностями.

Были разговоры об использовании спецификации текстового соответствия, однако было сочтено, что лучше начать с API C++, поскольку это добавило бы много сложности (и байк-линяния). Я надеюсь, что появится API Python.