Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ dependencies {
implementation(project(":core:network-impl"))

detektPlugins(libs.detekt.formatting)
detektPlugins(project(":detekt-rules"))

implementation(project(":feature:example-home:api"))
implementation(project(":feature:example-profile:api"))
Expand Down
1 change: 1 addition & 0 deletions detekt-rules/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
19 changes: 19 additions & 0 deletions detekt-rules/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
plugins {
id("java-library")
alias(libs.plugins.jvm)
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

dependencies {
implementation(libs.detekt.api)
compileOnly(libs.kotlin.compiler.embeddable)
}

kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ru.yeahub.rules

import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.RuleSet
import io.gitlab.arturbosch.detekt.api.RuleSetProvider

class CustomRuleSetProvider : RuleSetProvider {

override val ruleSetId: String = "yeahub"

override fun instance(config: Config): RuleSet {
return RuleSet(
id = ruleSetId,
rules = listOf(NoNotNullAssertionRule(config))
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ru.yeahub.rules

import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.Debt
import io.gitlab.arturbosch.detekt.api.Entity
import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import org.jetbrains.kotlin.psi.KtUnaryExpression

class NoNotNullAssertionRule(config: Config = Config.Companion.empty) : Rule(config) {

init {
println(">>> NoNotNullAssertionRule: ПРАВИЛО ЗАГРУЖЕНО! <<<")
}

override val issue = Issue(
"NoNotNullAssertionRule",
Severity.Style,
"Оператор !! запрещён. Используйте безопасные вызовы (.?) или элвис-оператор (?:).",

@Yrun00 Yrun00 Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Предлагаю расширить формулировку - замена !! на ?. или ?: не всегда корректна, потому что в местах с обязательным контрактом это может скрыть ошибку дефолтным значением или невыполнением кода. Лучше явно разрешить fail-fast варианты: requireNotNull для проверки входных аргументов и checkNotNull для проверки внутренних инвариантов/состояния. Тогда мы не теряем понятное падение там, где null означает баг в коде.

(понятно, что текущая подсказка их не запрещает - но может сложиться впечатление что разрешены только ?: и .?)

Или добавить подсказку, что для явных fail-fast вариантов можно использовать ?: error("error text") - мне было не очевидно что ?: возможно применять и таким образом.

Debt.Companion.FIVE_MINS
)

override fun visitUnaryExpression(expression: KtUnaryExpression) {
val operatorText = expression.operationReference.text
if (operatorText == "!!") {
report(
CodeSmell(
issue,
Entity.Companion.from(expression),
message = "Использование оператора !! запрещено"
)
)
}
super.visitUnaryExpression(expression)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ru.yeahub.rules.CustomRuleSetProvider
6 changes: 5 additions & 1 deletion detekt-setting/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ complexity:
LongMethod:
active: false
TooManyFunctions:
active: false
active: false

yeahub:
NoNotNullAssertionRule:
active: true
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ kotlin = "2.0.21"
coreKtx = "1.10.1"
junit = "5.8.2"
junitPlatformLauncher = "1.8.2"
kotlinCompilerEmbeddable = "2.0.21"
lifecycleRuntimeCompose = "2.7.0"
mockk = "1.14.2"
espressoCore = "3.5.1"
Expand Down Expand Up @@ -47,6 +48,8 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
detekt-api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "detekt" }
kotlin-compiler-embeddable = { module = "org.jetbrains.kotlin:kotlin-compiler-embeddable", version.ref = "kotlinCompilerEmbeddable" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ include(":feature:public-collections:api")
include(":feature:questions-or-collections")
include(":feature:questions-or-collections:api")
include(":feature:questions-or-collections:impl")

include(":detekt-rules")
Loading