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

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

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

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

3 ответов


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

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

Если вы хотите исправить код, который является неправильным стилем, вам нужно что-то, что может изменить представление кода. Coverity и Fortify не предлагают этот AFAIK. Я считаю, что Clang предлагает возможность изменять AST и регенерировать код; вы все равно должны иметь довольно глубокие знания о структуре AST, чтобы закодировать логику взлома дерева и получить ее право.

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

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

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

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

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

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

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

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

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

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

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

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


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

  • Я Визуальный Линт как единая точка входа для запуска всех этих инструментов. VL-это плагин для VS для запуска сторонних инструментов статического анализа и позволяет одним щелчком мыши маршрутизировать из отчета в исходный код. Помимо поддержки GUI для выбора между различными уровнями ошибок, он также обеспечивает автоматизированный фон анализ (который говорит вам, сколько ошибок было исправлено, как вы идете), ручной анализ для одного файла, цветные дисплеи ошибок и средство построения графиков. Установщик 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: это, вероятно, самый распространенный, и мы все его использовали. Так что я замалчиваю детали. Достаточно сказать, что он ловит ошибки, такие как использование postfix приращение для непримитивных типов предупреждает об использовании size() при использовании empty (), уменьшении области переменных, неправильной квалификации имен членов в определении класса, неправильном порядке инициализации членов класса, отсутствующих инициализациях, неиспользуемых переменных и т. д. Для нашей кодовой базы cppcheck сообщил об ошибках 6K. Было несколько ложных срабатываний (например, неиспользуемая функция), но они были подавлены. Вы можете узнать больше о cppcheck здесь: http://cppcheck.sourceforge.net/manual.pdf

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

  • Inspirel Вера++: это программируемый инструмент для проверки, анализа и преобразования исходного кода на языке 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. Для нашего проекта Vera++ найдено около 90K проблем (для 20 нечетных правил).


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

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

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

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


пример Матчера (найти в этой теме): цель это найти вызовы перегрузки конструктора 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 AST, поэтому не только гарантируется, что независимо от того, насколько сложны используемые макросы и шаблоны, пока ваш код компилируется, он может быть проанализирован; но это также означает, что усложняет запросы, которые в зависимости от результата перегрузки разрешение может быть выражено.

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

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