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.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.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
|
||||
|
||||
@@ -2503,6 +2503,14 @@
|
||||
language="kotlin"
|
||||
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"
|
||||
groupPath="Kotlin"
|
||||
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")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user