Перейти к содержанию

Пороговые значения по умолчанию

На этой странице перечислены пороговые значения по умолчанию для каждого правила Qualimetrix. Когда метрика превышает порог warning, выдается предупреждение. Когда превышает порог error -- ошибка.

Правила сложности (Complexity)

Правила, которые измеряют, насколько сложно понять и протестировать код.

Правило ID Уровень Warning Error Область
Cyclomatic Complexity complexity.ccn Метод 10 20 Метод
Cyclomatic Complexity complexity.ccn Класс (макс.) 30 50 Класс
Cognitive Complexity complexity.cognitive Метод 15 30 Метод
Cognitive Complexity complexity.cognitive Класс (макс.) 30 50 Класс
NPath Complexity complexity.npath Метод 200 1000 Метод
NPath Complexity complexity.npath Класс (макс.) 500 1000 Класс (отключено)
WMC complexity.wmc - 50 80 Класс

Cyclomatic Complexity подсчитывает количество независимых путей выполнения в методе. Метод с CCN равным 10 имеет 10 различных путей для тестирования.

Cognitive Complexity измеряет, насколько сложно читать код. В отличие от цикломатической сложности, вложенные конструкции штрафуются сильнее.

NPath Complexity подсчитывает количество возможных путей выполнения. Растет гораздо быстрее, чем цикломатическая сложность для кода с большим количеством условий.

WMC (Weighted Methods per Class) -- сумма цикломатических сложностей всех методов класса. Высокий WMC означает, что класс делает слишком много.

Правила размера (Size)

Правила, которые проверяют, не стали ли классы и пространства имен слишком большими.

Правило ID Warning Error Область
Method Count size.method-count 20 30 Класс
Class Count size.class-count 15 25 Пространство имен
Property Count size.property-count 15 20 Класс

Правила проектирования (Design)

Правила, которые проверяют дизайн классов и структуру наследования.

Правило ID Warning Error Область
LCOM cohesion.lcom 3 5 Класс
NOC design.noc 10 15 Класс
DIT design.dit 4 6 Класс
Покрытие типами параметров design.type-coverage.param 80 (ниже) 50 (ниже) Класс
Покрытие типами возврата design.type-coverage.return 80 (ниже) 50 (ниже) Класс
Покрытие типами свойств design.type-coverage.property 80 (ниже) 50 (ниже) Класс

LCOM (Lack of Cohesion of Methods) измеряет, насколько хорошо методы в классе связаны друг с другом. Высокий LCOM говорит о том, что класс стоит разделить.

NOC (Number of Children) подсчитывает прямых наследников. Слишком много наследников означает, что родительский класс может быть слишком общим.

DIT (Depth of Inheritance Tree) подсчитывает количество уровней наследования. Глубокие иерархии сложнее понимать и поддерживать.

Type Coverage измеряет процент типизированных объявлений. В отличие от большинства правил, нарушения фиксируются, когда значения падают ниже порога.

Правила связанности (Coupling)

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

Правило ID Warning Error Область
CBO coupling.cbo 14 20 Класс
CBO coupling.cbo 14 20 Пространство имен
Instability coupling.instability 0.8 0.95 Класс
Instability coupling.instability 0.8 0.95 Пространство имен
Distance coupling.distance 0.3 0.5 Пространство имен
ClassRank coupling.class-rank 0.02 0.05 Класс
Непривязанный неймспейс фреймворка coupling.unmatched-framework-namespace — (warning, фиксированная) Проект

CBO (Coupling Between Objects) подсчитывает количество других классов, от которых зависит данный класс. Высокая связанность затрудняет внесение изменений.

Instability -- коэффициент от 0 (полностью стабильный) до 1 (полностью нестабильный). Класс, который зависит от многих других, но от которого никто не зависит -- нестабилен. По умолчанию min_afferent: 1 -- классы и пространства имён без зависимых (Ca=0) пропускаются, так как имеют I=1.0 по определению. Установите 2, чтобы также пропускать символы с единственным зависимым.

Distance from the Main Sequence измеряет, насколько хорошо пространство имен балансирует между абстрактностью и стабильностью. Значение, близкое к 0 -- идеально.

ClassRank использует алгоритм PageRank на графе зависимостей для определения наиболее "важных" классов. Высокий ClassRank означает, что класс является критическим узлом с широким влиянием на систему. Пороги автоматически адаптируются к размеру проекта через sqrt-масштабирование (калибровано для 100 классов).

Непривязанный неймспейс фреймворка не имеет числового порога: сообщает о префиксе framework-namespaces, под который не попало ни одно имя прогона — по находке на префикс, с фиксированной severity warning. Это обычная находка, поэтому её видят --fail-on, --disable-rule и baseline. См. правила Coupling.

Правила сопровождаемости (Maintainability)

Эти правила работают наоборот: нарушение фиксируется, когда метрика падает ниже порога, а не превышает его.

Правило ID Warning (ниже) Error (ниже) Область
Maintainability Index maintainability.mi 40 20 Метод

Maintainability Index объединяет сложность, количество строк кода и метрики Холстеда в единую оценку от 0 до 100. Чем выше -- тем лучше. Оценка ниже 20 означает, что код очень сложно поддерживать.

Правила архитектуры (Architecture)

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

Правило ID Серьёзность По умолчанию Примечания
Циклические зависимости architecture.circular-dependency Error (прямые) / Warning (транзитивные) включено Прямые циклы (размер 2) — Error; более длинные — Warning. См. Правила архитектуры.
Нарушения слоёв architecture.layer-violation Warning (настраивается) включено (no-op без architecture.layers) Числовых порогов нет, только флаг enabled и выбор severity. Активируется, только если секция верхнего уровня architecture: объявляет слои. См. Правила архитектуры.
Недостижимый слой architecture.unreachable-layer Error (фиксированная, не настраивается) включено (срабатывает только с architecture.layers) Один диагностик на каждый объявленный слой, паттерны которого не совпали ни с одним классом, ни с одним концом ребра зависимости. Ловит ситуацию, когда более широкий паттерн раньше в списке тихо перехватывает класс у более позднего слоя; учёт концов рёбер вдобавок к классам не даёт слоям, служащим только для классификации внешнего кода (например, вендорный неймспейс ClickHouseDB\**, видимый лишь как ЦЕЛЬ зависимости), ложно считаться недостижимыми. Это конфигурационная ошибка: она безусловно завершает прогон, независимо от --fail-on, и не может быть принята в baseline или подавлена. Удалённой опции unreachable_layer_severity больше не существует — серьёзность зафиксирована. Слой, объявленный pending: true, эта диагностика пропускает.
Сработавший задел architecture.pending-layer-matched Error (фиксированная, не настраивается) включено (срабатывает только для слоёв с pending: true) Один диагностик на каждый слой, объявленный pending: true — «код ещё не написан», декларация, подавляющая для него architecture.unreachable-layer, — чьи критерии всё же совпали хотя бы с одним классом или концом ребра зависимости. Совпадение засчитывается, даже если все назначения выиграл более широкий слой, объявленный раньше: именно этот случай подсчёт назначений и пропустил бы. Это конфигурационная ошибка: она безусловно завершает прогон, независимо от --fail-on, и не может быть принята в baseline или подавлена. См. Архитектурные правила.
Потенциальное затенение architecture.potential-shadow Error (фиксированная, не настраивается) включено (срабатывает только с architecture.layers) Поиск по фактическим классам более специфичного слоя, объявленного позже более широкого и потому никогда не выигрывающего в своей области. Само по себе перекрытие не диагностируется: идиома «сначала узкое, потом широкое» вплоть до финального **-catch-all законна и молчит. Для каждой пары (assigned, shadowed) — один диагностик. Это конфигурационная ошибка: она безусловно завершает прогон, независимо от --fail-on, и не может быть принята в baseline или подавлена. Удалённой опции potential_shadow_severity больше не существует — серьёзность зафиксирована.
Пустой шаблон architecture.empty-template Error (фиксированная, не настраивается) включено (срабатывает только с шаблонными слоями) Один диагностик на каждый шаблонный слой, развернувшийся в ноль конкретных инстансов — фактически отключает привязанную к нему политику. Типичные причины: опечатка в шаблоне паттерна, все кандидаты исключены, или односегментный {var} там, где нужен {var:**}. Это конфигурационная ошибка: она безусловно завершает прогон, независимо от --fail-on, и не может быть принята в baseline или подавлена. Удалённой опции empty_template_severity больше не существует — серьёзность зафиксирована.
Покрытие слоёв architecture.coverage-gap Warning или Error (по режиму coverage-gap) выключено (coverage-gap: ignore) Один агрегированный диагностик, когда architecture.coverage-gap установлен в warn или error и анализируемые логические классы (включая изолированные классы без рёбер) либо концы рёбер зависимости находятся вне всех объявленных слоёв. Печатаемое слово соответствует настроенному режиму coverage-gap:, но это по-прежнему конфигурационная ошибка: при срабатывании она безусловно завершает прогон независимо от --fail-on и не может быть принята в baseline или подавлена. coverage-gap: ignore остаётся способом полностью отключить эту диагностику.
Неотнесённые объявления architecture.unassigned-class Warning или Error (по режиму mode) выключено (mode: ignore) Один агрегированный диагностик со счётом проанализированных class-like объявлений (классы, интерфейсы, трейты, енумы), не попавших ни в один объявленный слой. В отличие от architecture.coverage-gap концы рёбер зависимостей в счёт не входят, поэтому вендорный код, который проект классифицировать не может, в число не попадает. Метрическое значение — абсолютный счёт, поэтому текущее число можно принять в baseline и снижать постепенно. Настраивается собственной опцией mode (CLI: --unassigned-class-mode).

Правила обнаружения файлов (Discovery)

Встроенное правило discovery.unmatched-exclude сообщает о выборе файлов самим прогоном: значение --exclude или запись exclude:, не совпавшая ни с одним каталогом. Числовых порогов у него нет.

Канал Severity По умолчанию Примечания
discovery.unmatched-exclude Warning (фиксированная, ненастраиваемая) включено Обычная находка, а не ошибка конфигурации: общий конфиг может законно называть путь, которого нет в одном из репозиториев. Сообщается на уровне проекта и только на прогоне, чьи пути покрывают production-корни автозагрузки.

Правила подавления (Suppression)

Встроенное правило suppression.configuration сообщает о конфигурации подавлений самого прогона: значение suppress_paths или suppress_namespaces, глобальное или per-rule, не назвавшее ничего из того, что содержит прогон. Числовых порогов у него нет.

Канал Severity По умолчанию Примечания
suppression.unmatched-path Warning (фиксированная, не настраивается) включено Глобальное значение suppress_paths, не совпавшее ни с одним проанализированным файлом. Уровень проекта, только на прогоне, покрывающем production-корни автозагрузки; в baseline не пишется.
suppression.unmatched-namespace Warning (фиксированная, не настраивается) включено То же для suppress_namespaces против неймспейсов, объявленных прогоном.
suppression.unmatched-rule-ledger Warning (фиксированная, не настраивается) включено То же для любого из двух ключей, заданного под rules.<имя>.

Правила аннотаций

Встроенное правило annotation.directive сообщает об inline-директивах @qmx-*, которые ничего не адресуют, не могут быть применены, или больше ничего не делают. У него нет числовых порогов, оно сообщает через четыре канала, каждый — своя диагностика. Полный справочник — Правила аннотаций, а о том, как директивы взаимодействуют с подавлением и baseline — Baseline.

Канал Серьёзность По умолчанию Примечания
annotation.unresolved-directive Error (фиксированная, не настраивается) включено Конфигурационная ошибка: директива называет несуществующий канал. Безусловно завершает прогон независимо от --fail-on; не может быть принята в baseline или подавлена.
annotation.unsupported-threshold Error (фиксированная, не настраивается) включено Конфигурационная ошибка: @qmx-threshold нацелен на правило, не объявляющее поддержку override порога. Безусловно завершает прогон; не может быть принята в baseline или подавлена.
annotation.invalid-threshold Error (фиксированная, не настраивается) включено Конфигурационная ошибка: сам payload @qmx-threshold некорректен. Безусловно завершает прогон; не может быть принята в baseline или подавлена.
annotation.unused-directive Info (настраивается через unused_directive_severity) включено Обычное нарушение, не конфигурационная ошибка: директива корректна, но ничего из адресованного ею не сработало за этот прогон. Может быть принята в baseline, убрана корневым suppress_paths или сужена git-скоупом; suppress_namespaces и собственные исключения правила до неё не достают. Это единственный канал, который нельзя адресовать @qmx-ignore.

Правила запахов кода (Code Smell)

Эти правила обнаруживают конкретные паттерны, которые обычно являются плохой практикой. У большинства нет числовых порогов -- они либо находят паттерн, либо нет. Два правила (Long Parameter List и Unreachable Code) используют числовые пороги.

Правило ID Warning Error Статус
Constructor Over-injection code-smell.constructor-overinjection 8 params 12 params включено
Data Class design.data-class WOC ≤ 33%, WMC ≤ 10 включено
God Class design.god-class WMC ≥ 47, TCC < 0.33, LCOM ≥ 3, LOC ≥ 300 (3 of 4) включено
Boolean Argument code-smell.boolean-argument включено (allowed_prefixes: is, has, can, should, will, did, was; flag_promoted_properties: false)
count() in Loop code-smell.count-in-loop включено
Debug Code code-smell.debug-code всегда включено
Empty Catch code-smell.empty-catch всегда включено
Error Suppression code-smell.error-suppression всегда включено (allowed_functions: [])
eval() code-smell.eval всегда включено
exit()/die() code-smell.exit всегда включено
goto code-smell.goto всегда включено
Superglobals code-smell.superglobals всегда включено
Long Parameter List code-smell.long-parameter-list 4 params (VO: 8) 6 params (VO: 12) включено
Unreachable Code code-smell.unreachable-code 1 2 включено
Unused Private code-smell.unused-private всегда включено
Identical Sub-expression code-smell.identical-subexpression всегда включено

Правила дупликации (Duplication)

Правила, которые обнаруживают дублированный код.

Правило ID Warning Error Область
Code Duplication duplication.clone <50 строк >=50 строк Метод

Code Duplication обнаруживает дублированные блоки кода. Настраивается через min_lines: 5 и min_tokens: 70 -- блоки, не достигающие этих порогов, игнорируются. Дубликаты менее 50 строк выдают предупреждение; 50 строк и более -- ошибку.

Правила безопасности (Security)

Правила, которые обнаруживают потенциальные уязвимости безопасности.

Правило ID Серьезность По умолчанию
Hardcoded Credentials security.hardcoded-credentials Error включено
SQL Injection security.sql-injection Error включено
XSS security.xss Error включено
Command Injection security.command-injection Error включено
Sensitive Parameter security.sensitive-parameter Warning включено

Hardcoded Credentials обнаруживает пароли, API-ключи и токены, захардкоженные непосредственно в исходном коде.

SQL Injection обнаруживает использование суперглобальных переменных при построении SQL-запросов без параметризации.

XSS обнаруживает вывод суперглобальных переменных без экранирования (htmlspecialchars и т.д.).

Command Injection обнаруживает использование суперглобальных переменных в функциях выполнения команд без санитизации.

Sensitive Parameter обнаруживает параметры с чувствительными именами без атрибута #[\SensitiveParameter].

Как настроить пороговые значения

С помощью YAML-файла конфигурации

Создайте файл qmx.yaml в корне вашего проекта:

rules:
  complexity.ccn:
    callable:
      warning: 15
      error: 30
    class:
      max_warning: 40
      max_error: 60

  size.method-count:
    warning: 25
    error: 40

  coupling.cbo:
    warning: 18
    error: 25

  maintainability.mi:
    warning: 30
    error: 15

Сокращённая запись threshold

Если вам нужен единый порог без разделения на warning и error (все нарушения — ошибки), используйте ключ threshold вместо отдельных warning/error:

rules:
  complexity.ccn:
    callable:
      threshold: 15    # equivalent to warning: 15, error: 15

  size.method-count:
    threshold: 25

  coupling.cbo:
    class:
      threshold: 18

Это задаёт warning и error одним и тем же значением, так что любое нарушение на этом уровне становится ошибкой. Полезно в CI, где нужен простой бинарный результат "прошёл/не прошёл". Нельзя смешивать threshold с явными ключами warning/error в одном и том же уровне правила.

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

rules:
  design.type-coverage.param:
    threshold: 90
  design.type-coverage.return:
    threshold: 90
  design.type-coverage.property:
    threshold: 80

Вычисляемые метрики (health scores) тоже поддерживают threshold:

computed_metrics:
  health.complexity:
    threshold: 50      # score below 50 → error

Затем запустите анализ с указанием файла конфигурации:

vendor/bin/qmx check src/ --config=qmx.yaml

Отключение правил

Чтобы полностью отключить правило, установите enabled: false:

rules:
  code-smell.boolean-argument:
    enabled: false

Отключение группы правил

Вы можете отключить все правила в группе через CLI:

vendor/bin/qmx check src/ --disable-rule=code-smell.*

code-smell.* отключает всех потомков группы code-smell; голый префикс code-smell без звёздочки теперь ошибка, а не сокращение для всей группы.

Через командную строку

Переопределяйте настройки из командной строки:

vendor/bin/qmx check src/ --disable-rule=complexity.npath

Подавление отдельных нарушений

Добавьте @qmx-ignore в docblock, чтобы подавить конкретное нарушение. @qmx-ignore адресует канал, а complexity.ccn — один канал, публикующийся на двух уровнях (callable и class). Голое имя канала подавляет оба уровня; сузь его до одного через :callable или :class:

/**
 * @qmx-ignore complexity.ccn:callable
 */
function complexButNecessary(): void
{
    // ...
}

Можно также подавить все правила в группе тем же wildcard-видом:

/**
 * @qmx-ignore complexity.*
 */

Полный синтаксис селекторов — в Baseline.