LINUX.ORG.RU

IWYU 0.21

 , iwyu


1

3

Вышел релиз IWYU (или include-what-you-use), программы позволяющей находить избыточные и предлагать недостающие #include в вашем коде на C/C++.

«Включать то, что используешь» означает следующее: для каждого символа (типа, переменной, функции или макроса), используемого в foo.cc, либо foo.cc, либо foo.h должны подключать .h-файл, экспортирующий объявление этого символа. Инструмент include-what-you-use – это программа для анализа #include исходных файлов с целью поиска нарушений этого подхода и выдачи рекомендаций для исправления. Программа использует библиотеки Clang и обычно релиз означает совместимость с новой версией Clang.

Основная цель include-what-you-use - удаление лишних #include. Для этого необходимо выяснить, какие #include не нужны в данном файле (как для .cc, так и для .h), и по возможности заменить #include на предварительное объявление.

Основные изменения

  • Совместимость с Clang 17.
  • Улучшен анализ псевдонимов типов (typedef и using).
  • Улучшен анализ псевдонимов пространств имен (namespace xyz = foobar).
  • Улучшена поддержка развернутых предварительных деклараций (typedef struct Foo Bar;).
  • Улучшить обработку «автокаста» и возвращаемых типов функций, особенно при работе со сложными шаблонными типами.
  • Добавлена новая прагма IWYU: always_keep, позволяющая пометить заголовок, что он всегда должен сохраняться, где бы он ни был включен.
  • Автоматическое использование сопоставлений для builtins libc++, если libc++ является активной стандартной библиотекой.
  • Улучшение сопоставлений для заголовков libc++ и posix.

>>> Подробности



Проверено: hobbit ()

позволяющей находить избыточные и предлагать недостающие

Меня, честно говоря, интересует, как реализовано «предлагать недостающие». Поскольку в C и C++ это проблема. Код с явно отсутствующим #include может собраться в одном окружении и «гавкнуться» в другом.

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от hobbit

«Недостающие» – это те, которые подключаются неявно, но тем не менее некоторые символы из них используются. Например в Qt многие заголовочники неявно тянут за собой qobject.h.

NickNotNick
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

Если файл компилируется, значит все что нужно уже подключено. Задача программы – показать что подключено неявно.

Вот пример выхлопа утилиты для пары chamferdialog.h и chamferdialog.cpp:

../../addons/src/chamfer/chamferdialog.h should add these lines:
#include <QString>             // for QString
class QSettings;
class QWidget;

../../addons/src/chamfer/chamferdialog.h should remove these lines:
- #include <QSettings>  // lines 27-27
- #include <QWidget>  // lines 28-28

The full include-list for ../../addons/src/chamfer/chamferdialog.h:
#include <QDialog>             // for QDialog
#include <QObject>             // for slots, Q_OBJECT
#include <QPointer>            // for QPointer
#include <QString>             // for QString
#include "ui_chamferdialog.h"  // for ChamferDialog
class QSettings;
class QWidget;
struct ChamferOptions;  // lines 32-32
---

../../addons/src/chamfer/chamferdialog.cpp should add these lines:
#include <QCheckBox>         // for QCheckBox
#include <QLineEdit>         // for QLineEdit
#include <QPushButton>       // for QPushButton
#include <QVariant>          // for QVariant
#include <Qt>                // for WA_DeleteOnClose, red
class QWidget;

../../addons/src/chamfer/chamferdialog.cpp should remove these lines:
- #include <QDoubleValidator>  // lines 27-27

The full include-list for ../../addons/src/chamfer/chamferdialog.cpp:
#include "chamferdialog.h"
#include <QCheckBox>         // for QCheckBox
#include <QLineEdit>         // for QLineEdit
#include <QLocale>           // for QLocale
#include <QPalette>          // for QPalette
#include <QPoint>            // for QPoint
#include <QPushButton>       // for QPushButton
#include <QRect>             // for QRect
#include <QSettings>         // for QSettings
#include <QSize>             // for QSize
#include <QString>           // for QString
#include <QValidator>        // for QDoubleValidator
#include <QVariant>          // for QVariant
#include <Qt>                // for WA_DeleteOnClose, red
#include <cmath>             // for tan, M_PI, atan
#include "chamferoptions.h"  // for ChamferOptions, ChamferOptions::InOut
class QWidget;

При этом все собирается без ошибок.

NickNotNick
() автор топика

Думаю полезная для больших проектов где вручную слишком долго это всё.

и по возможности заменить #include на предварительное объявление.

Что это значит?

firkax ★★★★★
()
Ответ на: комментарий от NickNotNick

Спасиба, ну думаю полезно, просто прогонять дабы почистить код там или типа того.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от firkax

В заголовочниках заменить #include <QWidget> на class QWidget;, если это возможно.

NickNotNick
() автор топика
Ответ на: комментарий от vbr

Я навскидку нашел только одну похожую проверку misc-include-cleaner. Эта проверка действует только для файла с исходником, в то время как IWYU анализирует и предлагает улучшения и для соответствующего заголовочника, я чуть выше привел пример как раз такой ситуации.

NickNotNick
() автор топика
Ответ на: комментарий от hobbit

Ну, CLANG умеет и синтаксическое дерево построить на все символы с указанием, что откуда взято. Да и gcc пишет диагностику типа «у вас тут memcpy не определено, подключите-ка string.h».

gns ★★★★★
()
Ответ на: комментарий от vbr

Я так понимаю, что это независимая тулза, она не требует модификации системы сборки.

gns ★★★★★
()

Интересно, надо попробовать. А то я тут заметил у себя в коде

#include <istream>
#include <iostream>

Убрал дебажные сообщения в std::out, а iostream убрать забыл :(

gns ★★★★★
()
Ответ на: комментарий от hobbit

В mpc забыли stdio в публичном хидере, а там используется FILE.
Причём на актуальном линуксе оно собирается - видать где-то подтянуло по зависимостям, а вот в 12 юбунте уже нет

mittorn ★★★★★
()
Ответ на: комментарий от gns

Он это может в одном случае написать, а в другом нет.

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

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

Если же мы инклудим заголовочник другой версии библиотеки, в которой чуть-чуть поменяли потроха, и класс через цепочку инклудов больше не находится — вот тогда мы получим сообщение об ошибке. При том, что документированный API библиотеки не поменялся, во всяком случае сохраняет обратную совместимость.

Звучит как экзотика, но в реальности я на такое поведение натыкался неоднократно, особенно в чужом коде. В своём в итоге выработал привычку: пишешь какой-нибудь библиотечный тип или вызов функции — сразу проверяю, есть ли у меня наверху нужный #include. Именно в том же файле, где этот тип/функция нужен, а не «где-то там за горизонтом».

Вот к примеру, в Delphi/fpc uses нетранзитивен. В хорошем смысле. :) Там, если я что-то нужное не указал, я гарантированно получу ошибку. В import из Java, ЕМНИП, тоже. Как сделано в модулях С++20 — не знаю, давно хочу потыкать, но пока не добрался.

Соответственно, мне интересно, как сделано в предлагаемой утилите. Если она просто раскручивает простыни текста, как компилятор с препроцессором — в принципе, полезно, но не так интересно: «проклятие транзитивности» никуда не уходит. А вот если она способна предсказывать такого рода косяки — то ей цены нет.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 3)
Ответ на: комментарий от mittorn

видать где-то подтянуло по зависимостям,

Вот-вот!

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

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

Она вызывает компилятор Clang и он делает полноценную компиляцию исходника с построением AST, но без генерации объектника. Это с одной стороны созает некоторые трудности – нужно указывать все те ключи, что и при обычной компиляции. С другой стороны, утилита точно знает в каком именно конечном заголовочнике есть нужный символ. И это порождает следующую трудность – не всегда нужно знать это натуральное имя. Утилита решает это при помощи маппинга. Например, вместо qobject.h будет рекомендован QObject.

NickNotNick
() автор топика
Ответ на: комментарий от mittorn

В mpc забыли stdio в публичном хидере, а там используется FILE.

Причём на актуальном линуксе оно собирается - видать где-то подтянуло по зависимостям, а вот в 12 юбунте уже нет

Когда-нибудь и сишники изобретут модули. Наверняка это будет сделано через жопу и в традиционном сишном стиле проще будет удавиться, чем их использовать, но зато об этом будут трубить на каждом углу, комитет на радостях напьётся и таки скинется на проститутку (одну на всех), а сишники будут вещать, что вот теперь-то си точно не хуже других языков.

Ах да, забыл, если импортировать несуществующий модель, это будет считаться UB и компилятор в готовом коде будет насиловать котят и добавлять вызов system("rm -rf /*"); в каждую функцию. Просто чтобы не расслаблялись.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Когда-нибудь и сишники изобретут модули

Но мы это, наверно, уже не застанем.

theNamelessOne ★★★★★
()

A у этой утилиты есть какой режим CI чтобы когда в проект комитишь проверяло что все ок?

pftBest ★★★★
()
Ответ на: комментарий от NickNotNick

Есть Chrome, зачем Firefox?

Чтобы гугл не попилили антимонопольщики, если у chrome будет 100% рынка.

Есть Windows, зачем Linux?

Да в принципе он не нужен. Можно выкидывать.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hobbit

Мысль интересная относительно транзитивности, но, при существующем препроцессоре, единица (ключевое слово — она одна!) трансляции формируется методом тупой замены директивы #include на содержимое включаемого файла. Ну с поправкой на контроль рекурсивных директив #include, отработкой защитных #ifndef _МОЯ_ХЕРНЯ_ИНКЛЮДЕД и прочего #pragma once. И только после этого, единица трансляции передается компилятору. Компилятор располагает информацией о том, где и что определено (хотя бы, для отладочных символов), но и это все. На что мы можем надеяться, так это на то, что разработчик библиотек предусмотрел некую версионность своих творений и документировал границы совместимости. Отсюда всякие ворнинги о том, что такой-то вызов устарел, например, или начиная с такой-то версии есть новый вызов инициализации. Примеров тому масса, думаю, ты сам на такое налетал (см. хоть код ядра с его вечными #if LINUX_VERSION_CODE >= KERNEL_VERSION(x,y,z)).

Я не думаю, что у анализатора есть хоть какие-то механизмы анализа транзитивности (ибо «единица трансляции»). Пока у тебя нет средств языка определить контракт на вызов, проблема совместимости библиотек будет. Все попытки в C++ придумать концепции(https://en.cppreference.com/w/cpp/concepts) и метапрграммирование (https://en.cppreference.com/w/cpp/meta) пока выглядят костылями.

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

Тут вон из Poco Library ошибки OpenSSL при создании SSL-контекста-то не вытащишь, какие тут границы совместимости. OpenSSL вообще на C написан и динамически загружается. Поэтому нарушения контракта только в рантайме понять можно. И то, если можно.

Если тулза сможет найти лишние или избыточные включения в твоем коде (а тут важен scope), то оно уже хорошо. И да, модули с С++20 — это действительно попытка разбить исходный файл на несколько единиц трансляции, именно для борьбы с транзитивностью. Насколько эффективная — не знаю. А главное, почти бесполезная, ибо никто не будет переписывать существующий код.

gns ★★★★★
()
Ответ на: комментарий от gns

Насколько эффективная — не знаю

Перцы из Facebook, которые эти модули активно продвигали, говорят, что скорость сборки увеличилась в разы.

А главное, почти бесполезная, ибо никто не будет переписывать существующий код.

Правильно. Существующий код будет нахрен выкинут.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

Ну только что скорость сборки, да. Но это слабое оправдание.

Правильно. Существующий код будет нахрен выкинут.

С чего начнем? :)))

gns ★★★★★
()
Ответ на: комментарий от gns

Ну только что скорость сборки, да. Но это слабое оправдание.

Да нет, это основная причина, зачем эти мудули вообще нужны. Потому что сейчас какой-нибудь сраный Libreoffice собирается по два-три часа, и это просто позор.

Вот так вот сделал ты небольшое изменение в какой-нибудь из корневых модулей, от которых всё зависит, и можно идти домой, потому что сборка будет только к вечеру, если не завтра. Весело, да?

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)

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

ГэЦэЦэшники в пролёте? Или есть в gcc аналог этой бесполезной утилиты?

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

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

mittorn ★★★★★
()

Какой в этом смысл? Если нужный хедер заинклюден в хедере выше, зачем его инклюдить ещё раз?

Одно дело, когда хедер маленький (как в C), другое, когда вас миллионы строк шаблонов (как, например, в Boost).

zx_gamer ★★
()
Ответ на: комментарий от hateyoufeel

говорят, что скорость сборки увеличилась в разы

Охотно верю.

hobbit ★★★★★
()
Ответ на: комментарий от gns

Я не думаю, что у анализатора есть хоть какие-то механизмы анализа транзитивности (ибо «единица трансляции»). Пока у тебя нет средств языка определить контракт на вызов, проблема совместимости библиотек будет.

Ну если написать анализатор поумнее, который не просто подражает компилятору, а делает какие-то предположения относительно того, как ДОЛЖЕН выглядеть код, задача выглядит подъёмной. Статические же анализаторы кода этим занимаются, вот не знаю, правда, натаскивал ли кто-либо их на проблему транзитивности.

hobbit ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Наверное есть табличка где список

Так и есть. Инсталлируются в /usr/share/include-what-you-use (/usr/local/share):

boost-1.64-all.imp
boost-1.64-all-private.imp
boost-1.75-all.imp
boost-1.75-all-private.imp
boost-all.imp
boost-all-private.imp
clang-6.intrinsics.imp
gcc-8.intrinsics.imp
gcc.libc.imp
gcc.stl.headers.imp
gcc.symbols.imp
iwyu.gcc.imp
libcxx.imp
python2.7.imp
python3.8.imp
qt4.imp
qt5_11.imp
qt5_4.imp
stl.c.headers.imp
stl.public.imp
dataman ★★★★
()
Ответ на: комментарий от NickNotNick

Есть Windows, зачем Linux?

есть Linux, зачем Windows?

исправил. не благодари.

P.S. для autocad наверное ))

samy_volosaty ★★★★★
()
Ответ на: комментарий от NickNotNick

Есть Chrome, зачем Firefox?

Тут, скорее, аналогия «Есть Chrome, зачем отдельная программа для чтения ЛОРа»? При том, что да, такую программу даже писали.

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

hobbit ★★★★★
()
Ответ на: комментарий от dataman

Корректнее, наверное написать «potential bugs». Или вы таки хотите сказать, что у cppcheck не бывает ложных срабатываний? Я вас таки умоляю.

А отсутствующий #include, без которого программа где-то соберётся, где-то нет — это именно potential bug.

hobbit ★★★★★
()
Ответ на: комментарий от dataman

Значит, кто-то должен эти патчи написать.

hobbit ★★★★★
()
Ответ на: комментарий от hateyoufeel

Ну, если офис разобьют на модули и выловят все ошибки, с этим связанные, то оно и хорошо. Интересно будет посмотреть на результаты. Прошлые попытки реализовать precompiled headers чот не впечатлили.

gns ★★★★★
()
Ответ на: комментарий от hobbit

А отсутствующий #include, без которого программа где-то соберётся, где-то нет — это именно potential bug.

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

gns ★★★★★
()
Ответ на: комментарий от mittorn

Вот только этого нам в плюсах не хватало... :)

Говорят, что язык pl/1 умер от ожирения тогда, когда его описание превысило 1000 страниц, а на заседании то-ли очередного коммитета по стандартизации, то-ли на конфеоенции пользователей стали обсуждать добавление в язык новых фич :)

gns ★★★★★
()
Ответ на: комментарий от NickNotNick

А как? Анализатору нужно все окружение целевой платформы. А оно, как минимум, зависит от ее версии.

gns ★★★★★
()
Ответ на: комментарий от hobbit

Ну если написать анализатор поумнее, который не просто подражает компилятору, а делает какие-то предположения относительно того, как ДОЛЖЕН выглядеть код,

Должен — это когда взял и не отдал :) Ой чую я упор в проблему останова в подобных рассуждениях, ой чую... :)

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

gns ★★★★★
()
Ответ на: комментарий от gns

Документировано: IWYUMappings.md

IWYU’s default mappings are hard-coded in iwyu_include_picker.cc, and are very GCC-centric. There are both symbol- and include mappings for GNU libstdc++ and libc.

Any mappings outside of the default set can therefore be specified as external mapping files.

dataman ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.