[FE] Fix positioning strategy for SAFE_CALL_WILL_CHANGE_NULLABILITY warning
^KT-46860
This commit is contained in:
committed by
teamcity
parent
565c61a702
commit
078acb1bfe
+6
@@ -21176,6 +21176,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeAccessOnUnit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnNotNullableType.kt")
|
||||
public void testSafeCallOnNotNullableType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnTypeWithNullableUpperBound.kt")
|
||||
public void testSafeCallOnTypeWithNullableUpperBound() throws Exception {
|
||||
|
||||
+6
@@ -21176,6 +21176,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeAccessOnUnit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnNotNullableType.kt")
|
||||
public void testSafeCallOnNotNullableType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnTypeWithNullableUpperBound.kt")
|
||||
public void testSafeCallOnTypeWithNullableUpperBound() throws Exception {
|
||||
|
||||
+6
@@ -21176,6 +21176,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeAccessOnUnit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnNotNullableType.kt")
|
||||
public void testSafeCallOnNotNullableType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnTypeWithNullableUpperBound.kt")
|
||||
public void testSafeCallOnTypeWithNullableUpperBound() throws Exception {
|
||||
|
||||
+1
-1
@@ -1113,7 +1113,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val UNNECESSARY_SAFE_CALL by warning<PsiElement>(PositioningStrategy.SAFE_ACCESS) {
|
||||
parameter<ConeKotlinType>("receiverType")
|
||||
}
|
||||
val SAFE_CALL_WILL_CHANGE_NULLABILITY by warning<KtSafeQualifiedExpression>()
|
||||
val SAFE_CALL_WILL_CHANGE_NULLABILITY by warning<KtSafeQualifiedExpression>(PositioningStrategy.CALL_ELEMENT_WITH_DOT)
|
||||
val UNEXPECTED_SAFE_CALL by error<PsiElement>(PositioningStrategy.SAFE_ACCESS)
|
||||
val UNNECESSARY_NOT_NULL_ASSERTION by warning<KtExpression>(PositioningStrategy.OPERATOR) {
|
||||
parameter<ConeKotlinType>("receiverType")
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
DECLARATION_START_TO_NAME,
|
||||
REDUNDANT_NULLABLE,
|
||||
INLINE_FUN_MODIFIER,
|
||||
|
||||
CALL_ELEMENT_WITH_DOT,
|
||||
;
|
||||
|
||||
val expressionToCreate get() = "SourceElementPositioningStrategies.${strategy ?: name}"
|
||||
|
||||
+1
-1
@@ -592,7 +592,7 @@ object FirErrors {
|
||||
val UNSAFE_OPERATOR_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ITERATOR_ON_NULLABLE by error0<KtExpression>()
|
||||
val UNNECESSARY_SAFE_CALL by warning1<PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.SAFE_ACCESS)
|
||||
val SAFE_CALL_WILL_CHANGE_NULLABILITY by warning0<KtSafeQualifiedExpression>()
|
||||
val SAFE_CALL_WILL_CHANGE_NULLABILITY by warning0<KtSafeQualifiedExpression>(SourceElementPositioningStrategies.CALL_ELEMENT_WITH_DOT)
|
||||
val UNEXPECTED_SAFE_CALL by error0<PsiElement>(SourceElementPositioningStrategies.SAFE_ACCESS)
|
||||
val UNNECESSARY_NOT_NULL_ASSERTION by warning1<KtExpression, ConeKotlinType>(SourceElementPositioningStrategies.OPERATOR)
|
||||
val NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION by warning0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
|
||||
|
||||
+24
@@ -1120,6 +1120,30 @@ object LightTreePositioningStrategies {
|
||||
return markElement(byKeyword, startOffset, endOffset, tree, node)
|
||||
}
|
||||
}
|
||||
|
||||
val CALL_ELEMENT_WITH_DOT: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val callElementRanges = SELECTOR_BY_QUALIFIED.mark(node, startOffset, endOffset, tree)
|
||||
val callElementRange = when (callElementRanges.size) {
|
||||
1 -> callElementRanges.first()
|
||||
else -> return callElementRanges
|
||||
}
|
||||
|
||||
val dotRanges = SAFE_ACCESS.mark(node, startOffset, endOffset, tree)
|
||||
val dotRange = when (dotRanges.size) {
|
||||
1 -> dotRanges.first()
|
||||
else -> return dotRanges
|
||||
}
|
||||
|
||||
return listOf(TextRange(dotRange.startOffset, callElementRange.endOffset))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun KtSourceElement.hasValOrVar(): Boolean =
|
||||
|
||||
+19
@@ -499,6 +499,25 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val CALL_ELEMENT_WITH_DOT: PositioningStrategy<KtQualifiedExpression> = object : PositioningStrategy<KtQualifiedExpression>() {
|
||||
override fun mark(element: KtQualifiedExpression): List<TextRange> {
|
||||
val callElementRanges = SELECTOR_BY_QUALIFIED.mark(element)
|
||||
val callElementRange = when (callElementRanges.size) {
|
||||
1 -> callElementRanges.first()
|
||||
else -> return callElementRanges
|
||||
}
|
||||
|
||||
val dotRanges = SAFE_ACCESS.mark(element)
|
||||
val dotRange = when (dotRanges.size) {
|
||||
1 -> dotRanges.first()
|
||||
else -> return dotRanges
|
||||
}
|
||||
|
||||
return listOf(TextRange(dotRange.startOffset, callElementRange.endOffset))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val DECLARATION_WITH_BODY: PositioningStrategy<KtDeclarationWithBody> = object : PositioningStrategy<KtDeclarationWithBody>() {
|
||||
override fun mark(element: KtDeclarationWithBody): List<TextRange> {
|
||||
|
||||
+5
@@ -364,4 +364,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.DELEGATED_SUPERTYPE_BY_KEYWORD,
|
||||
PositioningStrategies.DELEGATED_SUPERTYPE_BY_KEYWORD
|
||||
)
|
||||
|
||||
val CALL_ELEMENT_WITH_DOT = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.CALL_ELEMENT_WITH_DOT,
|
||||
PositioningStrategies.CALL_ELEMENT_WITH_DOT
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1097,7 +1097,7 @@ public interface Errors {
|
||||
DiagnosticFactory3<KtExpression, PsiElement, String, PsiElement> UNSAFE_INFIX_CALL = DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory3<KtExpression, PsiElement, String, PsiElement> UNSAFE_OPERATOR_CALL = DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, KotlinType> UNNECESSARY_SAFE_CALL = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> SAFE_CALL_WILL_CHANGE_NULLABILITY = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtQualifiedExpression> SAFE_CALL_WILL_CHANGE_NULLABILITY = DiagnosticFactory0.create(WARNING, PositioningStrategies.CALL_ELEMENT_WITH_DOT);
|
||||
DiagnosticFactory0<PsiElement> UNEXPECTED_SAFE_CALL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, KotlinType> UNNECESSARY_NOT_NULL_ASSERTION = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
|
||||
fun ff() {
|
||||
val i: Int = 1
|
||||
val a: Int = <!SAFE_CALL_WILL_CHANGE_NULLABILITY!>i<!UNNECESSARY_SAFE_CALL!>?.<!>plus(2)<!>
|
||||
val a: Int = i<!SAFE_CALL_WILL_CHANGE_NULLABILITY!><!UNNECESSARY_SAFE_CALL!>?.<!>plus(2)<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@ fun foo(): String {
|
||||
}
|
||||
fun bar(): String {
|
||||
val x = fn() ?: return ""
|
||||
val y = <!SAFE_CALL_WILL_CHANGE_NULLABILITY!>x<!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() }<!> <!USELESS_ELVIS!>?: "unreachable"<!>
|
||||
val y = x<!SAFE_CALL_WILL_CHANGE_NULLABILITY!><!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() }<!> <!USELESS_ELVIS!>?: "unreachable"<!>
|
||||
return y
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ fun foo(): String {
|
||||
}
|
||||
fun bar(): String {
|
||||
val x = fn() ?: return ""
|
||||
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>y<!> =<!> <!SAFE_CALL_WILL_CHANGE_NULLABILITY!>x<!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() }<!> <!UNREACHABLE_CODE, USELESS_ELVIS!>?: "unreachable"<!>
|
||||
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>y<!> =<!> x<!SAFE_CALL_WILL_CHANGE_NULLABILITY!><!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() }<!> <!UNREACHABLE_CODE, USELESS_ELVIS!>?: "unreachable"<!>
|
||||
<!UNREACHABLE_CODE!>return y<!>
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// FIR_IDENTICAL
|
||||
// LANGUAGE: -SafeCallsAreAlwaysNullable
|
||||
// DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
// ISSUE: KT-46860
|
||||
|
||||
interface A {
|
||||
fun id(): A
|
||||
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun test_1(a: A) {
|
||||
val s = a.id().id().id().id().id().id().id().id()<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.foo()<!>.length
|
||||
}
|
||||
|
||||
fun test_2(a: A) {
|
||||
val s = a.id()
|
||||
.id()
|
||||
.id()
|
||||
.id()
|
||||
<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.id()<!>
|
||||
.id()
|
||||
.id()
|
||||
.id()
|
||||
<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.foo()<!>
|
||||
<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.length<!>
|
||||
}
|
||||
|
||||
fun test_3(a: A) {
|
||||
val s = a.id()<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.
|
||||
id()<!>.
|
||||
id()<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.
|
||||
foo()<!>.
|
||||
length
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public fun test_1(/*0*/ a: A): kotlin.Unit
|
||||
public fun test_2(/*0*/ a: A): kotlin.Unit
|
||||
public fun test_3(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract fun id(): A
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Generated
+6
@@ -21182,6 +21182,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeAccessOnUnit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnNotNullableType.kt")
|
||||
public void testSafeCallOnNotNullableType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallOnTypeWithNullableUpperBound.kt")
|
||||
public void testSafeCallOnTypeWithNullableUpperBound() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user