Implicit Nothing? type: don't report when declaration overrides nullable nothing type

#KT-30481 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-04-09 12:09:43 +09:00
committed by Mikhail Glukhikh
parent cf4471ba53
commit 14259ca9e0
17 changed files with 93 additions and 17 deletions
@@ -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
}
@@ -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
}
@@ -0,0 +1,7 @@
abstract class Parent {
protected abstract fun foo(): String?
}
class Child : Parent() {
override fun <caret>foo() = null
}
@@ -0,0 +1,7 @@
abstract class Parent {
protected abstract fun foo(): String?
}
class Child : Parent() {
override fun foo(): Nothing? = null
}
@@ -0,0 +1,9 @@
// PROBLEM: none
abstract class Parent {
protected abstract fun foo(): Nothing?
}
class Child : Parent() {
override fun <caret>foo() = null
}
@@ -0,0 +1,9 @@
// PROBLEM: none
abstract class Parent {
abstract val foo: Nothing?
}
class Child : Parent() {
override val <caret>foo = null
}
@@ -0,0 +1,7 @@
abstract class Parent {
abstract val foo: Int?
}
class Child : Parent() {
override val <caret>foo = null
}
@@ -0,0 +1,7 @@
abstract class Parent {
abstract val foo: Int?
}
class Child : Parent() {
override val foo: Nothing? = null
}
@@ -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");
}
}