Make private: don't suggest if property has @JvmField annotation

#KT-27138 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-09-28 11:46:50 +03:00
committed by Mikhail Glukhikh
parent 248e09ff2c
commit c65e246e02
7 changed files with 29 additions and 13 deletions
@@ -18,9 +18,11 @@ package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.annotations.JVM_FIELD_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
fun KtModifierListOwner.addAnnotation(
@@ -73,3 +75,5 @@ fun KtAnnotated.findAnnotation(annotationFqName: FqName): KtAnnotationEntry? {
return annotationEntries.firstOrNull { entry -> context.get(BindingContext.ANNOTATION, entry)?.fqName == annotationFqName }
}
fun KtAnnotated.hasJvmFieldAnnotation(): Boolean = findAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) != null
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.hasJvmFieldAnnotation
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
@@ -277,7 +278,12 @@ fun KtDeclaration.implicitVisibility(): KtModifierKeywordToken? {
}
}
fun KtModifierListOwner.canBePrivate() = modifierList?.hasModifier(KtTokens.ABSTRACT_KEYWORD) != true
fun KtModifierListOwner.canBePrivate(): Boolean {
if (modifierList?.hasModifier(KtTokens.ABSTRACT_KEYWORD) == true) return false
if (this.isAnnotationClassPrimaryConstructor()) return false
if (this is KtProperty && this.hasJvmFieldAnnotation()) return false
return true
}
fun KtModifierListOwner.canBeProtected(): Boolean {
val parent = when (this) {
@@ -291,6 +297,11 @@ fun KtModifierListOwner.canBeProtected(): Boolean {
}
}
fun KtModifierListOwner.canBeInternal(): Boolean = !isAnnotationClassPrimaryConstructor()
private fun KtModifierListOwner.isAnnotationClassPrimaryConstructor(): Boolean =
this is KtPrimaryConstructor && (this.parent as? KtClass)?.hasModifier(KtTokens.ANNOTATION_KEYWORD) ?: false
fun KtClass.isInheritable(): Boolean {
return when (getModalityFromDescriptor()) {
KtTokens.ABSTRACT_KEYWORD, KtTokens.OPEN_KEYWORD, KtTokens.SEALED_KEYWORD -> true
@@ -22,10 +22,7 @@ import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.idea.core.canBePrivate
import org.jetbrains.kotlin.idea.core.canBeProtected
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -105,14 +102,10 @@ open class ChangeVisibilityModifierIntention protected constructor(
}
}
protected fun isAnnotationClassPrimaryConstructor(element: KtDeclaration) =
element is KtPrimaryConstructor && (element.parent as? KtClass)?.hasModifier(KtTokens.ANNOTATION_KEYWORD) ?: false
class Public : ChangeVisibilityModifierIntention(KtTokens.PUBLIC_KEYWORD), HighPriorityAction
class Private : ChangeVisibilityModifierIntention(KtTokens.PRIVATE_KEYWORD), HighPriorityAction {
override fun applicabilityRange(element: KtDeclaration): TextRange? {
if (isAnnotationClassPrimaryConstructor(element)) return null
return if (element.canBePrivate()) super.applicabilityRange(element) else null
}
}
@@ -125,8 +118,7 @@ open class ChangeVisibilityModifierIntention protected constructor(
class Internal : ChangeVisibilityModifierIntention(KtTokens.INTERNAL_KEYWORD) {
override fun applicabilityRange(element: KtDeclaration): TextRange? {
if (isAnnotationClassPrimaryConstructor(element)) return null
return super.applicabilityRange(element)
return if (element.canBeInternal()) super.applicabilityRange(element) else null
}
}
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
class Test {
@JvmField
<caret>val foo = 1
}
-1
View File
@@ -1,7 +1,6 @@
// "Add annotation target" "false"
// WITH_RUNTIME
// ACTION: Make internal
// ACTION: Make private
// ACTION: Specify type explicitly
// ACTION: Add use-site target 'property'
// ERROR: This annotation is not applicable to target 'top level property without backing field or delegate'
@@ -2,7 +2,6 @@
// WITH_RUNTIME
// ERROR: This annotation is not applicable to target 'top level property without backing field or delegate'
// ACTION: Make internal
// ACTION: Make private
// ACTION: Remove explicit type specification
// ACTION: Add use-site target 'property'
<caret>@JvmField val number: Int
@@ -3568,6 +3568,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/changeVisibility/private/hasModifier4.kt");
}
@TestMetadata("jvmField.kt")
public void testJvmField() throws Exception {
runTest("idea/testData/intentions/changeVisibility/private/jvmField.kt");
}
@TestMetadata("noModifierListAnnotation.kt")
public void testNoModifierListAnnotation() throws Exception {
runTest("idea/testData/intentions/changeVisibility/private/noModifierListAnnotation.kt");