Inspection detecting redundant Unit return type (#1144)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This inspection reports redundant 'Unit' return type which can be omitted.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1977,6 +1977,15 @@
|
|||||||
language="kotlin"
|
language="kotlin"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RedundantUnitReturnTypeInspection"
|
||||||
|
displayName="Redundant 'Unit' return type"
|
||||||
|
groupName="Kotlin"
|
||||||
|
enabledByDefault="true"
|
||||||
|
cleanupTool="true"
|
||||||
|
level="WARNING"
|
||||||
|
language="kotlin"
|
||||||
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.RedundantIfInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.RedundantIfInspection"
|
||||||
displayName="Redundant 'if' statement"
|
displayName="Redundant 'if' statement"
|
||||||
groupPath="Kotlin"
|
groupPath="Kotlin"
|
||||||
|
|||||||
@@ -16,21 +16,50 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.intentions
|
package org.jetbrains.kotlin.idea.intentions
|
||||||
|
|
||||||
import com.intellij.codeInspection.ProblemHighlightType
|
import com.intellij.codeInspection.*
|
||||||
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 org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
import com.intellij.psi.PsiElementVisitor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||||
|
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
|
||||||
class RemoveSetterParameterTypeInspection : IntentionBasedInspection<KtCallableDeclaration>(
|
class RemoveSetterParameterTypeInspection : AbstractKotlinInspection() {
|
||||||
RemoveExplicitTypeIntention::class,
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||||
{ it -> RemoveExplicitTypeIntention.isSetterParameter(it) }
|
return object : KtVisitorVoid() {
|
||||||
) {
|
override fun visitDeclaration(dcl: KtDeclaration) {
|
||||||
override fun problemHighlightType(element: KtCallableDeclaration) = ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
if (dcl is KtParameter && dcl.typeReference != null && dcl.isSetterParameter) {
|
||||||
|
holder.registerProblem(dcl,
|
||||||
|
"Redundant setter parameter type",
|
||||||
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
|
IntentionWrapper(RemoveExplicitTypeIntention(), dcl.containingKtFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun inspectionTarget(element: KtCallableDeclaration) = (element as? KtParameter)?.typeReference
|
class RedundantUnitReturnTypeInspection : AbstractKotlinInspection() {
|
||||||
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||||
|
return object : KtVisitorVoid() {
|
||||||
|
override fun visitNamedFunction(function: KtNamedFunction) {
|
||||||
|
super.visitNamedFunction(function)
|
||||||
|
if (function.containingFile is KtCodeFragment) return
|
||||||
|
if ((function.descriptor as? FunctionDescriptor)?.returnType?.isUnit() ?: false) {
|
||||||
|
function.typeReference?.typeElement?.let {
|
||||||
|
holder.registerProblem(it,
|
||||||
|
"Redundant 'Unit' return type",
|
||||||
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
|
IntentionWrapper(RemoveExplicitTypeIntention(), function.containingKtFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
|
class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
|
||||||
@@ -39,21 +68,7 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
|
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
|
||||||
if (element.containingFile is KtCodeFragment) return null
|
return getRange(element)
|
||||||
if (element.typeReference == null) return null
|
|
||||||
|
|
||||||
if (element is KtParameter && (element.isLoopParameter || element.isSetterParameter)) {
|
|
||||||
return element.textRange
|
|
||||||
}
|
|
||||||
|
|
||||||
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
|
|
||||||
if (element !is KtProperty && (element !is KtNamedFunction || element.hasBlockBody())) return null
|
|
||||||
|
|
||||||
return when {
|
|
||||||
initializer != null -> TextRange(element.startOffset, initializer.startOffset - 1)
|
|
||||||
element is KtProperty && element.getter != null -> TextRange(element.startOffset, element.typeReference!!.endOffset)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
|
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
|
||||||
@@ -61,9 +76,28 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun isSetterParameter(element: KtCallableDeclaration) =
|
fun getRange(element: KtCallableDeclaration): TextRange? {
|
||||||
element is KtParameter && element.isSetterParameter
|
if (element.containingFile is KtCodeFragment) return null
|
||||||
|
if (element.typeReference == null) return null
|
||||||
|
|
||||||
private val KtParameter.isSetterParameter: Boolean get() = (parent.parent as? KtPropertyAccessor)?.isSetter ?: false
|
if (element is KtParameter && (element.isLoopParameter || element.isSetterParameter)) {
|
||||||
|
return element.textRange
|
||||||
|
}
|
||||||
|
|
||||||
|
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
|
||||||
|
if (element !is KtProperty && element !is KtNamedFunction) return null
|
||||||
|
(element as? KtNamedFunction)?.let {
|
||||||
|
if (it.hasBlockBody() && (element.descriptor as? FunctionDescriptor)?.returnType?.isUnit()?.not() ?: true) return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
initializer != null -> TextRange(element.startOffset, initializer.startOffset - 1)
|
||||||
|
element is KtProperty && element.getter != null -> TextRange(element.startOffset, element.typeReference!!.endOffset)
|
||||||
|
element is KtNamedFunction -> TextRange(element.startOffset, element.typeReference!!.endOffset)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val KtParameter.isSetterParameter: Boolean get() = (parent.parent as? KtPropertyAccessor)?.isSetter ?: false
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fun foo(): Unit {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): Unit {
|
||||||
|
return Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
fun baz(): Unit = println("ok")
|
||||||
|
|
||||||
|
fun f1(): Int = 1
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<problems>
|
||||||
|
<problem>
|
||||||
|
<file>Test.kt</file>
|
||||||
|
<line>1</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 'Unit' return type</problem_class>
|
||||||
|
<description>Redundant Unit return type</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>Test.kt</file>
|
||||||
|
<line>4</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 'Unit' return type</problem_class>
|
||||||
|
<description>Redundant Unit return type</description>
|
||||||
|
</problem>
|
||||||
|
<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 'Unit' return type</problem_class>
|
||||||
|
<description>Redundant Unit return type</description>
|
||||||
|
</problem>
|
||||||
|
</problems>
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.intentions.RedundantUnitReturnTypeInspection
|
||||||
+4
-4
@@ -4,15 +4,15 @@
|
|||||||
<line>4</line>
|
<line>4</line>
|
||||||
<module>light_idea_test_case</module>
|
<module>light_idea_test_case</module>
|
||||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Redundant setter parameter type</problem_class>
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant setter parameter type</problem_class>
|
||||||
<description>Remove explicit type specification</description>
|
<description>Redundant setter parameter type</description>
|
||||||
</problem>
|
</problem>
|
||||||
<problem>
|
<problem>
|
||||||
<file>test.kt</file>
|
<file>test.kt</file>
|
||||||
<line>10</line>
|
<line>10</line>
|
||||||
<module>light_idea_test_case</module>
|
<module>light_idea_test_case</module>
|
||||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Redundant setter parameter type</problem_class>
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant setter parameter type</problem_class>
|
||||||
<description>Remove explicit type specification</description>
|
<description>Redundant setter parameter type</description>
|
||||||
</problem>
|
</problem>
|
||||||
</problems>
|
</problems>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(): <caret>Unit = bar()
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo() = bar()
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun main(args: Array<String>): <caret>Unit {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -281,6 +281,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("redundantUnitReturnType/inspectionData/inspections.test")
|
||||||
|
public void testRedundantUnitReturnType_inspectionData_Inspections_test() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantUnitReturnType/inspectionData/inspections.test");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("redundantVisibilityModifier/inspectionData/inspections.test")
|
@TestMetadata("redundantVisibilityModifier/inspectionData/inspections.test")
|
||||||
public void testRedundantVisibilityModifier_inspectionData_Inspections_test() throws Exception {
|
public void testRedundantVisibilityModifier_inspectionData_Inspections_test() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantVisibilityModifier/inspectionData/inspections.test");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantVisibilityModifier/inspectionData/inspections.test");
|
||||||
|
|||||||
@@ -13010,6 +13010,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeExplicitType"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeExplicitType"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("funNoBody.kt")
|
||||||
|
public void testFunNoBody() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/funNoBody.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("funWithBody.kt")
|
||||||
|
public void testFunWithBody() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/funWithBody.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("notOnParameterOfFunctionType.kt")
|
@TestMetadata("notOnParameterOfFunctionType.kt")
|
||||||
public void testNotOnParameterOfFunctionType() throws Exception {
|
public void testNotOnParameterOfFunctionType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/notOnParameterOfFunctionType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/notOnParameterOfFunctionType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user