Refactoring: IncreaseVisibilityFix --> ChangeVisibilityFix + MakeVisibleFactory + IncreaseExposedVisibilityFactory

This commit is contained in:
Mikhail Glukhikh
2016-04-18 18:51:24 +03:00
committed by Mikhail Glukhikh
parent fe44671b6a
commit 934c374030
5 changed files with 194 additions and 139 deletions
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.idea.core.canBeProtected
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.ExposedVisibilityChecker
open class ChangeVisibilityFix(
element: KtModifierListOwner,
protected val elementName: String,
protected val visibilityModifier: KtModifierKeywordToken
) : KotlinQuickFixAction<KtModifierListOwner>(element) {
override fun getText() = "Make $elementName $visibilityModifier"
override fun getFamilyName() = "Make $visibilityModifier"
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
element.setVisibility(visibilityModifier)
}
protected class ChangeToPublicFix(element: KtModifierListOwner, elementName: String) :
ChangeVisibilityFix(element, elementName, KtTokens.PUBLIC_KEYWORD), HighPriorityAction
protected class ChangeToProtectedFix(element: KtModifierListOwner, elementName: String) :
ChangeVisibilityFix(element, elementName, KtTokens.PROTECTED_KEYWORD) {
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) =
super.isAvailable(project, editor, file) && element.canBeProtected()
}
protected class ChangeToInternalFix(element: KtModifierListOwner, elementName: String) :
ChangeVisibilityFix(element, elementName, KtTokens.INTERNAL_KEYWORD)
companion object {
fun create(
declaration: KtModifierListOwner,
descriptor: DeclarationDescriptorWithVisibility,
targetVisibility: Visibility
) : IntentionAction? {
if (!ExposedVisibilityChecker().checkDeclarationWithVisibility(declaration, descriptor, targetVisibility)) return null
val name = descriptor.name.asString()
return when (targetVisibility) {
Visibilities.INTERNAL -> ChangeToInternalFix(declaration, name)
Visibilities.PROTECTED -> ChangeToProtectedFix(declaration, name)
Visibilities.PUBLIC -> ChangeToPublicFix(declaration, name)
else -> null
}
}
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.DescriptorWithRelation
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.Permissiveness.LESS
import org.jetbrains.kotlin.descriptors.Visibilities.PROTECTED
import org.jetbrains.kotlin.descriptors.Visibilities.PUBLIC
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
object IncreaseExposedVisibilityFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
@Suppress("UNCHECKED_CAST")
val factory = diagnostic.factory as DiagnosticFactory3<*, EffectiveVisibility, DescriptorWithRelation, EffectiveVisibility>
val exposedDiagnostic = factory.cast(diagnostic)
val exposedDescriptor = exposedDiagnostic.b.descriptor as? DeclarationDescriptorWithVisibility ?: return null
val exposedDeclaration = DescriptorToSourceUtils.getSourceFromDescriptor(exposedDescriptor) as? KtModifierListOwner ?: return null
val exposedVisibility = exposedDiagnostic.c
val exposingVisibility = exposedDiagnostic.a
val boundVisibility = when (exposedVisibility.relation(exposingVisibility)) {
LESS -> exposingVisibility.toVisibility()
else -> PUBLIC
}
val exposingDeclaration = diagnostic.psiElement.getParentOfType<KtDeclaration>(true)
val targetVisibility = when (boundVisibility) {
PROTECTED -> if (exposedDeclaration.parent == exposingDeclaration?.parent) PROTECTED else PUBLIC
else -> boundVisibility
}
return ChangeVisibilityFix.create(exposedDeclaration, exposedDescriptor, targetVisibility)
}
}
@@ -1,129 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.Permissiveness.LESS
import org.jetbrains.kotlin.descriptors.Visibilities.*
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.canBeProtected
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.ExposedVisibilityChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
open class IncreaseVisibilityFix(
element: KtModifierListOwner,
private val elementName: String,
private val visibilityModifier: KtModifierKeywordToken
) : KotlinQuickFixAction<KtModifierListOwner>(element), CleanupFix {
override fun getText() = "Make $elementName $visibilityModifier"
override fun getFamilyName() = "Make $visibilityModifier"
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
element.setVisibility(visibilityModifier)
}
class IncreaseToPublicFix(element: KtModifierListOwner, elementName: String) :
IncreaseVisibilityFix(element, elementName, PUBLIC_KEYWORD), HighPriorityAction
class IncreaseToProtectedFix(element: KtModifierListOwner, elementName: String) :
IncreaseVisibilityFix(element, elementName, PROTECTED_KEYWORD) {
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) =
super.isAvailable(project, editor, file) && element.canBeProtected()
}
class IncreaseToInternalFix(element: KtModifierListOwner, elementName: String) :
IncreaseVisibilityFix(element, elementName, INTERNAL_KEYWORD)
companion object : KotlinSingleIntentionActionFactory() {
private fun create(
declaration: KtModifierListOwner,
descriptor: DeclarationDescriptorWithVisibility,
targetVisibility: Visibility
) : IntentionAction? {
if (!ExposedVisibilityChecker().checkDeclarationWithVisibility(declaration, descriptor, targetVisibility)) return null
val name = descriptor.name.asString()
return when (targetVisibility) {
INTERNAL -> IncreaseToInternalFix(declaration, name)
PROTECTED -> IncreaseToProtectedFix(declaration, name)
PUBLIC -> IncreaseToPublicFix(declaration, name)
else -> null
}
}
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val element = diagnostic.psiElement as? KtElement ?: return null
val context = element.analyze(BodyResolveMode.PARTIAL)
val usageModule = context.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, element.getContainingKtFile())?.module
@Suppress("UNCHECKED_CAST")
val factory = diagnostic.factory as DiagnosticFactory3<*, DeclarationDescriptor, *, DeclarationDescriptor>
val descriptor = factory.cast(diagnostic).c as? DeclarationDescriptorWithVisibility ?: return null
val declaration = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) as? KtModifierListOwner ?: return null
val module = DescriptorUtils.getContainingModule(descriptor)
val targetVisibility = if (module != usageModule || descriptor.visibility != PRIVATE) PUBLIC else INTERNAL
return create(declaration, descriptor, targetVisibility)
}
}
object Exposed : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
@Suppress("UNCHECKED_CAST")
val factory = diagnostic.factory as DiagnosticFactory3<*, EffectiveVisibility, DescriptorWithRelation, EffectiveVisibility>
val exposedDiagnostic = factory.cast(diagnostic)
val exposedDescriptor = exposedDiagnostic.b.descriptor as? DeclarationDescriptorWithVisibility ?: return null
val exposedDeclaration = DescriptorToSourceUtils.getSourceFromDescriptor(exposedDescriptor) as? KtModifierListOwner ?: return null
val exposedVisibility = exposedDiagnostic.c
val exposingVisibility = exposedDiagnostic.a
val boundVisibility = when (exposedVisibility.relation(exposingVisibility)) {
LESS -> exposingVisibility.toVisibility()
else -> PUBLIC
}
val exposingDeclaration = diagnostic.psiElement.getParentOfType<KtDeclaration>(true)
val targetVisibility = when (boundVisibility) {
PROTECTED -> if (exposedDeclaration.parent == exposingDeclaration?.parent) PROTECTED else PUBLIC
else -> boundVisibility
}
return create(exposedDeclaration, exposedDescriptor, targetVisibility)
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibilities.*
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
object MakeVisibleFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val element = diagnostic.psiElement as? KtElement ?: return null
val context = element.analyze(BodyResolveMode.PARTIAL)
val usageModule = context.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, element.getContainingKtFile())?.module
@Suppress("UNCHECKED_CAST")
val factory = diagnostic.factory as DiagnosticFactory3<*, DeclarationDescriptor, *, DeclarationDescriptor>
val descriptor = factory.cast(diagnostic).c as? DeclarationDescriptorWithVisibility ?: return null
val declaration = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) as? KtModifierListOwner ?: return null
val module = DescriptorUtils.getContainingModule(descriptor)
val targetVisibility = if (module != usageModule || descriptor.visibility != PRIVATE) PUBLIC else INTERNAL
return ChangeVisibilityFix.create(declaration, descriptor, targetVisibility)
}
}
@@ -149,17 +149,17 @@ class QuickFixRegistrar : QuickFixContributor {
CANNOT_CHANGE_ACCESS_PRIVILEGE.registerFactory(ChangeVisibilityModifierFix)
CANNOT_WEAKEN_ACCESS_PRIVILEGE.registerFactory(ChangeVisibilityModifierFix)
INVISIBLE_REFERENCE.registerFactory(IncreaseVisibilityFix)
INVISIBLE_MEMBER.registerFactory(IncreaseVisibilityFix)
INVISIBLE_SETTER.registerFactory(IncreaseVisibilityFix)
INVISIBLE_REFERENCE.registerFactory(MakeVisibleFactory)
INVISIBLE_MEMBER.registerFactory(MakeVisibleFactory)
INVISIBLE_SETTER.registerFactory(MakeVisibleFactory)
EXPOSED_FUNCTION_RETURN_TYPE.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_PARAMETER_TYPE.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_PROPERTY_TYPE.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_RECEIVER_TYPE.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_SUPER_CLASS.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_SUPER_INTERFACE.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_TYPE_PARAMETER_BOUND.registerFactory(IncreaseVisibilityFix.Exposed)
EXPOSED_FUNCTION_RETURN_TYPE.registerFactory(IncreaseExposedVisibilityFactory)
EXPOSED_PARAMETER_TYPE.registerFactory(IncreaseExposedVisibilityFactory)
EXPOSED_PROPERTY_TYPE.registerFactory(IncreaseExposedVisibilityFactory)
EXPOSED_RECEIVER_TYPE.registerFactory(IncreaseExposedVisibilityFactory)
EXPOSED_SUPER_CLASS.registerFactory(IncreaseExposedVisibilityFactory)
EXPOSED_SUPER_INTERFACE.registerFactory(IncreaseExposedVisibilityFactory)
EXPOSED_TYPE_PARAMETER_BOUND.registerFactory(IncreaseExposedVisibilityFactory)
REDUNDANT_NULLABLE.registerFactory(RemoveNullableFix.Factory(RemoveNullableFix.NullableKind.REDUNDANT))
NULLABLE_SUPERTYPE.registerFactory(RemoveNullableFix.Factory(RemoveNullableFix.NullableKind.SUPERTYPE))