Implicit Nothing? type: don't report when declaration overrides nullable nothing type
#KT-30481 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
cf4471ba53
commit
14259ca9e0
@@ -354,12 +354,10 @@ fun KtDeclaration.isOverridable(): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
fun KtDeclaration.getModalityFromDescriptor(): KtModifierKeywordToken? {
|
||||
val descriptor = this.resolveToDescriptorIfAny()
|
||||
fun KtDeclaration.getModalityFromDescriptor(descriptor: DeclarationDescriptor? = resolveToDescriptorIfAny()): KtModifierKeywordToken? {
|
||||
if (descriptor is MemberDescriptor) {
|
||||
return mapModality(descriptor.modality)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
+19
-7
@@ -16,21 +16,33 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.inspections
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.getModalityFromDescriptor
|
||||
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
|
||||
|
||||
class ImplicitNullableNothingTypeInspection : IntentionBasedInspection<KtCallableDeclaration>(
|
||||
intention = SpecifyTypeExplicitlyIntention::class,
|
||||
additionalChecker = { declaration ->
|
||||
SpecifyTypeExplicitlyIntention.getTypeForDeclaration(declaration).isNullableNothing() &&
|
||||
(declaration.getModalityFromDescriptor() == KtTokens.OPEN_KEYWORD ||
|
||||
declaration is KtProperty && declaration.isVar)
|
||||
},
|
||||
problemText = "Implicit `Nothing?` type"
|
||||
intention = SpecifyTypeExplicitlyIntention::class,
|
||||
additionalChecker = { declaration -> declaration.check() },
|
||||
problemText = "Implicit `Nothing?` type"
|
||||
) {
|
||||
override fun inspectionTarget(element: KtCallableDeclaration) = element.nameIdentifier
|
||||
}
|
||||
|
||||
private fun KtCallableDeclaration.check(): Boolean {
|
||||
if (!SpecifyTypeExplicitlyIntention.getTypeForDeclaration(this).isNullableNothing()) return false
|
||||
val descriptor = this.resolveToDescriptorIfAny()
|
||||
return (getModalityFromDescriptor(descriptor) == KtTokens.OPEN_KEYWORD || this is KtProperty && this.isVar) &&
|
||||
!isOverridingNullableNothing(descriptor)
|
||||
}
|
||||
|
||||
private fun KtCallableDeclaration.isOverridingNullableNothing(descriptor: DeclarationDescriptor?): Boolean {
|
||||
return hasModifier(KtTokens.OVERRIDE_KEYWORD) &&
|
||||
(descriptor as? CallableMemberDescriptor)?.overriddenDescriptors?.any { it.returnType?.isNullableNothing() == true } == true
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
abstract class Parent {
|
||||
protected abstract fun foo(): String?
|
||||
}
|
||||
|
||||
class Child : Parent() {
|
||||
override fun <caret>foo() = null
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
abstract class Parent {
|
||||
protected abstract fun foo(): String?
|
||||
}
|
||||
|
||||
class Child : Parent() {
|
||||
override fun foo(): Nothing? = null
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
// PROBLEM: none
|
||||
|
||||
abstract class Parent {
|
||||
protected abstract fun foo(): Nothing?
|
||||
}
|
||||
|
||||
class Child : Parent() {
|
||||
override fun <caret>foo() = null
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
// PROBLEM: none
|
||||
|
||||
abstract class Parent {
|
||||
abstract val foo: Nothing?
|
||||
}
|
||||
|
||||
class Child : Parent() {
|
||||
override val <caret>foo = null
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
abstract class Parent {
|
||||
abstract val foo: Int?
|
||||
}
|
||||
|
||||
class Child : Parent() {
|
||||
override val <caret>foo = null
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
abstract class Parent {
|
||||
abstract val foo: Int?
|
||||
}
|
||||
|
||||
class Child : Parent() {
|
||||
override val foo: Nothing? = null
|
||||
}
|
||||
+27
-7
@@ -3271,7 +3271,7 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/inspectionsLocal/ImplicitNullableNothingType")
|
||||
@TestMetadata("idea/testData/inspectionsLocal/implicitNullableNothingType")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ImplicitNullableNothingType extends AbstractLocalInspectionTest {
|
||||
@@ -3280,32 +3280,52 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInImplicitNullableNothingType() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/ImplicitNullableNothingType"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/implicitNullableNothingType"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("final.kt")
|
||||
public void testFinal() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/ImplicitNullableNothingType/final.kt");
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/final.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("function.kt")
|
||||
public void testFunction() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/ImplicitNullableNothingType/function.kt");
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/function.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overrideFunction.kt")
|
||||
public void testOverrideFunction() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/overrideFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overrideNullableNothingFunction.kt")
|
||||
public void testOverrideNullableNothingFunction() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/overrideNullableNothingFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overrideNullableNothingProperty.kt")
|
||||
public void testOverrideNullableNothingProperty() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/overrideNullableNothingProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overrideProperty.kt")
|
||||
public void testOverrideProperty() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/overrideProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("top.kt")
|
||||
public void testTop() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/ImplicitNullableNothingType/top.kt");
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/top.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("val.kt")
|
||||
public void testVal() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/ImplicitNullableNothingType/val.kt");
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/val.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("variable.kt")
|
||||
public void testVariable() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/ImplicitNullableNothingType/variable.kt");
|
||||
runTest("idea/testData/inspectionsLocal/implicitNullableNothingType/variable.kt");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user