-
-
Notifications
You must be signed in to change notification settings - Fork 755
/
KDocReferencesNonPublicProperty.kt
103 lines (94 loc) · 3.22 KB
/
KDocReferencesNonPublicProperty.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package io.gitlab.arturbosch.detekt.rules.documentation
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.KtClass
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isProtected
import org.jetbrains.kotlin.psi.psiUtil.isPublic
/**
* This rule will report any KDoc comments that refer to non-public properties of a class.
* Clients do not need to know the implementation details.
*
* See [Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))
*
* <noncompliant>
* /**
* * Comment
* * [prop1] - non-public property
* * [prop2] - public property
* */
* class Test {
* private val prop1 = 0
* val prop2 = 0
* }
* </noncompliant>
*
* <compliant>
* /**
* * Comment
* * [prop2] - public property
* */
* class Test {
* private val prop1 = 0
* val prop2 = 0
* }
* </compliant>
*
*/
class KDocReferencesNonPublicProperty(config: Config = Config.empty) : Rule(config) {
override val issue = Issue(
javaClass.simpleName,
Severity.Maintainability,
"KDoc comments should not refer to non-public properties.",
Debt.FIVE_MINS
)
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
val enclosingClass = property.getTopmostParentOfType<KtClass>()
val comment = enclosingClass?.docComment?.text ?: return
if (property.isNonPublicInherited() && property.isReferencedInherited(comment)) {
report(property)
}
}
private fun KtProperty.isNonPublicInherited(): Boolean {
if (!isPublic && !isProtected()) {
return true
}
var classOrObject = containingClassOrObject
while (classOrObject is KtObjectDeclaration) {
if (!classOrObject.isPublic) {
return true
}
classOrObject = classOrObject.containingClassOrObject
}
return false
}
private fun KtProperty.isReferencedInherited(comment: String): Boolean {
var qualifiedName = nameAsSafeName.asString()
var classOrObject = containingClassOrObject
while (classOrObject is KtObjectDeclaration) {
qualifiedName = "${classOrObject.nameAsSafeName.asString()}.$qualifiedName"
classOrObject = classOrObject.containingClassOrObject
}
return comment.contains("[$qualifiedName]")
}
private fun report(property: KtNamedDeclaration) {
report(
CodeSmell(
issue,
Entity.atName(property),
"The property ${property.nameAsSafeName} " +
"is non-public and should not be referenced from KDoc comments."
)
)
}
}