From dfd1966dfad7f836c15c6ddb3f7e66a6aa37a3dd Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Mon, 7 Feb 2022 02:59:25 -0600 Subject: [PATCH] update InvalidPackageDeclaration to report if rootPackage is not present (#4484) --- .../main/resources/default-detekt-config.yml | 1 + .../rules/naming/InvalidPackageDeclaration.kt | 20 +++++++--- .../naming/InvalidPackageDeclarationSpec.kt | 38 +++++++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/detekt-core/src/main/resources/default-detekt-config.yml b/detekt-core/src/main/resources/default-detekt-config.yml index e5f4d9463c9..29c8bca2dec 100644 --- a/detekt-core/src/main/resources/default-detekt-config.yml +++ b/detekt-core/src/main/resources/default-detekt-config.yml @@ -316,6 +316,7 @@ naming: InvalidPackageDeclaration: active: false rootPackage: '' + requireRootInDeclaration: false LambdaParameterNaming: active: false parameterPattern: '[a-z][A-Za-z0-9]*|_' diff --git a/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclaration.kt b/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclaration.kt index 1b6ff531c4d..2f39e898702 100644 --- a/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclaration.kt +++ b/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclaration.kt @@ -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 @@ -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 Iterable.toNormalizedForm() = joinToString("|") private fun packageNameToNormalizedForm(packageName: String) = packageName.split('.').toNormalizedForm() diff --git a/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclarationSpec.kt b/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclarationSpec.kt index 4b2475fa21f..1ca90358255 100644 --- a/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclarationSpec.kt +++ b/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/InvalidPackageDeclarationSpec.kt @@ -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({ @@ -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 @@ -106,6 +108,42 @@ 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 ktFileWithRelativePath = compileContentForTest(source, createPath("src/foo/bar/File.kt")) + val findingsForRelativePath = InvalidPackageDeclaration(config).lint(ktFileWithRelativePath) + + assertThat(findingsForRelativePath).isEmpty() + + val ktFileWithFullPath = compileContentForTest(source, createPath("src/com/example/foo/bar/File.kt")) + val findingsForFullPath = InvalidPackageDeclaration(config).lint(ktFileWithFullPath) + + assertThat(findingsForFullPath).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) + } + } } })