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

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

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

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

Ответ 1

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

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

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

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

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

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

Кроме того, можно писать шаблоны и преобразования с использованием языка спецификаций правил DMS, используя поверхностный синтаксис самого С++. Можно было бы закодировать OPs "не бросать исключения nonSTL" как

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

  • Из множества инструментов, которые можно запустить с помощью VL, я выбрал три, которые работают с собственным кодом на С++: 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 (в основном это руководство по стилю Google С++). Cpplint произвел ошибки 104K с нашей кодовой базой, большинство ошибок которой связаны с пробелами (отсутствующими или дополнительными), вкладками, позицией скобки и т.д. Некоторые из них, вероятно, стоит исправить: C-style casts, отсутствующие заголовки.

    /li >
  • Inspirel Vera ++: Это программируемый инструмент для проверки, анализа и преобразования исходного кода на С++. Это похоже на функциональность 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 ++ обнаружил около 90 тыс. Вопросов (для 20 нечетных правил).

Ответ 3

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

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

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

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


Пример 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())
)

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

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

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