Repository: detekt/detekt (kotlin)

Issue:
False negative for enum constants in UndocumentedPublic* rule group
## Steps to Reproduce
```kotlin
public enum class PublicEnum {
	Foo,
	Bar,
}
```

Configuration:
```gradle.kts
detekt.allRules = true
// Does not contain relevant lines, just a few rules deactivated or fine tuned.
detekt.config.from(rootProject.file("config/detekt/detekt.yml"))
dependencies { detektPlugins(libs.detekt.rules.libraries) }
```

## Observed Behavior
```console
src\main\kotlin\com\example\PublicEnum.kt:21:15: PublicEnum is missing required documentation. [UndocumentedPublicClass]
```

## Expected Behavior
Findings for each of the undocumented enum constants. They're public API as well, accessible as `PublicEnum.Foo`.
If
```kotlin
public companion object {
    public val Foo: PublicClass = ...
}
```
needs to be documented (`The property Foo is missing documentation. [UndocumentedPublicProperty]`), so does these enum constants `Foo` and `Bar` as they're essentially "just syntactic a shorthand" for the same.

## Context
I'm relying on detekt to ensure that all my public API surface is documented.

This repro might be a trivial case, but imagine an enum with 10-12 values, and no documentation.

 * Related: https://github.com/detekt/detekt/issues/7217

## Your Environment
* Version of detekt used: 1.23.5
* Version of Gradle used (if applicable): 8.7
* Gradle scan link (add `--scan` option when running the gradle task): N/A
* Operating System and version: Windows 10 / GitHub Actions Ubuntu 22.04
* Link to your project (if it's a public repository): N/A

Pull request:
Fixes https://github.com/detekt/detekt/issues/7218

Patch:
diff --git a/detekt-rules-documentation/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicProperty.kt b/detekt-rules-documentation/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicProperty.kt
index e306469b83f6..adcd1a5688f5 100644
--- a/detekt-rules-documentation/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicProperty.kt
+++ b/detekt-rules-documentation/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicProperty.kt
@@ -8,6 +8,7 @@ import io.gitlab.arturbosch.detekt.api.Rule
 import io.gitlab.arturbosch.detekt.api.config
 import io.gitlab.arturbosch.detekt.rules.documentation.internal.isPublicInherited
 import io.gitlab.arturbosch.detekt.rules.isPublicNotOverridden
+import org.jetbrains.kotlin.psi.KtEnumEntry
 import org.jetbrains.kotlin.psi.KtNamedDeclaration
 import org.jetbrains.kotlin.psi.KtPrimaryConstructor
 import org.jetbrains.kotlin.psi.KtProperty
@@ -46,6 +47,13 @@ class UndocumentedPublicProperty(config: Config) : Rule(
         super.visitProperty(property)
     }
 
+    override fun visitEnumEntry(enumEntry: KtEnumEntry) {
+        super.visitEnumEntry(enumEntry)
+        if (enumEntry.isPublicInherited(searchProtectedProperty) && enumEntry.docComment == null) {
+            report(enumEntry)
+        }
+    }
+
     private fun KtNamedDeclaration.isUndocumented(comment: String?) =
         comment == null || isNotReferenced(comment)
 


Test patch:
diff --git a/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicClassSpec.kt b/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicClassSpec.kt
index 56cde6318e80..e306308459ed 100644
--- a/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicClassSpec.kt
+++ b/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicClassSpec.kt
@@ -4,6 +4,7 @@ import io.gitlab.arturbosch.detekt.api.Config
 import io.gitlab.arturbosch.detekt.test.TestConfig
 import io.gitlab.arturbosch.detekt.test.compileAndLint
 import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.Nested
 import org.junit.jupiter.api.Test
 
 private const val SEARCH_IN_NESTED_CLASS = "searchInNestedClass"
@@ -199,27 +200,6 @@ class UndocumentedPublicClassSpec {
         assertThat(subject.compileAndLint(code)).isEmpty()
     }
 
-    @Test
-    fun `should report for enum classes`() {
-        val code = """
-            enum class Enum {
-                CONSTANT
-            }
-        """.trimIndent()
-        assertThat(subject.compileAndLint(code)).hasSize(1)
-    }
-
-    @Test
-    fun `should not report for enum constants`() {
-        val code = """
-            /** Some doc */
-            enum class Enum {
-                CONSTANT
-            }
-        """.trimIndent()
-        assertThat(subject.compileAndLint(code)).isEmpty()
-    }
-
     @Test
     fun `should not report for fun interfaces`() {
         val code = """
@@ -302,4 +282,48 @@ class UndocumentedPublicClassSpec {
         """.trimIndent()
         assertThat(subject.compileAndLint(code)).hasSize(2)
     }
+
+    @Nested
+    inner class `enum classes` {
+        @Test
+        fun `does not report documented enum class in public enum`() {
+            val code = """
+                /**
+                * This is PublicEnum
+                */
+                enum class PublicEnum {
+                    Foo,
+                    Bar,
+                }
+            """.trimIndent()
+            io.gitlab.arturbosch.detekt.test.assertThat(subject.compileAndLint(code)).isEmpty()
+        }
+
+        @Test
+        fun `does report undocumented enum class in public enum`() {
+            val code = """
+                enum class PublicEnum {
+                    Foo,
+                    Bar,
+                }
+            """.trimIndent()
+            io.gitlab.arturbosch.detekt.test.assertThat(subject.compileAndLint(code)).hasSize(1)
+        }
+
+        @Test
+        fun `does not report undocumented enum entries in private and internal enum`() {
+            val code = """
+                private enum class PrivateEnum {
+                    Foo,
+                    Bar,
+                }
+
+                internal enum class InternalEnum {
+                    Foo,
+                    Bar,
+                }
+            """.trimIndent()
+            io.gitlab.arturbosch.detekt.test.assertThat(subject.compileAndLint(code)).isEmpty()
+        }
+    }
 }
diff --git a/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicPropertySpec.kt b/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicPropertySpec.kt
index 88834790b728..d96d3c27d989 100644
--- a/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicPropertySpec.kt
+++ b/detekt-rules-documentation/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicPropertySpec.kt
@@ -433,4 +433,63 @@ class UndocumentedPublicPropertySpec {
             assertThat(subject.compileAndLint(code)).isEmpty()
         }
     }
+
+    @Nested
+    inner class `enum entries` {
+        @Test
+        fun `does report undocumented enum entries in public enum`() {
+            val code = """
+                /**
+                * This is PublicEnum
+                */
+                enum class PublicEnum {
+                    Foo,
+                    Bar,
+                }
+            """.trimIndent()
+            assertThat(subject.compileAndLint(code)).hasSize(2)
+        }
+
+        @Test
+        fun `does not report documented enum entries in public enum`() {
+            val code = """
+                /**
+                * This is PublicEnum
+                */
+                enum class PrivateEnum {
+                    /**
+                    * This is For
+                    */
+                    Foo,
+                    /**
+                    * This is Bar
+                    */
+                    Bar,
+                }
+            """.trimIndent()
+            assertThat(subject.compileAndLint(code)).isEmpty()
+        }
+
+        @Test
+        fun `does not report undocumented enum entries in private and internal enum`() {
+            val code = """
+                /**
+                * This is PrivateEnum
+                */
+                private enum class PrivateEnum {
+                    Foo,
+                    Bar,
+                }
+
+                /**
+                * This is InternalEnum
+                */
+                internal enum class InternalEnum {
+                    Foo,
+                    Bar,
+                }
+            """.trimIndent()
+            assertThat(subject.compileAndLint(code)).isEmpty()
+        }
+    }
 }