Inspection: convert initialized val to non-null type
^KT-35757 Fixed
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
8b28e54584
commit
18fbf5729d
@@ -2000,6 +2000,7 @@ action.ConfigureKotlinInProject.text=Configure Kotlin in Project
|
|||||||
action.KotlinConsoleREPL.text=Kotlin REPL
|
action.KotlinConsoleREPL.text=Kotlin REPL
|
||||||
action.LibraryToSourceDependencySupportToggleAction.text=Toggle library to source dependency support
|
action.LibraryToSourceDependencySupportToggleAction.text=Toggle library to source dependency support
|
||||||
|
|
||||||
|
inspection.convert.initialized.val.to.non.null.type.display.name=Convert initialized 'val' to non-null type
|
||||||
inspection.unused.unary.operator.display.name=Unused unary operator
|
inspection.unused.unary.operator.display.name=Unused unary operator
|
||||||
inspection.incomplete.destructuring.declaration.display.name=Incomplete destructuring declaration
|
inspection.incomplete.destructuring.declaration.display.name=Incomplete destructuring declaration
|
||||||
inspection.replace.guard.clause.with.function.call.display.name=Replace guard clause with kotlin's function call
|
inspection.replace.guard.clause.with.function.call.display.name=Replace guard clause with kotlin's function call
|
||||||
|
|||||||
@@ -2503,6 +2503,14 @@
|
|||||||
language="kotlin"
|
language="kotlin"
|
||||||
key="inspection.unused.unary.operator.display.name" bundle="messages.KotlinBundle"/>
|
key="inspection.unused.unary.operator.display.name" bundle="messages.KotlinBundle"/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ConvertInitializedValToNonNullTypeInspection"
|
||||||
|
groupPath="Kotlin"
|
||||||
|
groupName="Probable bugs"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="INFO"
|
||||||
|
language="kotlin"
|
||||||
|
key="inspection.convert.initialized.val.to.non.null.type.display.name" bundle="messages.KotlinBundle"/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.IncompleteDestructuringInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.IncompleteDestructuringInspection"
|
||||||
groupPath="Kotlin"
|
groupPath="Kotlin"
|
||||||
groupName="Probable bugs"
|
groupName="Probable bugs"
|
||||||
|
|||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This inspection reports nullable type of initialized 'val' should be converted into non-nullable type.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.inspections
|
||||||
|
|
||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.codeInspection.ProblemDescriptor
|
||||||
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
|
import com.intellij.codeInspection.ProblemsHolder
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isNull
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
|
class ConvertInitializedValToNonNullTypeInspection : AbstractKotlinInspection() {
|
||||||
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
|
||||||
|
propertyVisitor(fun(property) {
|
||||||
|
val typeReference = property.typeReference ?: return
|
||||||
|
|
||||||
|
if (shouldConvertToNonNullType(property)) {
|
||||||
|
holder.registerProblem(
|
||||||
|
typeReference,
|
||||||
|
"Initialized 'val' should be converted to non-null type",
|
||||||
|
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
|
||||||
|
RemoveRedundantNullableTypeQuickfix()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun shouldConvertToNonNullType(property: KtProperty): Boolean {
|
||||||
|
val initializer = property.initializer ?: return false
|
||||||
|
val type = property.resolveToDescriptorIfAny()?.type ?: return false
|
||||||
|
if (!TypeUtils.isNullableType(type)) return false
|
||||||
|
|
||||||
|
when (initializer) {
|
||||||
|
is KtConstantExpression -> {
|
||||||
|
return !initializer.isNull()
|
||||||
|
}
|
||||||
|
is KtStringTemplateExpression -> {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
is KtNameReferenceExpression, is KtCallExpression -> {
|
||||||
|
val context = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val assignedType = initializer.getType(context) ?: return false
|
||||||
|
return !TypeUtils.isNullableType(assignedType)
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RemoveRedundantNullableTypeQuickfix : LocalQuickFix {
|
||||||
|
override fun getName() = "Convert initialized 'val' to non-null type"
|
||||||
|
|
||||||
|
override fun getFamilyName() = name
|
||||||
|
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
|
val element = descriptor.psiElement
|
||||||
|
val factory = KtPsiFactory(project)
|
||||||
|
element.replace(factory.createType(element.text.removeSuffix("?")))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.inspections.ConvertInitializedValToNonNullTypeInspection
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s1: String?<caret> = bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String = ""
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s1: String = bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String = ""
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s0: String = ""
|
||||||
|
val s1: String?<caret> = s0
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s0: String = ""
|
||||||
|
val s1: String = s0
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s: String?<caret> = "Hello"
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s: String = "Hello"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
fun foo() {
|
||||||
|
val s1: String? = bar()
|
||||||
|
val s2: String?<caret> = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String? = ""
|
||||||
+33
@@ -3480,6 +3480,39 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/inspectionsLocal/convertInitializedValToNonNullType")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class ConvertInitializedValToNonNullType extends AbstractLocalInspectionTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInConvertInitializedValToNonNullType() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/convertInitializedValToNonNullType"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("assignToMethodCall.kt")
|
||||||
|
public void testAssignToMethodCall() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/convertInitializedValToNonNullType/assignToMethodCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("assignToVariable.kt")
|
||||||
|
public void testAssignToVariable() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/convertInitializedValToNonNullType/assignToVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("basic.kt")
|
||||||
|
public void testBasic() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/convertInitializedValToNonNullType/basic.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("negative.kt")
|
||||||
|
public void testNegative() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/convertInitializedValToNonNullType/negative.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/inspectionsLocal/convertNaNEquality")
|
@TestMetadata("idea/testData/inspectionsLocal/convertNaNEquality")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user