Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update InvalidPackageDeclaration to report if rootPackage is not present #4484

Merged
merged 5 commits into from Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions detekt-core/src/main/resources/default-detekt-config.yml
Expand Up @@ -456,6 +456,7 @@ naming:
InvalidPackageDeclaration:
active: false
rootPackage: ''
requireRootInDeclaration: false
LambdaParameterNaming:
active: false
parameterPattern: '[a-z][A-Za-z0-9]*|_'
Expand Down
Expand Up @@ -28,12 +28,20 @@ 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("")

@Configuration("requires the declaration to start with the specified rootPackage")
private val requireRootInDeclaration : Boolean by config(false)

override fun visitPackageDirective(directive: KtPackageDirective) {
super.visitPackageDirective(directive)
val declaredPath = directive.packageNames.map(KtElement::getText).toNormalizedForm()
if (declaredPath.isNotBlank()) {
val normalizedFilePath = directive.containingKtFile.absolutePath().parent.toNormalizedForm()
val normalizedRootPackage = packageNameToNormalizedForm(rootPackage)
if (requireRootInDeclaration && !declaredPath.startsWith(normalizedRootPackage)) {
directive.reportInvalidPackageDeclaration("The package declaration is missing the root package")
return
}

val expectedPath =
if (normalizedRootPackage.isBlank()) {
declaredPath
Expand All @@ -43,17 +51,17 @@ class InvalidPackageDeclaration(config: Config = Config.empty) : Rule(config) {

val isInRootPackage = expectedPath.isBlank()
if (!isInRootPackage && !normalizedFilePath.endsWith(expectedPath)) {
report(
CodeSmell(
issue,
Entity.from(directive),
"The package declaration does not match the actual file location.",
)
directive.reportInvalidPackageDeclaration(
"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()
Expand Down
Expand Up @@ -10,6 +10,7 @@ import java.nio.file.FileSystems
import java.nio.file.Paths

private const val ROOT_PACKAGE = "rootPackage"
private const val REQUIRE_ROOT_PACKAGE = "requireRootInDeclaration"

internal class InvalidPackageDeclarationSpec : Spek({

Expand Down Expand Up @@ -93,6 +94,7 @@ internal class InvalidPackageDeclarationSpec : Spek({

assertThat(findings).hasSize(1)
}

it("should report if file path matches root package but package declaration differs") {
val source = """
package io.foo.bar
Expand All @@ -106,6 +108,37 @@ internal class InvalidPackageDeclarationSpec : Spek({
assertThat(findings).hasSize(1)
}
}

describe("with root package required") {

val config by memoized { TestConfig(mapOf(ROOT_PACKAGE to "com.example", REQUIRE_ROOT_PACKAGE to true)) }

it("should pass if declaration starts with root package") {
val source = """
package com.example.foo.bar

class C
"""

val ktFile = compileContentForTest(source, createPath("src/foo/bar/File.kt"))
mateot1 marked this conversation as resolved.
Show resolved Hide resolved
val findings = InvalidPackageDeclaration(config).lint(ktFile)

assertThat(findings).isEmpty()
}

it("should report if root package is missing") {
val source = """
package foo.bar

class C
"""

val ktFile = compileContentForTest(source, createPath("src/foo/bar/File.kt"))
val findings = InvalidPackageDeclaration(config).lint(ktFile)

assertThat(findings).hasSize(1)
}
}
}
})

Expand Down