Do not report "can be private" on effectively private / local elements

So #KT-18822 Fixed
This commit is contained in:
Toshiaki Kameyama
2017-07-28 13:44:58 +09:00
committed by Mikhail Glukhikh
parent 05ea99441f
commit be0b01a1e6
4 changed files with 119 additions and 47 deletions
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.descriptors
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.*
@@ -26,6 +26,9 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiSearchHelper
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.effectiveVisibility
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.core.isInheritable
import org.jetbrains.kotlin.idea.core.isOverridable
@@ -58,22 +61,27 @@ class MemberVisibilityCanPrivateInspection : AbstractKotlinInspection() {
override fun visitParameter(parameter: KtParameter) {
super.visitParameter(parameter)
if (parameter.isConstructorDeclaredProperty()) {
if ((parameter.ownerFunction?.parent as? KtClass)?.isPrivate() == true) return
if (canBePrivate(parameter)) registerProblem(holder, parameter)
if (parameter.isConstructorDeclaredProperty() && canBePrivate(parameter)) {
registerProblem(holder, parameter)
}
}
}
}
private fun canBePrivate(declaration: KtNamedDeclaration): Boolean {
if (declaration.hasModifier(KtTokens.PRIVATE_KEYWORD) || declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
val descriptor = (declaration.toDescriptor() as? DeclarationDescriptorWithVisibility) ?: return false
when (descriptor.effectiveVisibility()) {
EffectiveVisibility.Private, EffectiveVisibility.Local -> return false
}
val classOrObject = declaration.containingClassOrObject ?: return false
val inheritable = classOrObject is KtClass && classOrObject.isInheritable()
if (!inheritable && declaration.hasModifier(KtTokens.PROTECTED_KEYWORD)) return false //reported by ProtectedInFinalInspection
if (declaration.isOverridable()) return false
if (declaration.toDescriptor()?.hasJvmFieldAnnotation() != false) return false
if (descriptor.hasJvmFieldAnnotation()) return false
val psiSearchHelper = PsiSearchHelper.SERVICE.getInstance(declaration.project)
val useScope = declaration.useScope
@@ -72,42 +72,6 @@
<description>Property 'c' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>109</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can have 'private' visibility</problem_class>
<description>Property 'a' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>110</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can have 'private' visibility</problem_class>
<description>Property 'b' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>114</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can have 'private' visibility</problem_class>
<description>Function 'f1' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>115</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can have 'private' visibility</problem_class>
<description>Function 'f2' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>135</line>
@@ -116,4 +80,49 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Can have 'private' visibility</problem_class>
<description>Property 'bar' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>180</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Class member can have 'private' visibility</problem_class>
<description>Property 'a' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>181</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Class member can have 'private' visibility</problem_class>
<description>Property 'b' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>182</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Class member can have 'private' visibility</problem_class>
<description>Function 'c' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>190</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Class member can have 'private' visibility</problem_class>
<description>Property 'b' can be private</description>
</problem>
<problem>
<file>test.kt</file>
<line>191</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Class member can have 'private' visibility</problem_class>
<description>Function 'c' can be private</description>
</problem>
</problems>
@@ -137,15 +137,71 @@ class G(val bar: Int) {
}
private class H(val a: String = "",
var b: String = "",
internal val c: String = "",
protected val d: String = "",
private val e: String = "") {
var b: String = "",
internal val c: String = "",
protected val d: String = "",
private val e: String = "") {
var f: String = ""
fun g(): String = ""
fun foo() {
println(a)
println(b)
println(c)
println(d)
println(e)
println(f)
println(g())
}
}
}
private class I {
class NestedCls(val a: String) {
var b: String = ""
fun c(): String = ""
fun foo() {
println(a)
println(b)
println(c())
}
}
object NestedObj {
var b: String = ""
fun c(): String = ""
fun foo() {
println(b)
println(c())
}
}
}
class J {
class NestedCls(val a: String) {
var b: String = ""
fun c(): String = ""
fun foo() {
println(a)
println(b)
println(c())
}
}
object NestedObj {
var b: String = ""
fun c(): String = ""
fun foo() {
println(b)
println(c())
}
}
}
fun withLocal(): Int {
class Local(val x: Int) {
val y = x
fun res() = x + y
}
val local = Local(42)
return local.res()
}