Add intention for changing setter accessibility #KT-22409 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
7f97d58970
commit
28123eaf7b
@@ -232,7 +232,10 @@ fun KtDeclaration.implicitVisibility(): KtModifierKeywordToken? =
|
||||
fun KtModifierListOwner.canBePrivate() = modifierList?.hasModifier(KtTokens.ABSTRACT_KEYWORD) != true
|
||||
|
||||
fun KtModifierListOwner.canBeProtected(): Boolean {
|
||||
val parent = this.parent
|
||||
val parent = when (this) {
|
||||
is KtPropertyAccessor -> this.property.parent
|
||||
else -> this.parent
|
||||
}
|
||||
return when (parent) {
|
||||
is KtClassBody -> parent.parent is KtClass
|
||||
is KtParameterList -> parent.parent is KtPrimaryConstructor
|
||||
|
||||
@@ -32,30 +32,45 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
open class ChangeVisibilityModifierIntention protected constructor(
|
||||
val modifier: KtModifierKeywordToken
|
||||
val modifier: KtModifierKeywordToken
|
||||
) : SelfTargetingRangeIntention<KtDeclaration>(KtDeclaration::class.java, "Make ${modifier.value}") {
|
||||
|
||||
override fun applicabilityRange(element: KtDeclaration): TextRange? {
|
||||
val modifierList = element.modifierList
|
||||
if (modifierList?.hasModifier(modifier) ?: false) return null
|
||||
if (modifierList?.hasModifier(modifier) == true) return null
|
||||
|
||||
val descriptor = element.toDescriptor() as? DeclarationDescriptorWithVisibility ?: return null
|
||||
val targetVisibility = modifier.toVisibility()
|
||||
if (descriptor.visibility == targetVisibility) return null
|
||||
|
||||
if (modifierList?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false) {
|
||||
if (KtPsiUtil.isLocal((element as? KtPropertyAccessor)?.property ?: element)) return null
|
||||
|
||||
if (modifierList?.hasModifier(KtTokens.OVERRIDE_KEYWORD) == true) {
|
||||
val callableDescriptor = descriptor as? CallableDescriptor ?: return null
|
||||
// cannot make visibility less than (or non-comparable with) any of the supers
|
||||
if (callableDescriptor.overriddenDescriptors
|
||||
.map { Visibilities.compare(it.visibility, targetVisibility) }
|
||||
.any { it == null || it > 0 }) return null
|
||||
.any { it == null || it > 0 }) return null
|
||||
}
|
||||
|
||||
text = defaultText
|
||||
|
||||
if (element is KtPropertyAccessor) {
|
||||
if (element.isGetter) return null
|
||||
if (targetVisibility == Visibilities.PUBLIC) {
|
||||
val explicitVisibility = element.modifierList?.visibilityModifierType()?.value ?: return null
|
||||
text = "Remove '$explicitVisibility' modifier"
|
||||
} else {
|
||||
val propVisibility = (element.property.toDescriptor() as? DeclarationDescriptorWithVisibility)?.visibility ?: return null
|
||||
if (propVisibility == targetVisibility) return null
|
||||
val compare = Visibilities.compare(targetVisibility, propVisibility)
|
||||
if (compare == null || compare > 0) return null
|
||||
}
|
||||
}
|
||||
val defaultRange = noModifierYetApplicabilityRange(element) ?: return null
|
||||
|
||||
if (element is KtPrimaryConstructor && defaultRange.isEmpty && element.visibilityModifier() == null) {
|
||||
@@ -70,6 +85,7 @@ open class ChangeVisibilityModifierIntention protected constructor(
|
||||
|
||||
override fun applyTo(element: KtDeclaration, editor: Editor?) {
|
||||
element.setVisibility(modifier)
|
||||
if (element is KtPropertyAccessor) element.modifierList?.nextSibling?.replace(KtPsiFactory(element).createWhiteSpace())
|
||||
}
|
||||
|
||||
private fun KtModifierKeywordToken.toVisibility(): Visibility {
|
||||
@@ -83,13 +99,16 @@ open class ChangeVisibilityModifierIntention protected constructor(
|
||||
}
|
||||
|
||||
private fun noModifierYetApplicabilityRange(declaration: KtDeclaration): TextRange? {
|
||||
if (KtPsiUtil.isLocal(declaration)) return null
|
||||
return when (declaration) {
|
||||
is KtNamedFunction -> declaration.funKeyword?.textRange
|
||||
is KtProperty -> declaration.valOrVarKeyword.textRange
|
||||
is KtPropertyAccessor -> declaration.namePlaceholder.textRange
|
||||
is KtClass -> declaration.getClassOrInterfaceKeyword()?.textRange
|
||||
is KtObjectDeclaration -> declaration.getObjectKeyword()?.textRange
|
||||
is KtPrimaryConstructor -> declaration.valueParameterList?.let { TextRange.from(it.startOffset, 0) } //TODO: use constructor keyword if exist
|
||||
is KtPrimaryConstructor -> declaration.valueParameterList?.let {
|
||||
//TODO: use constructor keyword if exist
|
||||
TextRange.from(it.startOffset, 0)
|
||||
}
|
||||
is KtSecondaryConstructor -> declaration.getConstructorKeyword().textRange
|
||||
is KtParameter -> declaration.valOrVarKeyword?.textRange
|
||||
is KtTypeAlias -> declaration.getTypeAliasKeyword()?.textRange
|
||||
@@ -97,7 +116,8 @@ open class ChangeVisibilityModifierIntention protected constructor(
|
||||
}
|
||||
}
|
||||
|
||||
protected fun isAnnotationClassPrimaryConstructor(element: KtDeclaration) = element is KtPrimaryConstructor && (element.parent as? KtClass)?.hasModifier(KtTokens.ANNOTATION_KEYWORD) ?: false
|
||||
protected fun isAnnotationClassPrimaryConstructor(element: KtDeclaration) =
|
||||
element is KtPrimaryConstructor && (element.parent as? KtClass)?.hasModifier(KtTokens.ANNOTATION_KEYWORD) ?: false
|
||||
|
||||
class Public : ChangeVisibilityModifierIntention(KtTokens.PUBLIC_KEYWORD), HighPriorityAction
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>internal set
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
class Test {
|
||||
private var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>get() = ""
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>private set
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
internal var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
internal var foo: String = ""
|
||||
<caret>private set
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
class Test {
|
||||
private var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
protected var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
protected var foo: String = ""
|
||||
<caret>private set
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
fun test() {
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>protected set
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
class Test {
|
||||
private var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// INTENTION_TEXT: Remove 'private' modifier
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>private set
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// INTENTION_TEXT: Remove 'private' modifier
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// INTENTION_TEXT: Remove 'private' modifier
|
||||
class Test {
|
||||
private var foo: String = ""
|
||||
<caret>private set
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// INTENTION_TEXT: Remove 'private' modifier
|
||||
class Test {
|
||||
private var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
class Test {
|
||||
var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
class Test {
|
||||
private var foo: String = ""
|
||||
<caret>set
|
||||
}
|
||||
@@ -2813,6 +2813,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetter.kt")
|
||||
public void testPropertySetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/internal/propertySetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterForPrivateProperty.kt")
|
||||
public void testPropertySetterForPrivateProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/internal/propertySetterForPrivateProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/internal/simple.kt");
|
||||
@@ -2966,6 +2978,42 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyGetter.kt")
|
||||
public void testPropertyGetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/propertyGetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetter.kt")
|
||||
public void testPropertySetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/propertySetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterForInternalProperty.kt")
|
||||
public void testPropertySetterForInternalProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/propertySetterForInternalProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterForPrivateProperty.kt")
|
||||
public void testPropertySetterForPrivateProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/propertySetterForPrivateProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterForProtectedProperty.kt")
|
||||
public void testPropertySetterForProtectedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/propertySetterForProtectedProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterInLocalClass.kt")
|
||||
public void testPropertySetterInLocalClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/propertySetterInLocalClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/private/simple.kt");
|
||||
@@ -3029,6 +3077,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetter.kt")
|
||||
public void testPropertySetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/protected/propertySetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterForPrivateProperty.kt")
|
||||
public void testPropertySetterForPrivateProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/protected/propertySetterForPrivateProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/protected/simple.kt");
|
||||
@@ -3068,6 +3128,30 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyPrivateSetter.kt")
|
||||
public void testPropertyPrivateSetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/propertyPrivateSetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyPrivateSetterForPrivateProperty.kt")
|
||||
public void testPropertyPrivateSetterForPrivateProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/propertyPrivateSetterForPrivateProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetter.kt")
|
||||
public void testPropertySetter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/propertySetter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertySetterForPrivateProperty.kt")
|
||||
public void testPropertySetterForPrivateProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/propertySetterForPrivateProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("publicByDefault.kt")
|
||||
public void testPublicByDefault() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/publicByDefault.kt");
|
||||
|
||||
Reference in New Issue
Block a user