Redundant modality modifier inspection #KT-11450 Fixed
This commit is contained in:
@@ -758,8 +758,7 @@ public class DescriptorResolver {
|
||||
return propertyDescriptor;
|
||||
}
|
||||
|
||||
/*package*/
|
||||
static boolean hasBody(KtProperty property) {
|
||||
public static boolean hasBody(KtProperty property) {
|
||||
boolean hasBody = property.hasDelegateExpressionOrInitializer();
|
||||
if (!hasBody) {
|
||||
KtPropertyAccessor getter = property.getGetter();
|
||||
|
||||
@@ -26,9 +26,11 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getLambdaArgumentName
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
|
||||
|
||||
@@ -188,6 +190,27 @@ fun KtDeclaration.implicitVisibility(): KtModifierKeywordToken? {
|
||||
return defaultVisibilityKeyword
|
||||
}
|
||||
|
||||
fun KtDeclaration.implicitModality(): KtModifierKeywordToken {
|
||||
if (this is KtClassOrObject) return KtTokens.FINAL_KEYWORD
|
||||
val klass = containingClassOrObject ?: return KtTokens.FINAL_KEYWORD
|
||||
if (hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||
if (klass.hasModifier(KtTokens.ABSTRACT_KEYWORD) ||
|
||||
klass.hasModifier(KtTokens.OPEN_KEYWORD) ||
|
||||
klass.hasModifier(KtTokens.SEALED_KEYWORD)) {
|
||||
return KtTokens.OPEN_KEYWORD
|
||||
}
|
||||
}
|
||||
if (klass is KtClass && klass.isInterface() && !hasModifier(KtTokens.PRIVATE_KEYWORD)) {
|
||||
val hasBody = when (this) {
|
||||
is KtProperty -> DescriptorResolver.hasBody(this)
|
||||
is KtFunction -> hasBody()
|
||||
else -> false
|
||||
}
|
||||
return if (hasBody) KtTokens.OPEN_KEYWORD else KtTokens.ABSTRACT_KEYWORD
|
||||
}
|
||||
return KtTokens.FINAL_KEYWORD
|
||||
}
|
||||
|
||||
fun KtSecondaryConstructor.getOrCreateBody(): KtBlockExpression {
|
||||
bodyExpression?.let { return it }
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports modality modifiers which match the default modality of an element
|
||||
(<code>final</code> for most elements, <code>open</code> for members with override).
|
||||
</body>
|
||||
</html>
|
||||
@@ -1443,6 +1443,14 @@
|
||||
level="WARNING"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.RedundantModalityModifierInspection"
|
||||
displayName="Redundant modality modifier"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
cleanupTool="true"
|
||||
level="WARNING"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.inspections
|
||||
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.idea.core.implicitModality
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
|
||||
|
||||
class RedundantModalityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
return object : KtVisitorVoid() {
|
||||
override fun visitDeclaration(declaration: KtDeclaration) {
|
||||
val modalityModifier = declaration.modalityModifier() ?: return
|
||||
if (modalityModifier.node.elementType == declaration.implicitModality()) {
|
||||
holder.registerProblem(modalityModifier,
|
||||
"Redundant modality modifier",
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||
RemoveModifierFix("Remove redundant modality modifier"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-23
@@ -17,43 +17,24 @@
|
||||
package org.jetbrains.kotlin.idea.inspections
|
||||
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.idea.core.implicitVisibility
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.addRemoveModifier.removeModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
||||
|
||||
class RedundantVisibilityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
return object : KtVisitorVoid() {
|
||||
override fun visitDeclaration(dcl: KtDeclaration) {
|
||||
val visibilityModifier = dcl.visibilityModifier() ?: return
|
||||
if (visibilityModifier.node.elementType == dcl.implicitVisibility()) {
|
||||
override fun visitDeclaration(declaration: KtDeclaration) {
|
||||
val visibilityModifier = declaration.visibilityModifier() ?: return
|
||||
if (visibilityModifier.node.elementType == declaration.implicitVisibility()) {
|
||||
holder.registerProblem(visibilityModifier,
|
||||
"Redundant visibility modifier",
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||
RemoveVisibilityModifierFix())
|
||||
RemoveModifierFix("Remove redundant visibility modifier"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveVisibilityModifierFix : LocalQuickFix {
|
||||
override fun getName(): String = "Remove redundant visibility modifier"
|
||||
|
||||
override fun getFamilyName(): String = name
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val modifierKeyword = descriptor.psiElement.node.elementType as KtModifierKeywordToken
|
||||
val modifierListOwner = descriptor.psiElement.getParentOfType<KtModifierListOwner>(true)
|
||||
?: throw IllegalStateException("Can't find modifier list owner for modifier")
|
||||
removeModifier(modifierListOwner, modifierKeyword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.inspections
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.addRemoveModifier.removeModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
|
||||
class RemoveModifierFix(val text: String) : LocalQuickFix {
|
||||
override fun getName(): String = text
|
||||
|
||||
override fun getFamilyName(): String = text
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val modifierKeyword = descriptor.psiElement.node.elementType as KtModifierKeywordToken
|
||||
val modifierListOwner = descriptor.psiElement.getParentOfType<KtModifierListOwner>(true)
|
||||
?: throw IllegalStateException("Can't find modifier list owner for modifier")
|
||||
removeModifier(modifierListOwner, modifierKeyword)
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<problems>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>4</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>13</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>22</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>25</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>29</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>31</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>33</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>39</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantModalityModifier.kt</file>
|
||||
<line>41</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantModalityModifier.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant modality modifier</problem_class>
|
||||
<description>Redundant modality modifier</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+1
@@ -0,0 +1 @@
|
||||
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.RedundantModalityModifierInspection
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Abstract
|
||||
abstract class Base {
|
||||
// Redundant final
|
||||
final fun foo() {}
|
||||
// Abstract
|
||||
abstract fun bar()
|
||||
// Open
|
||||
open val gav = 42
|
||||
}
|
||||
|
||||
class FinalDerived : Base() {
|
||||
// Redundant final
|
||||
override final fun bar() {}
|
||||
// Non-final member in final class
|
||||
override open val gav = 13
|
||||
}
|
||||
// Open
|
||||
open class OpenDerived : Base() {
|
||||
// Final
|
||||
override final fun bar() {}
|
||||
// Redundant open
|
||||
override open val gav = 13
|
||||
}
|
||||
// Redundant final
|
||||
final class Final
|
||||
// Interface
|
||||
interface Interface {
|
||||
// Redundant
|
||||
abstract fun foo()
|
||||
// Redundant
|
||||
private final fun bar() {}
|
||||
// Redundant
|
||||
open val gav: Int
|
||||
get() = 42
|
||||
}
|
||||
// Derived interface
|
||||
interface Derived : Interface {
|
||||
// Redundant
|
||||
override open fun foo() {}
|
||||
// Redundant
|
||||
final class Nested
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.inspections.RedundantModalityModifierInspection
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Remove redundant modality modifier" "true"
|
||||
open class C {
|
||||
<caret>final fun foo(){}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Remove redundant modality modifier" "true"
|
||||
open class C {
|
||||
fun foo(){}
|
||||
}
|
||||
@@ -160,6 +160,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("redundantModalityModifier/inspectionData/inspections.test")
|
||||
public void testRedundantModalityModifier_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantModalityModifier/inspectionData/inspections.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("redundantSamConstructor/inspectionData/inspections.test")
|
||||
public void testRedundantSamConstructor_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantSamConstructor/inspectionData/inspections.test");
|
||||
|
||||
@@ -6128,6 +6128,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/redundantModalityModifier")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class RedundantModalityModifier extends AbstractQuickFixTest {
|
||||
public void testAllFilesPresentInRedundantModalityModifier() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/redundantModalityModifier"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/redundantModalityModifier/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/redundantVisibilityModifier")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user