Неиспользуемая декларация или группа деклараций
[email protected]Неиспользуемый код увеличивает поверхность изменений: его продолжают читать, переносить и поддерживать, хотя он не участвует в работе продукта.
SWIFT ANALYZER / КАТАЛОГ
138 правил о поведении Swift-программ. От устаревшего состояния после await до лишних обходов коллекции и утечки секрета в лог.
Найдено правил: 138 · условий: 141
[email protected]Неиспользуемый код увеличивает поверхность изменений: его продолжают читать, переносить и поддерживать, хотя он не участвует в работе продукта.
[email protected]Тесты могут сохранять видимость востребованности API, который больше не нужен поставляемому приложению. Но тестовая поддержка сама по себе не ошибка.
[email protected]Прямой вызов через запрещённую границу делает слои зависимыми от внутренних деталей и затрудняет замену компонентов.
[email protected]Лишняя публичность создаёт обязательства совместимости и позволяет внешнему коду зависеть от деталей реализации.
[email protected]Лишняя product dependency расширяет граф сборки и поддержки. Для удаления нужно исключить не только вызовы, но и линковку, ресурсы и регистрацию.
[email protected]Код может случайно компилироваться через транзитивную зависимость и ломаться после безобидного изменения промежуточного пакета.
[email protected]Запрещённый цикл связывает жизненный цикл компонентов и мешает независимой сборке или изменению. Цикл важен относительно политики, а не сам по себе.
[email protected]Внутренний тип в публичной сигнатуре заставляет пользователей API знать о реализации и может нарушать границы модулей.
[email protected]Runtime-регистрация может ссылаться на несовместимый класс или точку входа, даже когда обычные вызовы выглядят корректно.
[email protected]Обязательный lookup отсутствующего ресурса приводит к неработающему пути или аварийному unwrap. Это проверяется относительно состава конкретной сборки.
[email protected]Параметр без семантической роли усложняет API и вводит вызывающий код в заблуждение. Виртуальные и protocol-вызовы требуют проверки всей семьи реализаций.
[email protected]Запись в свойство может создавать впечатление сохранённого состояния, хотя это состояние никогда не наблюдается. Но сама запись иногда имеет важный эффект lifetime.
[email protected]Conformance может быть частью dispatch или framework-контракта без очевидного вызова метода. Удалять его допустимо только при отсутствии всех значимых ролей.
[email protected]Import меняет доступный набор extensions и overloads. Успешная компиляция после удаления ещё не означает сохранение привязок вызовов.
[email protected]Код обращается к состоянию из контекста, которому это состояние не принадлежит. Особенно опасны границы legacy API, скрывающие изоляцию от компилятора.
[email protected]Внешняя точка входа может вызывать UI-код без проверенного контракта MainActor. Это повод проверить границу, а не автоматически объявить гонку.
[email protected]Detached-задача не наследует actor isolation и task-local значения так же, как обычная Task. Потеря нужного контекста может изменить поведение.
[email protected]Scheduler callback и изоляция его тела могут расходиться. Название очереди или нахождение рядом с MainActor не доказывает корректность.
[email protected]assumeIsolated утверждает уже существующую изоляцию, но не переключает executor. Ложное утверждение приводит к аварии или нарушению контракта.
[email protected]Некоторые ресурсы принадлежат определённой очереди, event loop или контексту. Общая потокобезопасность языка не отменяет их собственного контракта.
[email protected]После await задача может продолжиться на другом потоке даже при сохранённой actor isolation. Thread-local ресурс нельзя считать автоматически сохранённым.
[email protected]Адаптер задачи может потерять task-local значение или необходимое предпочтение executor, на которое опирается вызываемый код.
[email protected]Блокирующая операция занимает executor и мешает обслуживать другие задачи; на MainActor это проявляется зависанием UI.
[email protected]Длительная CPU-работа на критическом executor задерживает все обслуживаемые им события даже без блокирующих системных вызовов.
[email protected]Лишняя граница планирования добавляет задержку и меняет порядок событий. Удалять её можно лишь при сохранении наблюдаемой семантики.
[email protected]Поэлементные обращения к actor многократно оплачивают переход и открывают промежутки для interleaving. Пакетный метод иногда дешевле и точнее выражает операцию.
[email protected]Последовательные await могут случайно сериализовать независимые операции и увеличить время ответа до суммы задержек.
[email protected]Custom SerialExecutor обязан исключать одновременное исполнение своих jobs. Нарушение делает обещанную actor isolation недействительной.
[email protected]Проверка состояния до await может устареть: actor допускает другие обращения во время suspension.
[email protected]Если инвариант восстановится только после await, другой вызов actor может увидеть промежуточное некорректное состояние.
[email protected]Ответ старого запроса может перезаписать результат нового, хотя оба обращения к памяти корректно изолированы.
[email protected]Проверка кэша с последующим await позволяет нескольким callers одновременно запустить одну дорогую операцию.
[email protected]Actor сериализует отдельные участки исполнения, но не обещает FIFO завершения произвольных задач.
[email protected]Не возобновлённая continuation навсегда оставляет ожидающую задачу suspended. Типичный источник — пропущенная ветка ошибки.
[email protected]Continuation должна возобновляться ровно один раз. Конкурирующие success, timeout и cancellation легко нарушают это условие.
[email protected]Отмена может прийти до регистрации handle. Если её обработчик видит nil, операция позже запустится без возможности отмены.
[email protected]После отмены или отзыва разрешения задача может продолжить работу и выполнить запрещённую запись.
[email protected]Cancellation в Swift кооперативна: длительная работа без проверок продолжает расходовать ресурсы после отмены.
[email protected]Возврат первого результата из task group не завершает scope, пока не завершились остальные children. Timeout может оказаться фиктивным.
[email protected]Неструктурированная задача может пережить экран, запрос или сервис, для которого она создавалась.
[email protected]Потерянный handle throwing Task может скрыть ошибку обязательной операции: вызывающая сторона считает работу успешной.
[email protected]Удержание lock или аналогичного guard через await мешает прогрессу других задач и может нарушить требования привязки к потоку.
[email protected]Цикл ожиданий делает прогресс невозможным: каждый участник ждёт события, которое может произвести только другой участник цикла.
[email protected]Синхронное ожидание внутри cooperative pool может занять все потоки, необходимые задаче-производителю.
[email protected]Высокоприоритетная задача может ждать низкоприоритетную работу через непрозрачный bridge без нужного механизма donation или ограничения задержки.
[email protected]Unsafe Sendable или legacy-граница может скрыть общую изменяемую память от проверок компилятора.
[email protected]Callback может быть синхронным и повторно войти в объект до завершения инициализации или регистрации операции.
[email protected]Executor должен доставить каждый принятый job ровно один раз. Потеря зависает задачу, повторное исполнение нарушает runtime-контракт.
[email protected]Указатель на временно заимствованную память становится недействительным за пределами области borrow, даже если его тип позволяет сохранить адрес.
[email protected]Освобождение памяти не обнуляет все её aliases. Последующее чтение через любой alias использует уже недействительный ресурс.
[email protected]Повторное освобождение или несовместимая пара allocator/deallocator повреждает память. Совпадение типов указателей не доказывает совместимость.
[email protected]unowned не удерживает объект живым. Если callback переживает владельца, обращение приводит к аварии.
[email protected]Unmanaged переносит ответственность за retain/release на код. Несбалансированная передача приводит к утечке или преждевременному освобождению.
[email protected]Цикл сильных ссылок не даёт владельцам освободиться, если нет внешнего механизма разрыва.
[email protected]Weak-ссылка может исчезнуть раньше обязательной операции. Это обратная сторона механического устранения retain cycles.
[email protected]Observer, таймер или подписка продолжает получать события после завершения области, которой он принадлежит.
[email protected]Ошибка или ранний return может пропустить обязательное закрытие файла, дескриптора или другого ресурса.
[email protected]После close или передачи владения прежний handle больше нельзя использовать даже при сохранённом значении переменной.
[email protected]Выделенная память ещё не содержит инициализированных значений Swift. Чтение до initialize нарушает контракт хранения.
[email protected]Адрес может быть действительным, но переданный count выходит за доступный или инициализированный диапазон.
[email protected]Линейный поиск внутри цикла превращает обработку двух коллекций в произведение их размеров. При подходящей семантике индекс строится один раз.
[email protected]Одинаковая сортировка неизменного набора внутри цикла повторяет работу, которую можно выполнить один раз.
[email protected]Материализация полностью потребляемого промежуточного результата на каждом шаге может многократно копировать растущий объём данных.
[email protected]Удаление первого элемента Array сдвигает оставшийся хвост. Повторение до опустошения даёт квадратичную работу.
[email protected]Полная сортировка требует больше работы, чем поиск одного экстремума; для малого top-k тоже существуют специализированные алгоритмы.
[email protected]Comparator вызывается многократно, поэтому дорогая проекция внутри него может доминировать над самой сортировкой.
[email protected]Eager map вычисляет весь набор, хотя downstream потребляет лишь небольшой prefix.
[email protected]Изменение разделяемого CoW-буфера может физически скопировать весь storage. Частые snapshots перед мутацией делают стоимость неожиданной.
[email protected]Getter, локальная мутация и setter могут извлекать и возвращать большую коллекцию на каждом шаге вместо изменения на месте.
[email protected]Неудачная стратегия capacity может разрушить амортизированную стоимость роста, особенно в собственных контейнерах или при повторном точном резервировании.
[email protected]Поэлементные переходы между представлениями Swift и Objective-C могут повторять boxing, allocation или conversion.
[email protected]Дорогой hash или equality многократно исполняется при lookup и может скрыть линейную или более высокую стоимость за API словаря.
[email protected]Маленький slice может удерживать большой backing storage значительно дольше, чем ожидает вызывающий код.
[email protected]Тысячи очень маленьких задач могут тратить больше времени на scheduling, чем на полезную работу.
[email protected]Неограниченный fan-out удерживает входы, captures и результаты сразу многих задач, вызывая высокий пик памяти.
[email protected]Секрет, попавший в лог, может стать доступен гораздо более широкому кругу систем и людей, чем исходное хранилище.
[email protected]Интерполяция недоверенного значения в SQL смешивает данные и структуру запроса.
[email protected]Передача недоверенного текста оболочке позволяет интерпретировать его как команды и операторы.
[email protected]Недоверенная format string управляет интерпретацией аргументов, а в низкоуровневых API может нарушить безопасность памяти.
[email protected]Имя файла из архива может вывести запись за каталог назначения через .., абсолютный путь или symlink.
[email protected]Недоверенный текст в HTML или JavaScript может стать исполняемым кодом вместо содержимого.
[email protected]Пользовательский URL может направить привилегированный запрос к внутреннему сервису или недопустимой схеме.
[email protected]Формирование predicate из строки с пользовательским вводом позволяет изменить структуру условия.
[email protected]Недоверенное значение внутри regex меняет смысл поиска: данные становятся метасимволами регулярного выражения.
[email protected]Некоторые regex на специально подобранном длинном вводе требуют чрезмерного backtracking и блокируют обработчик.
[email protected]Разрешённые внешние XML entities могут читать локальные файлы или выполнять нежелательные сетевые обращения.
[email protected]Безусловное принятие сертификата убирает проверку подлинности сервера, хотя соединение выглядит зашифрованным.
[email protected]Криптографический примитив может работать корректно, но не подходить назначению: например, быстрый checksum не защищает пароль.
[email protected]Повтор nonce с одним ключом может разрушить гарантии схемы шифрования. Постоянная строка nonce особенно опасна при нескольких сообщениях.
[email protected]Быстрый или слишком дешёвый password derivation делает перебор украденной базы практичнее.
[email protected]Предсказуемый генератор позволяет угадывать токены, ключи и другие значения, безопасность которых зависит от случайности.
[email protected]Десериализация недоверенного объектного графа без ограничения типов допускает нежелательные объекты и поведение.
[email protected]Проверка доступа на одном пути не защищает другой путь к privileged sink; решение также может устареть к моменту применения.
[email protected]Значение может попасть к чувствительной операции по обходному пути, не проходящему обязательную проверку.
[email protected]Встроенный в shipping-продукт секрет доступен получателю бинарника и не может считаться серверной границей доверия.
[email protected]WebView, показывающий недоверенное содержимое, может получить bridge или доступы, предназначенные только доверенной странице.
[email protected]Ключ может быть корректно создан, но иметь недостаточную стойкость для выбранного назначения и политики.
[email protected]Зависимость, получаемая по незащищённому транспортному каналу, может быть подменена до попадания в сборку.
[email protected]Неопределённое разрешение зависимостей делает одну версию проекта зависимой от времени сборки и внешних изменений.
[email protected]Debug endpoint или обход проверки, попавший в shipping-вариант, открывает возможности, предназначенные только разработчику.
[email protected]Set и Dictionary предполагают согласованность equality и hashing. Если равные значения получают разные хеш-входы, membership может вести себя неожиданно.
[email protected]hashValue предназначен для внутрипроцессного хеширования и не является договором стабильной идентичности между запусками.
[email protected]Числа похожи, но количество символов, UTF-8 байтов и UTF-16 единиц — разные величины. Ошибка проявляется на не-ASCII данных.
[email protected]Индекс связан с состоянием коллекции. Изменение структуры может сделать сохранённый индекс недействительным.
[email protected]Мутация поля, участвующего в equality/hash, пока объект находится в Set или ключах Dictionary, ломает предположения membership.
[email protected]Алгоритм сортировки требует определённых законов сравнения. Их нарушение может давать нестабильный или неверный результат.
[email protected]Нестабильный порядок становится дефектом, когда результат должен повторяться: например, подпись, cache key или canonical JSON.
[email protected]Преобразование числа или расчёт размера может выйти за допустимый диапазон и привести к trap либо неверному значению.
[email protected]Infinity и NaN допустимы для части вычислений, но нарушают контракт consumer, которому нужны только конечные значения.
[email protected]Force unwrap, try! или другой force operation опасен, когда существует допустимый путь к невыполнимому предусловию.
[email protected]Single-pass sequence может исчерпаться при первом чтении. Второй consumer не обязательно увидит те же элементы.
[email protected]Внешне скопированное значение может разделять внутреннее изменяемое состояние, хотя API обещает независимую копию.
[email protected]Разные правила нормализации одной identity приводят к пропускам lookup, дубликатам или обходу проверок.
[email protected]Значение вычислено и записано, но до любого наблюдения заменено другим. Это может быть пропущенное использование или лишняя работа.
[email protected]Предикат, одинаковый для всех допустимых состояний, может скрывать неверную проверку и создавать ложное ощущение защиты.
[email protected]Одинаковые результаты обеих ветвей могут означать ошибку копирования или лишнее условие. Сходство текста не доказывает равенства эффектов.
[email protected]Недостижимая ветвь может указывать на потерянный сценарий обработки или устаревшее предположение о входе.
[email protected]Чистая операция с отброшенным результатом часто означает, что программист ожидал изменения исходного значения.
[email protected]Точное сравнение приближённых величин может не соответствовать заявленному допуску и неверно различать эквивалентные измерения.
[email protected]Producer быстрее consumer, а буфер не ограничен: очередь событий способна расти без верхней границы памяти.
[email protected]Политика dropping нарушает контракт, если каждое событие должно быть обработано: потеря может выглядеть как успешная отправка.
[email protected]Одновременные next на одном iterator могут нарушать его контракт и приводить к потере или неправильной доставке элементов.
[email protected]Отсутствие finish после терминального события оставляет consumer ждать данные, которые уже никогда не придут.
[email protected]Retry без прогресса, лимита или backoff может бесконечно нагружать сервис и удерживать задачу.
[email protected]Повтор операции после неясного сетевого исхода может применить её дважды, даже если первый ответ не был получен.
[email protected]Логически единое изменение, разбитое на отдельные транзакции, оставляет частично применённое состояние при ошибке.
[email protected]Identity, создаваемая заново при каждом чтении, заставляет SwiftUI считать прежний элемент новым и терять его локальное состояние.
[email protected]Два разных элемента с одинаковым id делают сопоставление views неоднозначным.
[email protected]Изменение состояния во время вычисления зависимого представления может запускать повторные обновления без достижения устойчивого состояния.
[email protected]Начальное значение State не означает синхронизацию с каждым новым input. View с прежней identity может сохранить старое значение.
[email protected]Изменение публичного API может сломать исходный код разрешённых consumers, хотя сама библиотека успешно собирается.
[email protected]Бинарный consumer может стать несовместим с новой библиотекой без перекомпиляции, даже когда исходники выглядят похожими.
[email protected]Неизменная сигнатура может скрывать смену порядка, ошибок, побочных эффектов или иного поведения, на которое опирается consumer.
[email protected]После изменения импортов или overloads прежний код может разрешаться в другой символ и незаметно менять смысл.
[email protected]Разрешённый version range может включать версию зависимости, с которой consumer несовместим.
[email protected]Изменение может обойти обязательную проверку затронутых consumers из-за неполной карты impact или ошибочного gate.
[email protected]Изменение может ухудшить гарантированную стоимость памяти или времени на сопоставимых входах, даже при сохранённом результате.
[email protected]Кэш возвращает устаревший результат, если ключ или invalidation не учитывает зависимость вычисления.
Один RuleID может объединять несколько условий. Вид результата не задаёт severity, а стратегия первого результата не означает готовность. Обзор направлений →