Do not insert explicit visibility modifier if it's default

This commit is contained in:
Valentin Kipyatkov
2015-09-14 21:41:02 +03:00
parent 8ba7f2c238
commit 1ccbda6af4
22 changed files with 102 additions and 61 deletions
@@ -22,7 +22,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.JetNodeTypes; import org.jetbrains.kotlin.JetNodeTypes;
import org.jetbrains.kotlin.kdoc.psi.api.KDoc; import org.jetbrains.kotlin.kdoc.psi.api.KDoc;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.addRemoveModifier.AddRemoveModifierPackage; import org.jetbrains.kotlin.psi.addRemoveModifier.AddRemoveModifierPackage;
import org.jetbrains.kotlin.psi.findDocComment.FindDocCommentPackage; import org.jetbrains.kotlin.psi.findDocComment.FindDocCommentPackage;
@@ -48,7 +47,7 @@ abstract class JetDeclarationImpl extends JetExpressionImpl implements JetDeclar
@Override @Override
public void addModifier(@NotNull JetModifierKeywordToken modifier) { public void addModifier(@NotNull JetModifierKeywordToken modifier) {
AddRemoveModifierPackage.addModifier(this, modifier, JetTokens.DEFAULT_VISIBILITY_KEYWORD); AddRemoveModifierPackage.addModifier(this, modifier);
} }
@Override @Override
@@ -22,7 +22,6 @@ import com.intellij.psi.stubs.StubElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.addRemoveModifier.AddRemoveModifierPackage; import org.jetbrains.kotlin.psi.addRemoveModifier.AddRemoveModifierPackage;
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
@@ -52,7 +51,7 @@ public class JetModifierListOwnerStub<T extends StubElement<?>> extends JetEleme
@Override @Override
public void addModifier(@NotNull JetModifierKeywordToken modifier) { public void addModifier(@NotNull JetModifierKeywordToken modifier) {
AddRemoveModifierPackage.addModifier(this, modifier, JetTokens.DEFAULT_VISIBILITY_KEYWORD); AddRemoveModifierPackage.addModifier(this, modifier);
} }
@Override @Override
@@ -39,7 +39,7 @@ public class JetPrimaryConstructor : JetConstructor<JetPrimaryConstructor> {
override fun addModifier(modifier: JetModifierKeywordToken) { override fun addModifier(modifier: JetModifierKeywordToken) {
val modifierList = modifierList val modifierList = modifierList
if (modifierList != null) { if (modifierList != null) {
addModifier(modifierList, modifier, JetTokens.PUBLIC_KEYWORD) addModifier(modifierList, modifier)
if (this.modifierList == null) { if (this.modifierList == null) {
getConstructorKeyword()?.delete() getConstructorKeyword()?.delete()
} }
@@ -33,14 +33,13 @@ private fun createModifierList(text: String, owner: JetModifierListOwner): JetMo
return owner.addBefore(newModifierList, anchor) as JetModifierList return owner.addBefore(newModifierList, anchor) as JetModifierList
} }
internal fun addModifier(owner: JetModifierListOwner, modifier: JetModifierKeywordToken, defaultVisibilityModifier: JetModifierKeywordToken) { internal fun addModifier(owner: JetModifierListOwner, modifier: JetModifierKeywordToken) {
val modifierList = owner.modifierList val modifierList = owner.modifierList
if (modifierList == null) { if (modifierList == null) {
if (modifier == defaultVisibilityModifier) return
createModifierList(modifier.value, owner) createModifierList(modifier.value, owner)
} }
else { else {
addModifier(modifierList, modifier, defaultVisibilityModifier) addModifier(modifierList, modifier)
} }
} }
@@ -54,7 +53,7 @@ internal fun addAnnotationEntry(owner: JetModifierListOwner, annotationEntry: Je
} }
} }
internal fun addModifier(modifierList: JetModifierList, modifier: JetModifierKeywordToken, defaultVisibilityModifier: JetModifierKeywordToken) { internal fun addModifier(modifierList: JetModifierList, modifier: JetModifierKeywordToken) {
if (modifierList.hasModifier(modifier)) return if (modifierList.hasModifier(modifier)) return
val newModifier = JetPsiFactory(modifierList).createModifier(modifier) val newModifier = JetPsiFactory(modifierList).createModifier(modifier)
@@ -63,15 +62,6 @@ internal fun addModifier(modifierList: JetModifierList, modifier: JetModifierKey
?.filterNotNull() ?.filterNotNull()
?.firstOrNull() ?.firstOrNull()
if (modifier == defaultVisibilityModifier) { // do not insert explicit 'internal' keyword (or 'public' for primary constructor)
//TODO: code style option
modifierToReplace?.delete()
if (modifierList.firstChild == null) {
modifierList.delete()
}
return
}
if (modifierToReplace != null) { if (modifierToReplace != null) {
modifierToReplace.replace(newModifier) modifierToReplace.replace(newModifier)
} }
@@ -25,6 +25,7 @@ import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.stubs.StubElement import com.intellij.psi.stubs.StubElement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.JetNodeTypes import org.jetbrains.kotlin.JetNodeTypes
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -394,3 +395,10 @@ public fun JetFunctionLiteralArgument.getFunctionLiteralArgumentName(bindingCont
public fun JetExpression.asAssignment(): JetBinaryExpression? = public fun JetExpression.asAssignment(): JetBinaryExpression? =
if (JetPsiUtil.isAssignment(this)) this as JetBinaryExpression else null if (JetPsiUtil.isAssignment(this)) this as JetBinaryExpression else null
public fun JetDeclaration.visibilityModifier(): PsiElement? {
val modifierList = modifierList ?: return null
return JetTokens.VISIBILITY_MODIFIERS.types
.asSequence()
.map { modifierList.getModifier(it as JetModifierKeywordToken) }
.firstOrNull { it != null }
}
@@ -465,7 +465,7 @@ public class OverridingUtil {
} }
@Nullable @Nullable
private static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) { public static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
if (descriptors.isEmpty()) { if (descriptors.isEmpty()) {
return Visibilities.DEFAULT_VISIBILITY; return Visibilities.DEFAULT_VISIBILITY;
} }
@@ -20,13 +20,19 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getFunctionLiteralArgumentName import org.jetbrains.kotlin.psi.psiUtil.getFunctionLiteralArgumentName
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <reified T: PsiElement> PsiElement.replaced(newElement: T): T { public inline fun <reified T: PsiElement> PsiElement.replaced(newElement: T): T {
@@ -153,4 +159,34 @@ public fun PsiElement.deleteSingle() {
public fun JetClass.getOrCreateCompanionObject() : JetObjectDeclaration { public fun JetClass.getOrCreateCompanionObject() : JetObjectDeclaration {
getCompanionObjects().firstOrNull()?.let { return it } getCompanionObjects().firstOrNull()?.let { return it }
return addDeclaration(JetPsiFactory(this).createCompanionObject()) as JetObjectDeclaration return addDeclaration(JetPsiFactory(this).createCompanionObject()) as JetObjectDeclaration
}
//TODO: code style option whether to insert redundant 'public' keyword or not
public fun JetDeclaration.setVisibility(visibilityModifier: JetModifierKeywordToken) {
val defaultVisibilityKeyword = if (hasModifier(JetTokens.OVERRIDE_KEYWORD)) {
(resolveToDescriptor() as? CallableMemberDescriptor)
?.overriddenDescriptors
?.let { OverridingUtil.findMaxVisibility(it) }
?.toKeyword()
}
else {
JetTokens.DEFAULT_VISIBILITY_KEYWORD
}
if (visibilityModifier == defaultVisibilityKeyword) {
this.visibilityModifier()?.let { removeModifier(it.node.elementType as JetModifierKeywordToken) }
return
}
addModifier(visibilityModifier)
}
private fun Visibility.toKeyword(): JetModifierKeywordToken? {
return when (this) {
Visibilities.PUBLIC -> JetTokens.PUBLIC_KEYWORD
Visibilities.PROTECTED -> JetTokens.PROTECTED_KEYWORD
Visibilities.INTERNAL -> JetTokens.INTERNAL_KEYWORD
Visibilities.PRIVATE -> JetTokens.PRIVATE_KEYWORD
else -> null
}
} }
@@ -19,14 +19,15 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.HighPriorityAction import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
public open class ChangeVisibilityModifierIntention protected constructor( public open class ChangeVisibilityModifierIntention protected constructor(
@@ -83,21 +84,7 @@ public open class ChangeVisibilityModifierIntention protected constructor(
} }
override fun applyTo(element: JetDeclaration, editor: Editor) { override fun applyTo(element: JetDeclaration, editor: Editor) {
val modifierToChange = element.visibilityModifier() element.setVisibility(modifier)
if (modifierToChange != null) {
modifierToChange.replace(JetPsiFactory(element).createModifier(modifier))
}
else {
element.addModifier(modifier)
}
}
private fun JetDeclaration.visibilityModifier(): PsiElement? {
val modifierList = getModifierList() ?: return null
return JetTokens.VISIBILITY_MODIFIERS.getTypes()
.asSequence()
.map { modifierList.getModifier(it as JetModifierKeywordToken) }
.firstOrNull { it != null } ?: return null
} }
private fun JetModifierKeywordToken.toVisibility(): Visibility { private fun JetModifierKeywordToken.toVisibility(): Visibility {
@@ -30,15 +30,16 @@ import org.jetbrains.kotlin.descriptors.Visibility;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.JetBundle; import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.core.PsiModificationUtilsKt;
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringUtil; import org.jetbrains.kotlin.idea.refactoring.JetRefactoringUtil;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.psi.JetDeclaration;
import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetModifierListOwner;
import org.jetbrains.kotlin.psi.JetParameter; import org.jetbrains.kotlin.psi.JetParameter;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierListOwner> { public class ChangeVisibilityModifierFix extends JetIntentionAction<JetDeclaration> {
public ChangeVisibilityModifierFix(@NotNull JetModifierListOwner element) { public ChangeVisibilityModifierFix(@NotNull JetDeclaration element) {
super(element); super(element);
} }
@@ -64,7 +65,7 @@ public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierL
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException { public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
JetModifierKeywordToken modifier = findVisibilityChangeTo(file); JetModifierKeywordToken modifier = findVisibilityChangeTo(file);
assert modifier != null; assert modifier != null;
element.addModifier(modifier); PsiModificationUtilsKt.setVisibility(element, modifier);
} }
@Nullable @Nullable
@@ -109,10 +110,10 @@ public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierL
public static JetSingleIntentionActionFactory createFactory() { public static JetSingleIntentionActionFactory createFactory() {
return new JetSingleIntentionActionFactory() { return new JetSingleIntentionActionFactory() {
@Override @Override
public JetIntentionAction<JetModifierListOwner> createAction(Diagnostic diagnostic) { public JetIntentionAction<JetDeclaration> createAction(Diagnostic diagnostic) {
PsiElement element = diagnostic.getPsiElement(); PsiElement element = diagnostic.getPsiElement();
if (!(element instanceof JetModifierListOwner)) return null; if (!(element instanceof JetDeclaration)) return null;
return new ChangeVisibilityModifierFix((JetModifierListOwner)element); return new ChangeVisibilityModifierFix((JetDeclaration)element);
} }
}; };
} }
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.idea.caches.resolve.JavaResolutionUtils; import org.jetbrains.kotlin.idea.caches.resolve.JavaResolutionUtils;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage; import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage;
import org.jetbrains.kotlin.idea.core.PsiModificationUtilsKt;
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringUtil; import org.jetbrains.kotlin.idea.refactoring.JetRefactoringUtil;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignaturePackage; import org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignaturePackage;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
@@ -346,10 +347,10 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
JetModifierKeywordToken newVisibilityToken = JetRefactoringUtil.getVisibilityToken(changeInfo.getNewVisibility()); JetModifierKeywordToken newVisibilityToken = JetRefactoringUtil.getVisibilityToken(changeInfo.getNewVisibility());
if (element instanceof JetCallableDeclaration) { if (element instanceof JetCallableDeclaration) {
((JetCallableDeclaration)element).addModifier(newVisibilityToken); PsiModificationUtilsKt.setVisibility((JetCallableDeclaration)element, newVisibilityToken);
} }
else if (element instanceof JetClass) { else if (element instanceof JetClass) {
((JetClass) element).createPrimaryConstructorIfAbsent().addModifier(newVisibilityToken); PsiModificationUtilsKt.setVisibility(((JetClass) element).createPrimaryConstructorIfAbsent(), newVisibilityToken);
} }
else throw new AssertionError("Invalid element: " + PsiUtilPackage.getElementTextWithContext(element)); else throw new AssertionError("Invalid element: " + PsiUtilPackage.getElementTextWithContext(element));
} }
@@ -0,0 +1,3 @@
class C {
protected<caret> fun foo(){}
}
@@ -3,5 +3,5 @@ interface I {
} }
abstract class C : I { abstract class C : I {
<caret>protected override fun foo() {} <caret>override fun foo() {}
} }
@@ -1,3 +0,0 @@
class C {
public<caret> fun foo(){}
}
@@ -0,0 +1,7 @@
interface I {
protected fun foo()
}
abstract class C : I {
<caret>override fun foo() {}
}
@@ -0,0 +1,7 @@
interface I {
protected fun foo()
}
abstract class C : I {
<caret>public override fun foo() {}
}
@@ -1,2 +1,2 @@
// INTENTION_TEXT: Make public // INTENTION_TEXT: Make public
class C <caret>public constructor(val v: Int) class C <caret>(val v: Int)
@@ -1,3 +1,3 @@
class C { class C {
<caret>public fun foo(){} <caret>fun foo(){}
} }
@@ -4,5 +4,5 @@ open class A {
} }
class B : A() { class B : A() {
<caret>protected override fun run() {} <caret>override fun run() {}
} }
@@ -4,5 +4,5 @@ open class A {
} }
class B : A() { class B : A() {
<caret>protected override fun run() {} <caret>override fun run() {}
} }
@@ -1,6 +1,6 @@
// "Change visibility modifier" "true" // "Change visibility modifier" "true"
abstract class C : ClassLoader() { abstract class C : ClassLoader() {
<caret>protected override fun findClass(var1: String): Class<*> { <caret>override fun findClass(var1: String): Class<*> {
throw ClassNotFoundException(var1) throw ClassNotFoundException(var1)
} }
} }
@@ -2264,6 +2264,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/changeVisibility/protected"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/changeVisibility/protected"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
} }
@TestMetadata("caretAfter.kt")
public void testCaretAfter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/protected/caretAfter.kt");
doTest(fileName);
}
@TestMetadata("noModifier.kt") @TestMetadata("noModifier.kt")
public void testNoModifier() throws Exception { public void testNoModifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/protected/noModifier.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/protected/noModifier.kt");
@@ -2321,18 +2327,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("caretAfter.kt")
public void testCaretAfter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/caretAfter.kt");
doTest(fileName);
}
@TestMetadata("forOverride.kt") @TestMetadata("forOverride.kt")
public void testForOverride() throws Exception { public void testForOverride() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/forOverride.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/forOverride.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("forOverride2.kt")
public void testForOverride2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/forOverride2.kt");
doTest(fileName);
}
@TestMetadata("primaryConstructor.kt") @TestMetadata("primaryConstructor.kt")
public void testPrimaryConstructor() throws Exception { public void testPrimaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/primaryConstructor.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/changeVisibility/public/primaryConstructor.kt");