FOnline Engine
Current master GitHub
Документация Docs/ru/contributing/coding-contracts/local-variables.md

Локальные переменные

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

В движке нет отдельного правила «неизменяемость по умолчанию». Локальные переменные, параметры функций и методов следуют обычной семантике изменения C++ и не требуют аннотации при записи.

Избыточный локальный const

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

int32_t count = GetCount();
item_ptr item = FindItem();

Сохраняйте константность, являющуюся частью фактического типа или семантики значения:

const Item* item = FindItem();       // const pointee
const Item& item = GetItem();        // const referent
const int32_t values[] = {1, 2};     // const elements
constexpr int32_t limit = 10;        // required by constexpr

У int32_t* const pointer верхнеуровневый const можно удалить, поэтому он диагностируется. Параметры эта проверка не рассматривает.

Редкое намеренное использование верхнеуровневого квалификатора локальной переменной можно подавить в строке диагностики или предыдущей строке:

const int32_t value = SelectOverload(); // FO_REDUNDANT_CONST_SUPPRESS: const is required for overload selection

Причина обязательна и должна содержать не менее восьми символов.

Явные простые локальные типы

Заменяйте локальный auto, только если выполняются все условия:

  • Clang определяет одно доступное неквалифицированное имя типа в snake_case.
  • У типа нет видимых аргументов шаблона.
  • Тип не вложен и не квалифицирован пространством имён.
  • Явное написание типа не добавляет и не скрывает преобразование.
  • Объявление не является structured binding, лямбдой или зависимым выведением.

Когда Clang показывает только канонический шаблонный тип, неквалифицированный псевдоним допустим, если он явно написан в инициализаторе, является единственным простым псевдонимом того же развёрнутого типа и доступен в месте объявления. Это покрывает вызовы вроде glm::translate(mat44 {...}, offset), не допуская внутренние имена библиотек наподобие iterator или value_type.

Примеры:

int32_t count = GetCount();
float32_t factor = GetFactor();
hstring name = GetName();

Сохраняйте auto в случаях вроде:

auto values = vector<int32_t> {};
auto iter = values.begin();                  // nested iterator type
auto handle = MakeHandle<void>();            // template spelling
auto pointer = GetRawPointer();               // explicit target may convert
auto [left, right] = Split(value);            // structured binding

Если выведенный числовой примитив записывается явно, используйте размерное имя движка:

Выведенный тип Явное написание
short int16_t
int int32_t
float float32_t
double float64_t

Существующие знаковые и беззнаковые типы фиксированной ширины сохраняют своё написание.

См. Контроль соблюдения, где описана проверка правила.

Использование после перемещения

Перемещение из локальной переменной не делает её изменяемой и не требует аннотации. Независимый gate bugprone-use-after-move запрещает последующее использование до корректной повторной инициализации:

value_type value = BuildValue();
Consume(std::move(value));

Намеренная проверка перемещённого объекта должна явно назвать контракт:

CHECK(value.empty()); // FO_USE_AFTER_MOVE_SUPPRESS: test verifies the moved-from container contract

Причина обязательна и должна содержать не менее восьми символов.

Контроль соблюдения

Эти правила рассчитаны на анализатор с compile_commands.json для Clang 20+: проверку явных типов и проверки clang-query / clang-tidy для избыточной локальной константности и использования после перемещения. Движок владеет только описанными правилами и маркерами FO_REDUNDANT_CONST_SUPPRESS / FO_USE_AFTER_MOVE_SUPPRESS. Реализация анализатора, создание базы компиляции, выбор области и политика CI принадлежат подключающему проекту.

Перед публикацией выполняйте все три проверки над изменёнными исходниками движка. Проект может распространить тот же gate на собственные native extensions, но пути проекта, имена задач и workflow jobs не входят в переиспользуемый контракт.

На машине, запускающей gate, должны быть доступны и clang-query, и clang-tidy, а база компиляции должна обеспечивать настоящий разбор. Сгенерированные заголовки из общей цепочки include движка должны существовать до анализа, иначе translation units завершатся на отсутствующих include ещё до проверки правил.

До передачи базе Clang tooling сократите compilation database до одной команды на translation unit. CMake создаёт entry для каждого target, компилирующего файл, поэтому один Engine source может встретиться десятки раз. Clang выполняет action для каждой entry, а clang-query удерживает каждый построенный AST, и duplicates умножают wall time и память. Один Engine AST занимает примерно половину гигабайта; существенно больший расход обычно означает непрореженную database, а не неизбежную стоимость analyzer.

Введите запрос.