Привет, Хабр!

У нашей команды выдалось очень насыщенное лето, результатами которого мы и спешим сегодня поделиться. Итак, встречайте новый релиз CLion 2020.2!

CLion release

Коротко о том, что вошло в новую версию:

  • Поддержка проектной модели Makefile.
  • Последние обновления в CMake.
  • Новые возможности C++20: explicit(bool), назначенные инициализаторы (designated initializers), циклы for на основе диапазонов с инициализаторами.
  • Обновленный статический анализатор кода: анализ на висячие указатели (dangling pointers), поиск возможностей упрощения кода, поиск неиспользуемого кода, анализ возвращаемого значения функции, ограниченной концептом.
  • Юнит-тестирование: поддержка нового фреймворка doctest, новые возможности Catch2 и Google Test. А также упрощение сбора метрик покрытия кода.
  • Обновления в плагине PlatformIO для разработки встроенных систем.
  • Улучшения в поддержке систем контроля версий.
  • Улучшения производительности редактора.
  • Исправления в отладчиках.

Поддержка проектной модели Makefile


Отметив этой весной пятилетие CLion, мы тут же включились в активную доработку самой ожидаемой возможности в IDE — поддержки проектов на основе Makefile. До этого у нас был только сырой прототип, который мы давали попробовать в частном порядке самым смелым нашим пользователям. Благодаря им мы смогли проверить прототип на широкой выборке Makefile-проектов, исправить множество проблем в нем и понять текущие (надеемся, временные) ограничения нашего решения. Наша цель — позволить пользователям работать с проектом на основе Makefile в CLion со всеми умными возможностями IDE, такими как навигация, рефакторинги, статический анализ кода и другие.

Текущий подход вкратце выглядит так: CLion запускает команду make на вашем проекте с дополнительной опцией --just-print, чтобы сэкономить время на реальной сборке. Если CLion может успешно распарсить вывод команды, то проект открывается и все работает!

Сразу оговоримся, работа над поддержкой Makefile в CLion еще далека от завершения — известных ограничений и недоделок еще много. Самое заметное:

  • Не поддерживаются проекты, использующие libtool (CPP-19549), distcc и ccache (CPP-19305), и другие обертки, которые “скрывают” флаги компиляции из выдачи или вмешиваются в вывод команды make.
  • CLion пока не умеет работать с выводом non-GNU Makes (например, NMake, BSD) (CPP-18723).
  • Не поддерживаются проекты, которые отключают вывод имен директорий в процессе сборки, так что CLion не может определить, к каким именно файлам относятся те или иные команды сборки.

Но даже текущее решение уже позволяет открыть в CLion ядро Линукса или код сервера базы данных PostgreSQL. Если интересно, то текущий список проектов, на которых наш прототип работает (а так же некоторые проекты, где он не работает, с указанными проблемами) можно найти на этой странице.

Попробовать на своем проекте очень просто:

  1. Подготовить проект, чтобы получить Makefile для него (например, во многих случаях надо запустить ./configure, так как CLion пока что сам не умеет этого делать).
  2. Открыть проект через File | Open и указать директорию, которая содержит самый главный проектный Makefile или прямо сам этот файл. Подтвердить, что открыть хотите как проект.
  3. CLion уточнит, запустить ли Clean. Это нужно, чтобы вызов команды make подхватил все файлы, а не только последние изменения.
  4. Это, собственно, и все! Результат попытки загрузки проекта будет выведен в окно Build.

posgres load

Вывод может содержать какие-то предупреждения, но если загрузка завершилась в целом успешно (около самой первой задачи должна быть зеленая отметка), то с проектом можно работать в CLion.

Настройки аргументов команды загрузки, тулчейн, используемый для загрузки, и другие опции можно найти в Settings/Preferences | Build, Execution, Deployment | Makefile:

Makefile options

Для запуска и отладки Makefile-приложений потребуется дополнительно создать конфигурации Makefile Application. При этом таргет можно будет выбрать из выпадающего списка — CLion подскажет, какие есть варианты:

Makefile App configuration

В нашем блоге на английском языке можно найти больше информации о работе с проектами на Makefile в CLion. Также рекомендуем к просмотру короткое демо (на английском):


Последние обновления в CMake


Как показывает статистика, три самых популярных сейчас проектных модели среди разработчиков на C++, это CMake, msbuild и Makefile. И именно CMake возглавляет этот рейтинг уже три года и продолжает расти. Поэтому мы непрерывно обновляем забандленную в CLion версию CMake и работаем над поддержкой последних нововведений в самом CMake. В этот раз мы обновили версию до 3.17 и соответственно добавили поддержку двух новых полезных возможностей CMake:

  • С Ninja Multi-Config теперь возможно генерировать все конфигурации (а не только выбранную Debug или Release) при использовании Ninja генератора (включается через -G "Ninja Multi-Config"). CLion правда пока использует только одну конфигурацию, указанную в настройках профиля CMake для проекта. Но это ограничение текущего UI, которое мы планируем исправить в будущем.
  • CMake precompiled headers заслуживают большего внимания. Вообще, идея предкомпилированных заголовочных файлов (PCH) не нова и поддерживается компиляторами уже давно. CLion также умеет работать с PCH довольно давно. Теперь же можно не вспоминать флаги компилятора для PCH и не передавать их в CMake каждому конкретному компилятору по-своему, а просто добавить заголовочные файлы в PCH-переменные таргета через команду target_precompile_headers. CLion 2020.2 теперь умеет с таким работать:

    CMake PCH

Заслуживает внимания и возможность открыть CMake проект в CLion из директории с результатом генерации CMake, теперь не только для генератора Makefile, но и для любого другого! Экономьте время — открывайте уже собранные проекты в CLion без перезапуска команды CMake на проекте.

С++20


А вы знаете, что, по нашим данным, в этом году уже 12% разработчиков на C++ используют стандарт C++20?! Поэтому мы, конечно, работаем активно над поддержкой новых возможностей в CLion. Но давайте сначала вспомним, что у нас вообще с языковым движками в CLion.

Итак, на текущий момент их два — встроенный на основе Java/Kotlin и довольно новый на основе Clangd, соответственно на С++ (для его разработки мы пользуемся CLion). Сейчас все усилия вкладываются в движок на основе Clangd. Он кажется хорошей перспективой, хотя действия на всем проекте (вроде рефакторингов) на нем пока делать нельзя — тут даже не идеальный и местами медленный Java-based движок выигрывает за счет всяких специфических оптимизаций и отложенных резолвов, ну и, конечно, за счет наличия кэша символов, необходимого для рефакторингов.

Но у Clangd есть один очень большой плюс — над поддержкой последних стандартов C++ в Clang там работает все сообщество, ведь проект открытый. Это, конечно, не означает, что нам совсем ничего не надо делать — эту поддержку все равно потом надо адаптировать под нужды CLion. Но это уже проще, чем писать поддержку возможностей C++ с нуля! А еще на основе поддержки в Clang можно писать свой специфический анализ или делать какие-то специальные фичи (так мы, например, сделали автодополнение для Concept-ов несколько релизов назад).

Мы убедились, что последнее обновление Clangd-движка, пришедшее с LLVM, стабильнее ведет себя на коде на C++20, да и в целом по нашей встроенной статистике Clangd-движок стал стабильнее. Поэтому убрали из настроек возможность полностью отключать Clangd-движок. Зато добавили в Settings/Preferences | Languages & Frameworks | C/C++ | Clangd информацию о той ревизии, с которой собран наш движок. Теперь вы знаете, чего ожидать от него в плане поддержки C++ и анализа встроенного Clang-Tidy:

LLVM revision

Кстати, в нашем онлайн-хелпе есть отличная статья со сравнительным анализом двух движков в плане поддержки возможностей C++.

А теперь о том, что же собственно добавилось из поддержки C++20:

  • Автодополнение для ключевых слов C++20: char8_t, consteval и constinit, co_await, co_return, и co_yield.
  • Автодополнение для полей из базового класса в назначенных инициализаторах:

    Designated Init
  • Конструкция explicit(bool) теперь правильно подсвечивается, в ней работают подсказки имен, навигация и рефакторинги:

    Explicit bool
  • Для циклов for на основе диапазонов с инициализаторами заработал рефакторинг Rename для переменных цикла.


Статический анализатор кода


В прошлом релизе мы перевели самый “тяжелый” наш анализ — анализ потока данных (Data Flow Analysis) — на движок на базе Clangd. Это сделано в основном для улучшения производительности. Но, как часто бывает, при рефакторинге было найдено много проблем и неаккуратностей. Так что мы в релизе 2020.2 продолжили улучшать этот анализ и исправлять баги в нем:

  • Заметнее всего, наверное, был улучшен анализ на неиспользуемый код.
  • На DFA также переехали такие вещи как Simplify code и Loop condition is never updated. Для первого в настройках теперь можно настраивать отдельно разные случаи, которые он умеет находить:

    Simplify settings

    К тому же, он теперь более аккуратно работает в случае макросов и шаблонов:

    Simplify

    Второй же анализ позволяет находить потенциально бесконечные циклы из-за того, что условие цикла не обновляется внутри цикла. Знатоки могли бы заметить, что аналогичный анализ есть и в Clang-Tidy (clang-tidy:bugprone-infinite-loop), но там он не работает для циклов с точками выхода и зачастую ложно-срабатывает для лямбд и референсов. В CLion анализ работает в данных случаях аккуратно:

    Loop condition
  • В CLion появился анализ на висячие указатели (dangling pointers)! Несмотря на некоторые ограничения (например, он работает только в локальном скоупе), он все равно очень полезен:

    Dangling pointer
  • Для кода, использующего Concepts из C++20, появился анализ и квик-фикс на добавление концепта к объявлению переменной типа auto, в которую присваивают результат выдачи ограниченной концептом функции:

    Concept constraint for function results

Окно результатов статического анализа


В этом релизе всеми любимый инспектор Гектор (которого некоторые наши пользователи даже тщетно пытались рассмешить) превратился в новый Inspection Widget, расположенный в правом верхнем углу области редактора. Теперь именно там находятся опции настройки уровня подсветки (от показа всех проблем до полного отключения анализатора кода), а при клике открывается окно результатов статического анализа для данного файла:

Inspection Widget and Problems View

Юнит-тестирование


Уже упомянутое здесь не раз исследование показывает, что 34% разработчиков на С++ не пишет никаких юнит-тестов. Хочется верить, что взамен они ведут тестирование какими-то другими способами. Отчасти, проблема в том, что в C++ нет ни стандартной проектной модели, ни стандартного менеджера зависимостей, а значит добавить фреймворк для юнит-тестирования в свой проект ох как не просто. Но сейчас становятся особо популярны так называемые header-only фреймворки, которые подключить в свой проект легко — добавил заголовочный файл и пиши себе тесты. А мы со своей стороны в IDE стараемся поддержать как можно больше опций. В этом релизе к набору из Google Test, Catch, Boost.Test еще добавили doctest. У нас, кстати, некоторое время назад был гостевой блог пост от его автора, где Viktor рассказывал, в чем преимущества данного фреймворка.

Поддержка в CLion включает обычные вещи:

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

doctest configs

Поддержка Google Test и Catch2 также обновилась:

  • Для Catch2 появилась поддержка шаблонных тестов.
  • А для Google Test поддержка макроса GTEST_SKIP(), который может быть очень полезен, если хочется уметь пропускать какие-то тесты, например в специфических окружениях.


Небольшое обзорное видео про улучшения в поддержке юнит тестирования от нашего адвоката (кстати, автора фреймворка Catch/Catch2):


Предупреждая ваши вопросы про CTest: сделать его чуть сложнее, потому что это не “очередной” фреймворк, а некоторый уровень абстракции для запуска чего угодно в виде теста. Но мы планируем некоторую интеграцию уже в 2020.3!

А также


Самое интересно, пожалуй, обсудили, теперь коротко обо всем остальном. Надо было с этого начать, но CLion 2020.2 включает множество небольших, но важных улучшений производительности редактора и исправлений подвисаний редактора. Одно из таких улучшений, например, это вставка обратного слэша при нажатии Enter внутри определения макроса. Казалось бы, как это помогает производительности редактора? Дело в том, что скорее всего новая строка — это часть определения текущего макроса, а вставка обратного слэша позволяет избежать ненужного репарсинга кучи кода, а значит и тормозов редактора.

Помимо этого:

  • Для разработчиков встроенных систем добавилось несколько важных интеграционных изменений в плагине для PlatformIO — генерация большего количества конфигураций запуска и отладки, подсветка в конфигурационных platformio.ini файлах и создание необходимых проекту профилей CMake автоматически.
  • Как обычно, из платформы IntelliJ приехало много улучшений в поддержке систем контроля версий. Из значимого: расширенные возможности по работе с GitHub Pull Requests и поддержка Git на WSL2 (то есть при работе с проектами на WSL2, CLion умеет теперь использовать Git оттуда).
  • По отладчикам в 2020.2 удалось сделать меньше, чем планировали. В основном, все большие задачи отодвинуты на 2020.3 (отладка от имени root-пользователя, отладка core-дампов). Но в этой версии мы проапгрейдили забандленную версию GDB до 9.2, а также обновили GDB STL pretty printers. Множество улучшений, как функциональных, так и по производительности и стабильности, было сделано в нашем отладчике на базе LLDB для тулчейна Microsoft Visual C++.

На этом на сегодня все. Дочитали до конца? Спасибо вам огромное за внимание! Пробуйте, пишите вопросы, предложения, восклицания в комментариях — мы всегда с радостью их читаем и отвечаем!

Команда CLion
The Drive to Develop