Split InvalidPackageDeclaration to create MissingPackageDeclaration (#4149)

This commit is contained in:
Brais Gabín
2021-10-16 00:36:04 +02:00
committed by GitHub
parent 7f381a6fc2
commit 63dc501b8c
7 changed files with 85 additions and 31 deletions

View File

@@ -447,7 +447,6 @@ naming:
ignoreOverridden: true
InvalidPackageDeclaration:
active: false
excludes: ['**/*.kts']
rootPackage: ''
MatchingDeclarationName:
active: true
@@ -556,6 +555,9 @@ potential-bugs:
ignoreOnClassesPattern: ''
MapGetWithNotNullAssertionOperator:
active: false
MissingPackageDeclaration:
active: false
excludes: ['**/*.kts']
MissingWhenCase:
active: true
allowElseExpression: true

View File

@@ -48,7 +48,7 @@ private object TestExclusions : Exclusions() {
private object KotlinScriptExclusions : Exclusions() {
override val pattern = "['**/*.kts']"
override val rules = setOf("InvalidPackageDeclaration")
override val rules = setOf("MissingPackageDeclaration")
}
private object LibraryExclusions : Exclusions() {

View File

@@ -0,0 +1,38 @@
package io.gitlab.arturbosch.detekt.rules.bugs
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.KtFile
import org.jetbrains.kotlin.psi.KtPackageDirective
/**
* Reports when the package declaration is missing.
*/
class MissingPackageDeclaration(config: Config = Config.empty) : Rule(config) {
override val issue = Issue(
javaClass.simpleName,
Severity.Maintainability,
"Kotlin source files should define a package",
debt = Debt.FIVE_MINS
)
private var packageDeclaration: KtPackageDirective? = null
override fun visitPackageDirective(directive: KtPackageDirective) {
super.visitPackageDirective(directive)
packageDeclaration = directive
}
override fun postVisit(root: KtFile) {
super.postVisit(root)
if (packageDeclaration?.text.isNullOrBlank()) {
report(CodeSmell(issue, Entity.from(root), "The file does not contain a package declaration."))
}
}
}

View File

@@ -32,6 +32,7 @@ class PotentialBugProvider : DefaultRuleSetProvider {
IteratorNotThrowingNoSuchElementException(config),
LateinitUsage(config),
MapGetWithNotNullAssertionOperator(config),
MissingPackageDeclaration(config),
MissingWhenCase(config),
RedundantElseInWhen(config),
UnconditionalJumpStatementInLoop(config),

View File

@@ -0,0 +1,31 @@
package io.gitlab.arturbosch.detekt.rules.bugs
import io.gitlab.arturbosch.detekt.test.assertThat
import io.gitlab.arturbosch.detekt.test.compileAndLint
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
internal class MissingPackageDeclarationSpec : Spek({
describe("MissingPackageDeclaration rule") {
it("should pass if package declaration is declared") {
val code = """
package foo.bar
class C
"""
val findings = MissingPackageDeclaration().compileAndLint(code)
assertThat(findings).isEmpty()
}
it("should report if package declaration is missing") {
val code = "class C"
val findings = MissingPackageDeclaration().compileAndLint(code)
assertThat(findings).hasSize(1)
}
}
})

View File

@@ -11,11 +11,10 @@ import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.config
import io.gitlab.arturbosch.detekt.api.internal.Configuration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPackageDirective
/**
* Reports when the package declaration is missing or the file location does not match the declared package.
* Reports when the file location does not match the declared package.
*/
class InvalidPackageDeclaration(config: Config = Config.empty) : Rule(config) {
@@ -29,21 +28,11 @@ class InvalidPackageDeclaration(config: Config = Config.empty) : Rule(config) {
@Configuration("if specified this part of the package structure is ignored")
private val rootPackage: String by config("")
private var packageDeclaration: KtPackageDirective? = null
override fun visitPackageDirective(directive: KtPackageDirective) {
super.visitPackageDirective(directive)
packageDeclaration = directive
}
override fun postVisit(root: KtFile) {
super.postVisit(root)
val packageDeclaration = packageDeclaration
val declaredPath = packageDeclaration?.packageNames?.map(KtElement::getText)?.toNormalizedForm()
if (declaredPath.isNullOrBlank()) {
root.reportInvalidPackageDeclaration("The file does not contain a package declaration.")
} else {
val normalizedFilePath = root.absolutePath().parent.toNormalizedForm()
val declaredPath = directive.packageNames.map(KtElement::getText).toNormalizedForm()
if (declaredPath.isNotBlank()) {
val normalizedFilePath = directive.containingKtFile.absolutePath().parent.toNormalizedForm()
val normalizedRootPackage = packageNameToNormalizedForm(rootPackage)
val expectedPath =
if (normalizedRootPackage.isBlank()) {
@@ -54,16 +43,17 @@ class InvalidPackageDeclaration(config: Config = Config.empty) : Rule(config) {
val isInRootPackage = expectedPath.isBlank()
if (!isInRootPackage && !normalizedFilePath.endsWith(expectedPath)) {
packageDeclaration
.reportInvalidPackageDeclaration("The package declaration does not match the actual file location.")
report(
CodeSmell(
issue,
Entity.from(directive),
"The package declaration does not match the actual file location.",
)
)
}
}
}
private fun KtElement.reportInvalidPackageDeclaration(message: String) {
report(CodeSmell(issue, Entity.from(this), message))
}
private fun <T> Iterable<T>.toNormalizedForm() = joinToString("|")
private fun packageNameToNormalizedForm(packageName: String) = packageName.split('.').toNormalizedForm()

View File

@@ -28,14 +28,6 @@ internal class InvalidPackageDeclarationSpec : Spek({
assertThat(findings).isEmpty()
}
it("should report if package declaration is missing") {
val ktFile = compileContentForTest("class C")
val findings = InvalidPackageDeclaration().lint(ktFile)
assertThat(findings).hasSize(1)
}
it("should report if package declaration does not match source location") {
val source = "package foo\n\nclass C"