Use descriptor modality in IDE inspections/intentions
This fixes KT-18160, KT-18194, KT-18195, KT-18197 ~
This commit is contained in:
+2
-1
@@ -36,7 +36,8 @@ interface DeclarationAttributeAltererExtension {
|
|||||||
declaration: DeclarationDescriptor?,
|
declaration: DeclarationDescriptor?,
|
||||||
containingDeclaration: DeclarationDescriptor?,
|
containingDeclaration: DeclarationDescriptor?,
|
||||||
currentModality: Modality,
|
currentModality: Modality,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext,
|
||||||
|
isImplicitModality: Boolean
|
||||||
): Modality? = null
|
): Modality? = null
|
||||||
|
|
||||||
fun shouldConvertFirstSAMParameterToReceiver(function: FunctionDescriptor) : Boolean = false
|
fun shouldConvertFirstSAMParameterToReceiver(function: FunctionDescriptor) : Boolean = false
|
||||||
|
|||||||
@@ -178,27 +178,6 @@ fun KtBlockExpression.contentRange(): PsiChildRange {
|
|||||||
|
|
||||||
// ----------- Inheritance -----------------------------------------------------------------------------------------------------------------
|
// ----------- Inheritance -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
fun KtClass.isInheritable(): Boolean {
|
|
||||||
return isInterface() || hasModifier(KtTokens.OPEN_KEYWORD) ||
|
|
||||||
hasModifier(KtTokens.ABSTRACT_KEYWORD) || hasModifier(KtTokens.SEALED_KEYWORD)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KtDeclaration.isOverridable(): Boolean {
|
|
||||||
val parent = parent
|
|
||||||
if (!(parent is KtClassBody || parent is KtParameterList)) return false
|
|
||||||
|
|
||||||
val klass = if (parent.parent is KtPrimaryConstructor)
|
|
||||||
parent.parent.parent as? KtClass
|
|
||||||
else
|
|
||||||
parent.parent as? KtClass
|
|
||||||
if (klass == null || (!klass.isInheritable() && !klass.isEnum())) return false
|
|
||||||
|
|
||||||
if (hasModifier(KtTokens.FINAL_KEYWORD) || hasModifier(KtTokens.PRIVATE_KEYWORD)) return false
|
|
||||||
|
|
||||||
return klass.isInterface() ||
|
|
||||||
hasModifier(KtTokens.ABSTRACT_KEYWORD) || hasModifier(KtTokens.OPEN_KEYWORD) || hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KtClass.isAbstract(): Boolean = isInterface() || hasModifier(KtTokens.ABSTRACT_KEYWORD)
|
fun KtClass.isAbstract(): Boolean = isInterface() || hasModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ public class ModifiersChecker {
|
|||||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, modifierListOwner);
|
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, modifierListOwner);
|
||||||
for (DeclarationAttributeAltererExtension extension : extensions) {
|
for (DeclarationAttributeAltererExtension extension : extensions) {
|
||||||
Modality newModality = extension.refineDeclarationModality(
|
Modality newModality = extension.refineDeclarationModality(
|
||||||
modifierListOwner, descriptor, containingDescriptor, modality, bindingContext);
|
modifierListOwner, descriptor, containingDescriptor, modality, bindingContext, false);
|
||||||
|
|
||||||
if (newModality != null) {
|
if (newModality != null) {
|
||||||
modality = newModality;
|
modality = newModality;
|
||||||
|
|||||||
+1
-1
@@ -26,10 +26,10 @@ import com.intellij.util.MergeQuery
|
|||||||
import com.intellij.util.Processor
|
import com.intellij.util.Processor
|
||||||
import com.intellij.util.Query
|
import com.intellij.util.Query
|
||||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.search.allScope
|
import org.jetbrains.kotlin.idea.search.allScope
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isOverridable
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun PsiElement.isOverridableElement(): Boolean = when (this) {
|
fun PsiElement.isOverridableElement(): Boolean = when (this) {
|
||||||
|
|||||||
@@ -19,11 +19,10 @@ package org.jetbrains.kotlin.idea.core
|
|||||||
import com.intellij.psi.PsiElement
|
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.tree.IElementType
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
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.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
@@ -232,7 +231,84 @@ fun KtModifierListOwner.canBeProtected(): Boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KtClass.isInheritable(): Boolean {
|
||||||
|
return when (getModalityFromDescriptor()) {
|
||||||
|
KtTokens.ABSTRACT_KEYWORD, KtTokens.OPEN_KEYWORD, KtTokens.SEALED_KEYWORD -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KtDeclaration.isOverridable(): Boolean {
|
||||||
|
val parent = parent
|
||||||
|
if (!(parent is KtClassBody || parent is KtParameterList)) return false
|
||||||
|
|
||||||
|
val klass = if (parent.parent is KtPrimaryConstructor)
|
||||||
|
parent.parent.parent as? KtClass
|
||||||
|
else
|
||||||
|
parent.parent as? KtClass
|
||||||
|
|
||||||
|
if (klass == null || (!klass.isInheritable() && !klass.isEnum())) return false
|
||||||
|
|
||||||
|
if (this.hasModifier(KtTokens.PRIVATE_KEYWORD)) {
|
||||||
|
// 'private' is incompatible with 'open'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (getModalityFromDescriptor()) {
|
||||||
|
KtTokens.ABSTRACT_KEYWORD, KtTokens.OPEN_KEYWORD -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KtDeclaration.getModalityFromDescriptor(): KtModifierKeywordToken? {
|
||||||
|
val descriptor = this.resolveToDescriptor(BodyResolveMode.PARTIAL)
|
||||||
|
if (descriptor is MemberDescriptor) {
|
||||||
|
return mapModality(descriptor.modality)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
fun KtDeclaration.implicitModality(): KtModifierKeywordToken {
|
fun KtDeclaration.implicitModality(): KtModifierKeywordToken {
|
||||||
|
var predictedModality = predictImplicitModality()
|
||||||
|
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this] ?: return predictedModality
|
||||||
|
val containingDescriptor = descriptor.containingDeclaration ?: return predictedModality
|
||||||
|
|
||||||
|
val extensions = DeclarationAttributeAltererExtension.getInstances(this.project)
|
||||||
|
for (extension in extensions) {
|
||||||
|
val newModality = extension.refineDeclarationModality(
|
||||||
|
this,
|
||||||
|
null,
|
||||||
|
containingDescriptor,
|
||||||
|
mapModalityToken(predictedModality),
|
||||||
|
bindingContext,
|
||||||
|
isImplicitModality = true)
|
||||||
|
|
||||||
|
if (newModality != null) {
|
||||||
|
predictedModality = mapModality(newModality)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return predictedModality
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapModality(accurateModality: Modality): KtModifierKeywordToken = when (accurateModality) {
|
||||||
|
Modality.FINAL -> KtTokens.FINAL_KEYWORD
|
||||||
|
Modality.SEALED -> KtTokens.SEALED_KEYWORD
|
||||||
|
Modality.OPEN -> KtTokens.OPEN_KEYWORD
|
||||||
|
Modality.ABSTRACT -> KtTokens.ABSTRACT_KEYWORD
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mapModalityToken(modalityToken: IElementType): Modality = when (modalityToken) {
|
||||||
|
KtTokens.FINAL_KEYWORD -> Modality.FINAL
|
||||||
|
KtTokens.SEALED_KEYWORD -> Modality.SEALED
|
||||||
|
KtTokens.OPEN_KEYWORD -> Modality.OPEN
|
||||||
|
KtTokens.ABSTRACT_KEYWORD -> Modality.ABSTRACT
|
||||||
|
else -> error("Unexpected modality keyword $modalityToken")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtDeclaration.predictImplicitModality(): KtModifierKeywordToken {
|
||||||
if (this is KtClassOrObject) {
|
if (this is KtClassOrObject) {
|
||||||
if (this is KtClass && this.isInterface()) return KtTokens.ABSTRACT_KEYWORD
|
if (this is KtClass && this.isInterface()) return KtTokens.ABSTRACT_KEYWORD
|
||||||
return KtTokens.FINAL_KEYWORD
|
return KtTokens.FINAL_KEYWORD
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ import com.intellij.openapi.ui.VerticalFlowLayout
|
|||||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
||||||
import com.intellij.ui.NonFocusableCheckBox
|
import com.intellij.ui.NonFocusableCheckBox
|
||||||
import com.intellij.util.containers.HashMap
|
import com.intellij.util.containers.HashMap
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isInheritable
|
|
||||||
import org.jetbrains.kotlin.utils.keysToMap
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
import javax.swing.JLabel
|
import javax.swing.JLabel
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.search.searches.OverridingMethodsSearch
|
import com.intellij.psi.search.searches.OverridingMethodsSearch
|
||||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.DelegatingFindMemberUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.DelegatingFindMemberUsagesHandler
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler
|
||||||
@@ -36,7 +37,6 @@ import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinTypeParameterFindUsag
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
|
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
|
||||||
import org.jetbrains.kotlin.plugin.findUsages.handlers.KotlinFindUsagesHandlerDecorator
|
import org.jetbrains.kotlin.plugin.findUsages.handlers.KotlinFindUsagesHandlerDecorator
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isOverridable
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
|
import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
|
||||||
import java.lang.IllegalArgumentException
|
import java.lang.IllegalArgumentException
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -32,12 +32,11 @@ import com.intellij.ui.StateRestoringCheckBox;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle;
|
import org.jetbrains.kotlin.idea.KotlinBundle;
|
||||||
|
import org.jetbrains.kotlin.idea.core.PsiModificationUtilsKt;
|
||||||
import org.jetbrains.kotlin.idea.findUsages.KotlinClassFindUsagesOptions;
|
import org.jetbrains.kotlin.idea.findUsages.KotlinClassFindUsagesOptions;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.RenderingUtilsKt;
|
import org.jetbrains.kotlin.idea.refactoring.RenderingUtilsKt;
|
||||||
import org.jetbrains.kotlin.psi.KtClass;
|
import org.jetbrains.kotlin.psi.KtClass;
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass;
|
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass;
|
||||||
@@ -91,7 +90,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
|
|||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
javaClass.getModifierList().setModifierProperty(
|
javaClass.getModifierList().setModifierProperty(
|
||||||
PsiModifier.FINAL,
|
PsiModifier.FINAL,
|
||||||
!(classOrObject instanceof KtClass && KtPsiUtilKt.isInheritable((KtClass) classOrObject))
|
!(classOrObject instanceof KtClass && PsiModificationUtilsKt.isInheritable((KtClass) classOrObject))
|
||||||
);
|
);
|
||||||
|
|
||||||
javaClass.putUserData(ORIGINAL_CLASS, classOrObject);
|
javaClass.putUserData(ORIGINAL_CLASS, classOrObject);
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||||
import org.jetbrains.kotlin.idea.highlighter.allImplementingCompatibleModules
|
import org.jetbrains.kotlin.idea.highlighter.allImplementingCompatibleModules
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isInheritable
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isOverridable
|
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|||||||
@@ -27,12 +27,16 @@ import com.intellij.psi.search.PsiSearchHelper
|
|||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
import com.intellij.util.Processor
|
import com.intellij.util.Processor
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
|
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
|
||||||
import org.jetbrains.kotlin.idea.refactoring.isConstructorDeclaredProperty
|
import org.jetbrains.kotlin.idea.refactoring.isConstructorDeclaredProperty
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
|
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
|
|
||||||
class MemberVisibilityCanPrivateInspection : AbstractKotlinInspection() {
|
class MemberVisibilityCanPrivateInspection : AbstractKotlinInspection() {
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.intellij.codeInspection.*
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElementVisitor
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import org.jetbrains.kotlin.idea.core.implicitVisibility
|
import org.jetbrains.kotlin.idea.core.implicitVisibility
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
@@ -28,7 +29,6 @@ import org.jetbrains.kotlin.psi.KtModifierListOwner
|
|||||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||||
import org.jetbrains.kotlin.psi.addRemoveModifier.addModifier
|
import org.jetbrains.kotlin.psi.addRemoveModifier.addModifier
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isInheritable
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
||||||
|
|
||||||
class ProtectedInFinalInspection : AbstractKotlinInspection() {
|
class ProtectedInFinalInspection : AbstractKotlinInspection() {
|
||||||
|
|||||||
+1
-24
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.core.implicitModality
|
import org.jetbrains.kotlin.idea.core.implicitModality
|
||||||
|
import org.jetbrains.kotlin.idea.core.mapModality
|
||||||
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
@@ -41,10 +42,6 @@ class RedundantModalityModifierInspection : AbstractKotlinInspection(), CleanupL
|
|||||||
|
|
||||||
if (modalityModifierType != implicitModality) return
|
if (modalityModifierType != implicitModality) return
|
||||||
|
|
||||||
// Descriptor may have the different modality (in case of all-open plugin enabled, for example)
|
|
||||||
val modalityFromPsi = getModality(implicitModality)
|
|
||||||
if (modalityFromPsi != null && hasRefinedModalityInDescriptor(declaration, modalityFromPsi)) return
|
|
||||||
|
|
||||||
holder.registerProblem(modalityModifier,
|
holder.registerProblem(modalityModifier,
|
||||||
"Redundant modality modifier",
|
"Redundant modality modifier",
|
||||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
@@ -53,24 +50,4 @@ class RedundantModalityModifierInspection : AbstractKotlinInspection(), CleanupL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasRefinedModalityInDescriptor(
|
|
||||||
declaration: KtDeclaration,
|
|
||||||
implicitModality: Modality
|
|
||||||
): Boolean {
|
|
||||||
val bindingContext = declaration.analyze(BodyResolveMode.PARTIAL)
|
|
||||||
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] ?: return false
|
|
||||||
return DeclarationAttributeAltererExtension.getInstances(declaration.project).any {
|
|
||||||
it.refineDeclarationModality(declaration, descriptor, descriptor.containingDeclaration,
|
|
||||||
implicitModality, bindingContext) != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getModality(modalityToken: IElementType): Modality? = when (modalityToken) {
|
|
||||||
KtTokens.FINAL_KEYWORD -> Modality.FINAL
|
|
||||||
KtTokens.SEALED_KEYWORD -> Modality.SEALED
|
|
||||||
KtTokens.OPEN_KEYWORD -> Modality.OPEN
|
|
||||||
KtTokens.ABSTRACT_KEYWORD -> Modality.ABSTRACT
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureConfiguration
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureConfiguration
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
|
||||||
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
|||||||
import org.jetbrains.kotlin.idea.util.getThisReceiverOwner
|
import org.jetbrains.kotlin.idea.util.getThisReceiverOwner
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isOverridable
|
|
||||||
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.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||||
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
|
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import com.intellij.util.PlatformIcons
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.intellij.refactoring.HelpID
|
|||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
import org.jetbrains.kotlin.idea.refactoring.AbstractPullPushMembersHandler
|
import org.jetbrains.kotlin.idea.refactoring.AbstractPullPushMembersHandler
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfoStorage
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfoStorage
|
||||||
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.psi.KtClass
|
|||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isInheritable
|
|
||||||
|
|
||||||
val PUSH_MEMBERS_DOWN = "Push Members Down"
|
val PUSH_MEMBERS_DOWN = "Push Members Down"
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions
|
import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions
|
||||||
import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions
|
import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions
|
||||||
import org.jetbrains.kotlin.idea.findUsages.processAllExactUsages
|
import org.jetbrains.kotlin.idea.findUsages.processAllExactUsages
|
||||||
|
|||||||
@@ -1,4 +1,22 @@
|
|||||||
<problems>
|
<problems>
|
||||||
|
<problem>
|
||||||
|
<file>test.kt</file>
|
||||||
|
<line>8</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||||
|
<description>Redundant modality modifier</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.kt</file>
|
||||||
|
<line>9</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||||
|
<description>Redundant modality modifier</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
<problem>
|
<problem>
|
||||||
<file>test.kt</file>
|
<file>test.kt</file>
|
||||||
<line>22</line>
|
<line>22</line>
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ abstract class AbstractAllOpenDeclarationAttributeAltererExtension : Declaration
|
|||||||
declaration: DeclarationDescriptor?,
|
declaration: DeclarationDescriptor?,
|
||||||
containingDeclaration: DeclarationDescriptor?,
|
containingDeclaration: DeclarationDescriptor?,
|
||||||
currentModality: Modality,
|
currentModality: Modality,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext,
|
||||||
|
isImplicitModality: Boolean
|
||||||
): Modality? {
|
): Modality? {
|
||||||
if (currentModality != Modality.FINAL) {
|
if (currentModality != Modality.FINAL) {
|
||||||
return null
|
return null
|
||||||
@@ -54,7 +55,7 @@ abstract class AbstractAllOpenDeclarationAttributeAltererExtension : Declaration
|
|||||||
|
|
||||||
val descriptor = declaration as? ClassDescriptor ?: containingDeclaration ?: return null
|
val descriptor = declaration as? ClassDescriptor ?: containingDeclaration ?: return null
|
||||||
if (descriptor.hasSpecialAnnotation(modifierListOwner)) {
|
if (descriptor.hasSpecialAnnotation(modifierListOwner)) {
|
||||||
return if (modifierListOwner.hasModifier(KtTokens.FINAL_KEYWORD))
|
return if (!isImplicitModality && modifierListOwner.hasModifier(KtTokens.FINAL_KEYWORD))
|
||||||
Modality.FINAL // Explicit final
|
Modality.FINAL // Explicit final
|
||||||
else
|
else
|
||||||
Modality.OPEN
|
Modality.OPEN
|
||||||
|
|||||||
+2
-2
@@ -33,13 +33,13 @@ import org.jetbrains.kotlin.asJava.toLightMethods
|
|||||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||||
import org.jetbrains.kotlin.idea.spring.isAnnotatedWith
|
import org.jetbrains.kotlin.idea.spring.isAnnotatedWith
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isInheritable
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isOverridable
|
|
||||||
|
|
||||||
class KotlinFinalClassOrFunSpringInspection : AbstractKotlinInspection() {
|
class KotlinFinalClassOrFunSpringInspection : AbstractKotlinInspection() {
|
||||||
class QuickFix<T: KtModifierListOwner>(private val element: T) : LocalQuickFix {
|
class QuickFix<T: KtModifierListOwner>(private val element: T) : LocalQuickFix {
|
||||||
|
|||||||
Reference in New Issue
Block a user