FIR: report UNSAFE_CALL on dot when possible
This commit is contained in:
@@ -15,7 +15,7 @@ fun test_2(x: Int?) {
|
||||
} else {
|
||||
x
|
||||
}
|
||||
y.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
y<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
|
||||
fun test_3(x: Int?) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ fun test3(x: AnotherClass?) {
|
||||
fun test4(x: SomeClass?) {
|
||||
val bar = x?.bar
|
||||
if (bar != null) {
|
||||
x.bar.<!UNSAFE_CALL!>length<!>
|
||||
x.bar<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ fun test_3(a: A?, b: Boolean) {
|
||||
if (b && a!!.foo()) {
|
||||
a.foo() // OK
|
||||
}
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!> // Bad
|
||||
a<!UNSAFE_CALL!>.<!>foo() // Bad
|
||||
}
|
||||
|
||||
fun test_4(a: A?, b: Boolean) {
|
||||
@@ -38,9 +38,9 @@ fun test_4(a: A?, b: Boolean) {
|
||||
|
||||
fun test_5(a: A?, b: Boolean) {
|
||||
if (b || a!!.foo()) {
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun <X : A?> test_6(x: X) {
|
||||
|
||||
+8
-8
@@ -8,13 +8,13 @@ fun test_1(b: Boolean?) {
|
||||
if ((b == true) == true) {
|
||||
b.not() // OK
|
||||
} else {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(b: Boolean?) {
|
||||
if ((b == true) != true) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
} else {
|
||||
b.not() // OK
|
||||
}
|
||||
@@ -22,7 +22,7 @@ fun test_2(b: Boolean?) {
|
||||
|
||||
fun test_3(b: Boolean?) {
|
||||
if ((b == true) == false) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
} else {
|
||||
b.not() // OK
|
||||
}
|
||||
@@ -32,13 +32,13 @@ fun test_4(b: Boolean?) {
|
||||
if ((b == true) != false) {
|
||||
b.not() // OK
|
||||
} else {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
}
|
||||
}
|
||||
|
||||
fun test_5(b: Boolean?) {
|
||||
if ((b != true) == true) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
} else {
|
||||
b.not() // OK
|
||||
}
|
||||
@@ -48,7 +48,7 @@ fun test_6(b: Boolean?) {
|
||||
if ((b != true) != true) {
|
||||
b.not() // OK
|
||||
} else {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +56,13 @@ fun test_7(b: Boolean?) {
|
||||
if ((b != true) == false) {
|
||||
b.not() // OK
|
||||
} else {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
}
|
||||
}
|
||||
|
||||
fun test_8(b: Boolean?) {
|
||||
if ((b != true) != false) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>not<!>()<!> // Bad
|
||||
b<!UNSAFE_CALL!>.<!>not() // Bad
|
||||
} else {
|
||||
b.not() // OK
|
||||
}
|
||||
|
||||
+6
-6
@@ -34,24 +34,24 @@ fun test_4(a: A?) {
|
||||
|
||||
fun test_5(a: A?) {
|
||||
a == null || throw Exception()
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun teat_6(a: A?) {
|
||||
a != null && throw Exception()
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun test_7(a: A?) {
|
||||
if (a == null || throw Exception()) {
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun test_8(a: A?) {
|
||||
if (a != null && throw Exception()) {
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/boundSmartcastsInBranches.kt
Vendored
+4
-4
@@ -104,18 +104,18 @@ fun test_7() {
|
||||
|
||||
if (x != null) {
|
||||
x.length // OK
|
||||
y.<!UNSAFE_CALL!>length<!> // Bad
|
||||
y<!UNSAFE_CALL!>.<!>length // Bad
|
||||
z.length // OK
|
||||
}
|
||||
if (y != null) {
|
||||
x.<!UNSAFE_CALL!>length<!> // Bad
|
||||
x<!UNSAFE_CALL!>.<!>length // Bad
|
||||
y.length // OK
|
||||
z.<!UNSAFE_CALL!>length<!> // Bad
|
||||
z<!UNSAFE_CALL!>.<!>length // Bad
|
||||
}
|
||||
|
||||
if (z != null) {
|
||||
x.length // OK
|
||||
y.<!UNSAFE_CALL!>length<!> // Bad
|
||||
y<!UNSAFE_CALL!>.<!>length // Bad
|
||||
z.length // OK
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -16,12 +16,12 @@ fun test_1(x: A, y: A?) {
|
||||
|
||||
fun test_2(x: A?, y: A?) {
|
||||
if (x == y) {
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
y.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
y<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
if (x === y) {
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
y.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
y<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,18 +39,18 @@ fun test_1(x: A?) {
|
||||
if (x != null) {
|
||||
x.foo()
|
||||
} else {
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun test_2(x: A?) {
|
||||
if (x == null) {
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
} else {
|
||||
x.foo()
|
||||
}
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun test_3(x: A?) {
|
||||
@@ -67,8 +67,8 @@ fun test_5(q: Q?) {
|
||||
// `q.data` is a property that has an open getter, so we can NOT smartcast it to non-nullable MyData.
|
||||
if (q?.data?.s?.inc() != null) {
|
||||
q.data // good
|
||||
q.data.<!UNSAFE_CALL!>s<!> // should be bad
|
||||
q.data.<!UNSAFE_CALL!>s<!>.inc() // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s.inc() // should be bad
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,15 +76,15 @@ fun test_6(q: Q?) {
|
||||
// `q.data` is a property that has an open getter, so we can NOT smartcast it to non-nullable MyData.
|
||||
q?.data?.s?.inc() ?: return
|
||||
q.data // good
|
||||
q.data.<!UNSAFE_CALL!>s<!> // should be bad
|
||||
q.data.<!UNSAFE_CALL!>s<!>.inc() // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s.inc() // should be bad
|
||||
}
|
||||
|
||||
fun test_7(q: Q?) {
|
||||
if (q?.fdata()?.fs()?.inc() != null) {
|
||||
q.fdata() // good
|
||||
q.fdata().<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>fs<!>()<!> // bad
|
||||
q.fdata().<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>fs<!>()<!>.inc() // bad
|
||||
q.fdata()<!UNSAFE_CALL!>.<!>fs() // bad
|
||||
q.fdata()<!UNSAFE_CALL!>.<!>fs().inc() // bad
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,44 +98,44 @@ fun test_9(a: Int, b: Int?) {
|
||||
if (a == b) {
|
||||
b.inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
|
||||
if (a === b) {
|
||||
b.inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
|
||||
if (b == a) {
|
||||
b.inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
|
||||
if (b === a) {
|
||||
b.inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
|
||||
fun test_10(a: Int?, b: Int?) {
|
||||
if (a == b) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
|
||||
if (a === b) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
|
||||
if (b == a) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
|
||||
if (b === a) {
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
b.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>inc<!>()<!>
|
||||
b<!UNSAFE_CALL!>.<!>inc()
|
||||
}
|
||||
|
||||
fun test_11(q: QImpl?, q2: QImpl) {
|
||||
@@ -148,8 +148,8 @@ fun test_11(q: QImpl?, q2: QImpl) {
|
||||
// Smartcasting of `q.data` should have no effect on `q2.data`.
|
||||
// Issue: Smartcasting of QImpl.data affects all instances
|
||||
q2.data
|
||||
q2.data.<!UNSAFE_CALL!>s<!> // should be bad
|
||||
q2.data.<!UNSAFE_CALL!>s<!>.inc() // should be bad
|
||||
q2.data<!UNSAFE_CALL!>.<!>s // should be bad
|
||||
q2.data<!UNSAFE_CALL!>.<!>s.inc() // should be bad
|
||||
|
||||
if (q2.data != null) {
|
||||
q2.data.s
|
||||
@@ -162,8 +162,8 @@ fun test_12(q: QImplWithCustomGetter?) {
|
||||
// `q.data` is a property that has an open getter, so we can NOT smartcast it to non-nullable MyData.
|
||||
if (q?.data?.s?.inc() != null) {
|
||||
q.data // good
|
||||
q.data.<!UNSAFE_CALL!>s<!> // should be bad
|
||||
q.data.<!UNSAFE_CALL!>s<!>.inc() // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s.inc() // should be bad
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ fun test_13(q: QImplMutable?) {
|
||||
// `q.data` is a property that is mutable, so we can NOT smartcast it to non-nullable MyData.
|
||||
if (q?.data?.s?.inc() != null) {
|
||||
q.data // good
|
||||
q.data.<!UNSAFE_CALL!>s<!> // should be bad
|
||||
q.data.<!UNSAFE_CALL!>s<!>.inc() // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s // should be bad
|
||||
q.data<!UNSAFE_CALL!>.<!>s.inc() // should be bad
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,6 @@ fun test_3(a: Any?, b: Boolean) {
|
||||
|
||||
fun test_4(a: Any?, b: Boolean) {
|
||||
if (a is String || b) {
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!> // Should be Bad
|
||||
a<!UNSAFE_CALL!>.<!>foo() // Should be Bad
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -5,7 +5,7 @@ fun test_1(s: String?) {
|
||||
if (s?.check() == true) {
|
||||
s.length // Should be OK
|
||||
} else {
|
||||
s.<!UNSAFE_CALL!>length<!> // Should be bad
|
||||
s<!UNSAFE_CALL!>.<!>length // Should be bad
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ fun test_2(s: String?) {
|
||||
if (s?.check() == false) {
|
||||
s.length // Should be OK
|
||||
} else {
|
||||
s.<!UNSAFE_CALL!>length<!> // Should be bad
|
||||
s<!UNSAFE_CALL!>.<!>length // Should be bad
|
||||
}
|
||||
}
|
||||
|
||||
fun test_3(s: String?) {
|
||||
if (s?.check() != true) {
|
||||
s.<!UNSAFE_CALL!>length<!> // Should be bad
|
||||
s<!UNSAFE_CALL!>.<!>length // Should be bad
|
||||
} else {
|
||||
s.length // Should be OK
|
||||
}
|
||||
@@ -27,7 +27,7 @@ fun test_3(s: String?) {
|
||||
|
||||
fun test_4(s: String?) {
|
||||
if (s?.check() != false) {
|
||||
s.<!UNSAFE_CALL!>length<!> // Should be bad
|
||||
s<!UNSAFE_CALL!>.<!>length // Should be bad
|
||||
} else {
|
||||
s.length // Should be OK
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ fun String.let(block: () -> Unit) {}
|
||||
|
||||
fun test(x: String?) {
|
||||
x?.foo(x.length == 1)
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
interface A {
|
||||
@@ -27,12 +27,12 @@ fun test_3(x: Any) {
|
||||
|
||||
fun test_4(x: A?) {
|
||||
x?.id()?.bool()
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>id<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>id()
|
||||
}
|
||||
|
||||
fun Any?.boo(b: Boolean) {}
|
||||
|
||||
fun test_5(x: A?) {
|
||||
x?.let { return }?.boo(x.bool())
|
||||
x.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>id<!>()<!>
|
||||
x<!UNSAFE_CALL!>.<!>id()
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,5 +11,5 @@ fun test(b: Boolean) {
|
||||
} else {
|
||||
a = null
|
||||
}
|
||||
a.<!UNSAFE_CALL{LT}!><!UNSAFE_CALL{PSI}!>foo<!>()<!>
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -18,5 +18,5 @@ fun test_3() {
|
||||
x = ""
|
||||
x.length
|
||||
x = null
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -7,7 +7,7 @@ fun test_1(s: String?) {
|
||||
fun test_2(s: String?) {
|
||||
// contracts related
|
||||
if (s.isNullOrEmpty()) {
|
||||
s.<!INAPPLICABLE_CANDIDATE{LT}, UNSAFE_CALL!>length<!> // Should be bad
|
||||
s<!UNSAFE_CALL!>.<!>length // Should be bad
|
||||
} else {
|
||||
s.length // Should be OK
|
||||
}
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ fun test_1(x: String?) {
|
||||
if (checkNotNull(x)) {
|
||||
x.length // OK
|
||||
} else {
|
||||
x.<!INAPPLICABLE_CANDIDATE{LT}, UNSAFE_CALL!>length<!> // Error
|
||||
x<!UNSAFE_CALL!>.<!>length // Error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ fun test_3(x: A?) {
|
||||
with(x) {
|
||||
myRequireNotNull()
|
||||
}
|
||||
x.<!INAPPLICABLE_CANDIDATE{LT}, UNSAFE_CALL!>foo<!>()
|
||||
x<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
|
||||
fun test_4(x: A?) {
|
||||
|
||||
-1
@@ -122,7 +122,6 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
|
||||
rootCause.actualType?.isNullable == true &&
|
||||
(rootCause.expectedType == null || !rootCause.expectedType!!.isMarkedNullable)
|
||||
) {
|
||||
// TODO: report on call operation node, e.g., x<!>.<!>length instead of x.<!>length<!>
|
||||
val expectedType = rootCause.expectedType
|
||||
|
||||
if (expectedType == null || expectedType.isEffectivelyNotNull()) {
|
||||
|
||||
+1
-1
@@ -209,7 +209,7 @@ object FirErrors {
|
||||
val WRONG_IMPLIES_CONDITION by warning0<FirSourceElement, PsiElement>()
|
||||
|
||||
// Nullability
|
||||
val UNSAFE_CALL by error1<FirSourceElement, PsiElement, ConeKotlinType>()
|
||||
val UNSAFE_CALL by error1<FirSourceElement, PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.DOT_BY_SELECTOR)
|
||||
// TODO: val UNSAFE_IMPLICIT_INVOKE_CALL by error1<FirSourceElement, PsiElement, ConeKotlinType>()
|
||||
// TODO: val UNSAFE_INFIX_CALL by ...
|
||||
// TODO: val UNSAFE_OPERATOR_CALL by ...
|
||||
|
||||
+23
@@ -271,6 +271,26 @@ object LightTreePositioningStrategies {
|
||||
return markElement(modifier ?: node, startOffset, endOffset, tree, node)
|
||||
}
|
||||
}
|
||||
|
||||
val DOT_BY_SELECTOR: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
if (node.tokenType != KtNodeTypes.REFERENCE_EXPRESSION && node.tokenType != KtNodeTypes.CALL_EXPRESSION) {
|
||||
// TODO: normally CALL_EXPRESSION should not be here. In PSI we have REFERENCE_EXPRESSION even for x.bar() case
|
||||
// Remove CALL_EXPRESSION from here and repeat code below twice (see PSI counterpart) when fixed
|
||||
return super.mark(node, startOffset, endOffset, tree)
|
||||
}
|
||||
val parentNode = tree.getParent(node) ?: return super.mark(node, startOffset, endOffset, tree)
|
||||
if (parentNode.tokenType == KtNodeTypes.DOT_QUALIFIED_EXPRESSION) {
|
||||
return markElement(tree.dotOperator(parentNode) ?: node, startOffset, endOffset, tree, node)
|
||||
}
|
||||
return super.mark(node, startOffset, endOffset, tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirSourceElement.hasValOrVar(): Boolean =
|
||||
@@ -285,6 +305,9 @@ fun FirSourceElement.hasPrimaryConstructor(): Boolean =
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.constructorKeyword(node: LighterASTNode): LighterASTNode? =
|
||||
findChildByType(node, KtTokens.CONSTRUCTOR_KEYWORD)
|
||||
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.dotOperator(node: LighterASTNode): LighterASTNode? =
|
||||
findChildByType(node, KtTokens.DOT)
|
||||
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.initKeyword(node: LighterASTNode): LighterASTNode? =
|
||||
findChildByType(node, KtTokens.INIT_KEYWORD)
|
||||
|
||||
|
||||
+5
@@ -62,4 +62,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.PARAMETER_VARARG_MODIFIER,
|
||||
PositioningStrategies.PARAMETER_VARARG_MODIFIER
|
||||
)
|
||||
|
||||
val DOT_BY_SELECTOR = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.DOT_BY_SELECTOR,
|
||||
PositioningStrategies.DOT_BY_SELECTOR
|
||||
)
|
||||
}
|
||||
@@ -703,4 +703,19 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val DOT_BY_SELECTOR: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun mark(element: PsiElement): List<TextRange> {
|
||||
when (element) {
|
||||
is KtNameReferenceExpression -> {
|
||||
var parent = element
|
||||
repeat(2) {
|
||||
parent = parent.parent
|
||||
(parent as? KtDotQualifiedExpression)?.operationTokenNode?.psi?.let { return mark(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mark(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class C {
|
||||
while (a == null) {
|
||||
break;
|
||||
}
|
||||
a.<!UNSAFE_CALL!>compareTo<!>("2")
|
||||
a<!UNSAFE_CALL!>.<!>compareTo("2")
|
||||
}
|
||||
|
||||
fun notContainsBreak(a: String?, b: String?) {
|
||||
@@ -70,7 +70,7 @@ class C {
|
||||
break@l
|
||||
}
|
||||
}
|
||||
a.<!UNSAFE_CALL!>compareTo<!>("2")
|
||||
a<!UNSAFE_CALL!>.<!>compareTo("2")
|
||||
}
|
||||
|
||||
fun unresolvedBreak(a: String?, array: Array<Int>) {
|
||||
@@ -80,7 +80,7 @@ class C {
|
||||
}
|
||||
if (true) break else <!NOT_A_LOOP_LABEL!>break@l<!>
|
||||
}
|
||||
a.<!UNSAFE_CALL!>compareTo<!>("2")
|
||||
a<!UNSAFE_CALL!>.<!>compareTo("2")
|
||||
}
|
||||
|
||||
fun twoLabelsOnLoop() {
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ fun test() {
|
||||
|
||||
fun f(out : String?) {
|
||||
out?.get(0)
|
||||
out.<!UNSAFE_CALL!>get<!>(0)
|
||||
out<!UNSAFE_CALL!>.<!>get(0)
|
||||
if (out != null) else return;
|
||||
out.get(0)
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -7,7 +7,7 @@ operator fun <K> Container<K>.iterator(): Iterator<K> = null!!
|
||||
fun test() {
|
||||
val container: Container<String>? = null
|
||||
// Error
|
||||
container.<!UNSAFE_CALL!>iterator<!>()
|
||||
container<!UNSAFE_CALL!>.<!>iterator()
|
||||
// for extension iterator, this code compiles, but should not
|
||||
<!UNSAFE_CALL!>for (s in container) {}<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,6 +10,6 @@ fun test(a: Any?, flag: Boolean, x: Any?) {
|
||||
}
|
||||
else {
|
||||
b = x
|
||||
b.<!UNSAFE_CALL!>hashCode<!>()
|
||||
b<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ import outer.*
|
||||
|
||||
command.foo
|
||||
|
||||
command.<!UNSAFE_CALL!>equals<!>(null)
|
||||
command<!UNSAFE_CALL!>.<!>equals(null)
|
||||
command?.equals(null)
|
||||
command.equals1(null)
|
||||
command?.equals1(null)
|
||||
|
||||
@@ -9,13 +9,13 @@ interface T {
|
||||
}
|
||||
|
||||
fun test(t: T) {
|
||||
t.<!UNSAFE_CALL!>f<!>(1) //unsafe call error
|
||||
t<!UNSAFE_CALL!>.<!>f(1) //unsafe call error
|
||||
t.f?.invoke(1)
|
||||
}
|
||||
|
||||
fun test1(t: T?) {
|
||||
t.<!UNRESOLVED_REFERENCE!>f<!>(1) // todo resolve f as value and report UNSAFE_CALL
|
||||
t?.<!UNSAFE_CALL!>f<!>(1)
|
||||
t.<!UNSAFE_CALL!>f<!>?.invoke(1)
|
||||
t<!UNSAFE_CALL!>.<!>f?.invoke(1)
|
||||
t?.f?.invoke(1)
|
||||
}
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ fun <R> List<R>.a() {}
|
||||
|
||||
fun test1(i: Int?) {
|
||||
1.<!INAPPLICABLE_CANDIDATE!>a<!>()
|
||||
i.<!UNSAFE_CALL!>a<!>()
|
||||
i<!UNSAFE_CALL!>.<!>a()
|
||||
}
|
||||
|
||||
fun <R> test2(c: Collection<R>) {
|
||||
@@ -19,7 +19,7 @@ fun Int.foo() {}
|
||||
|
||||
fun test3(s: String?) {
|
||||
"".<!INAPPLICABLE_CANDIDATE!>foo<!>()
|
||||
s.<!UNSAFE_CALL!>foo<!>()
|
||||
s<!UNSAFE_CALL!>.<!>foo()
|
||||
"".<!INAPPLICABLE_CANDIDATE!>foo<!>(1)
|
||||
s.<!INAPPLICABLE_CANDIDATE!>foo<!>("a")
|
||||
}
|
||||
@@ -52,5 +52,5 @@ fun test7(l: List<String?>) {
|
||||
}
|
||||
|
||||
fun test8(l: List<Any>?) {
|
||||
l.<!UNSAFE_CALL!>b<!>()
|
||||
l<!UNSAFE_CALL!>.<!>b()
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -23,7 +23,7 @@ fun testNoSmartCast1(s: String?) {
|
||||
if (s != null) ""
|
||||
else noSmartCast1(null) { "" }
|
||||
)
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
fun testNoSmartCast2(s: String?) {
|
||||
@@ -31,7 +31,7 @@ fun testNoSmartCast2(s: String?) {
|
||||
if (s != null) ( {""} )
|
||||
else noSmartCast2(null) { "" }
|
||||
)
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
fun testNoSmartCast3(s: String?) {
|
||||
@@ -39,7 +39,7 @@ fun testNoSmartCast3(s: String?) {
|
||||
if (s != null) ""
|
||||
else noSmartCast3(null) { "" }
|
||||
)
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
// KT-36069
|
||||
@@ -48,5 +48,5 @@ fun testNoSmartCast4(s: String?) {
|
||||
if (s != null) ( {""} )
|
||||
else noSmartCast4(null) { "" }
|
||||
)
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ package c
|
||||
interface A<T>
|
||||
|
||||
fun test(a: A<Int>?) {
|
||||
a.<!UNSAFE_CALL!>foo<!>() //no error
|
||||
a<!UNSAFE_CALL!>.<!>foo() //no error
|
||||
}
|
||||
|
||||
fun <R> A<R>.foo() {}
|
||||
|
||||
//------------
|
||||
fun test(nullabilityInfoMap: Map<Int, Any>?) {
|
||||
nullabilityInfoMap.<!UNSAFE_CALL!>iterator<!>() //no error
|
||||
nullabilityInfoMap<!UNSAFE_CALL!>.<!>iterator() //no error
|
||||
}
|
||||
|
||||
//resolves to
|
||||
@@ -20,7 +20,7 @@ public fun <K,V> Map<K,V>.iterator(): Iterator<Map.Entry<K,V>> {}
|
||||
//-------------
|
||||
fun foo() : Boolean {
|
||||
val nullableList = getNullableList()
|
||||
return nullableList.<!UNSAFE_CALL!>contains<!>("")
|
||||
return nullableList<!UNSAFE_CALL!>.<!>contains("")
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ public interface J2 extends J {
|
||||
// FILE: main.kt
|
||||
fun main() {
|
||||
<!INAPPLICABLE_CANDIDATE!>J<!> { s: String -> s} // should be prohibited, because SAM value parameter has nullable type
|
||||
J { "" + it.<!UNSAFE_CALL!>length<!> }
|
||||
J { "" + it<!UNSAFE_CALL!>.<!>length }
|
||||
J { null }
|
||||
J { it?.length?.toString() }
|
||||
|
||||
<!INAPPLICABLE_CANDIDATE!>J2<!> { s: String -> s}
|
||||
J2 { "" + it.<!UNSAFE_CALL!>length<!> }
|
||||
J2 { "" + it<!UNSAFE_CALL!>.<!>length }
|
||||
J2 { null }
|
||||
J2 { it?.length?.toString() }
|
||||
}
|
||||
|
||||
+5
-5
@@ -13,18 +13,18 @@ fun test(x : Int?, a : A?) {
|
||||
x?.plus(1)
|
||||
x <!NONE_APPLICABLE!>+<!> 1
|
||||
<!UNSAFE_CALL!>-<!>x
|
||||
x.<!UNSAFE_CALL!>unaryMinus<!>()
|
||||
x<!UNSAFE_CALL!>.<!>unaryMinus()
|
||||
x?.unaryMinus()
|
||||
|
||||
a.<!UNSAFE_CALL!>plus<!>(1)
|
||||
a<!UNSAFE_CALL!>.<!>plus(1)
|
||||
a?.plus(1)
|
||||
a <!UNSAFE_CALL!>plus<!> 1
|
||||
a <!UNSAFE_CALL!>+<!> 1
|
||||
<!UNSAFE_CALL!>-<!>a
|
||||
a.<!UNSAFE_CALL!>unaryMinus<!>()
|
||||
a<!UNSAFE_CALL!>.<!>unaryMinus()
|
||||
a?.unaryMinus()
|
||||
|
||||
a.<!UNSAFE_CALL!>div<!>(1)
|
||||
a<!UNSAFE_CALL!>.<!>div(1)
|
||||
a <!UNSAFE_CALL!>/<!> 1
|
||||
a <!UNSAFE_CALL!>div<!> 1
|
||||
a?.div(1)
|
||||
@@ -36,6 +36,6 @@ fun test(x : Int?, a : A?) {
|
||||
|
||||
1 <!UNSAFE_CALL!>in<!> a
|
||||
a <!UNSAFE_CALL!>contains<!> 1
|
||||
a.<!UNSAFE_CALL!>contains<!>(1)
|
||||
a<!UNSAFE_CALL!>.<!>contains(1)
|
||||
a?.contains(1)
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -7,7 +7,7 @@ fun main() {
|
||||
val x: Foo? = null
|
||||
val y: Foo? = null
|
||||
|
||||
x.<!UNSAFE_CALL!>foo<!>(y)
|
||||
x<!UNSAFE_CALL!>.<!>foo(y)
|
||||
x!!.<!INAPPLICABLE_CANDIDATE!>foo<!>(y)
|
||||
x.foo(y!!)
|
||||
x!!.foo(y!!)
|
||||
@@ -16,8 +16,8 @@ fun main() {
|
||||
val b: Foo? = null
|
||||
val c: Foo? = null
|
||||
|
||||
a.<!UNSAFE_CALL!>foo<!>(b.<!UNSAFE_CALL!>foo<!>(c))
|
||||
a!!.foo(b.<!UNSAFE_CALL!>foo<!>(c))
|
||||
a<!UNSAFE_CALL!>.<!>foo(b<!UNSAFE_CALL!>.<!>foo(c))
|
||||
a!!.foo(b<!UNSAFE_CALL!>.<!>foo(c))
|
||||
a.foo(b!!.<!INAPPLICABLE_CANDIDATE!>foo<!>(c))
|
||||
a!!.foo(b!!.<!INAPPLICABLE_CANDIDATE!>foo<!>(c))
|
||||
a.foo(b.foo(c!!))
|
||||
|
||||
+4
-4
@@ -6,8 +6,8 @@ fun A.bar() {}
|
||||
fun A?.buzz() {}
|
||||
|
||||
fun test(a : A?) {
|
||||
a.<!UNSAFE_CALL!>foo<!>() // error
|
||||
a.<!UNSAFE_CALL!>bar<!>() // error
|
||||
a<!UNSAFE_CALL!>.<!>foo() // error
|
||||
a<!UNSAFE_CALL!>.<!>bar() // error
|
||||
a.buzz()
|
||||
|
||||
a?.foo()
|
||||
@@ -34,8 +34,8 @@ fun A?.test3() {
|
||||
<!UNSAFE_CALL!>bar<!>() // error
|
||||
buzz()
|
||||
|
||||
this.<!UNSAFE_CALL!>foo<!>() // error
|
||||
this.<!UNSAFE_CALL!>bar<!>() // error
|
||||
this<!UNSAFE_CALL!>.<!>foo() // error
|
||||
this<!UNSAFE_CALL!>.<!>bar() // error
|
||||
this.buzz()
|
||||
|
||||
this?.foo()
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
//KT-1270 Poor highlighting when trying to dereference a nullable reference
|
||||
|
||||
package kt1270
|
||||
|
||||
fun foo() {
|
||||
val sc = java.util.HashMap<String, SomeClass>()[""]
|
||||
val value = sc.<!UNSAFE_CALL!>value<!>
|
||||
}
|
||||
|
||||
private class SomeClass() {
|
||||
val value : Int = 5
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
//KT-1270 Poor highlighting when trying to dereference a nullable reference
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ package e
|
||||
fun main() {
|
||||
val compareTo = 1
|
||||
val s: String? = null
|
||||
s.<!UNSAFE_CALL!>compareTo<!>("")
|
||||
s<!UNSAFE_CALL!>.<!>compareTo("")
|
||||
|
||||
val bar = 2
|
||||
s.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
// FILE: A.java
|
||||
|
||||
// It's supposed that there is no JSR-305 annotation in classpath
|
||||
public interface A<T> {
|
||||
public boolean foo(@javax.annotation.Nullable T y) {}
|
||||
}
|
||||
|
||||
// FILE: B.java
|
||||
|
||||
public class B {
|
||||
public static void bar(A<String> y) {}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
fun test() {
|
||||
B.bar() { it.<!UNSAFE_CALL!>hashCode<!>() > 0 }
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: A.java
|
||||
|
||||
// It's supposed that there is no JSR-305 annotation in classpath
|
||||
|
||||
Vendored
-45
@@ -1,45 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
public class J {
|
||||
@NotNull
|
||||
public static J staticNN;
|
||||
@Nullable
|
||||
public static J staticN;
|
||||
public static J staticJ;
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
// @NotNull platform type
|
||||
val platformNN = J.staticNN
|
||||
// @Nullable platform type
|
||||
val platformN = J.staticN
|
||||
// platform type with no annotation
|
||||
val platformJ = J.staticJ
|
||||
|
||||
platformNN.foo()
|
||||
platformN.<!UNSAFE_CALL!>foo<!>()
|
||||
platformJ.foo()
|
||||
|
||||
with(platformNN) {
|
||||
foo()
|
||||
}
|
||||
with(platformN) {
|
||||
<!UNSAFE_CALL!>foo<!>()
|
||||
}
|
||||
with(platformJ) {
|
||||
foo()
|
||||
}
|
||||
|
||||
platformNN.bar()
|
||||
platformN.bar()
|
||||
platformJ.bar()
|
||||
}
|
||||
|
||||
fun J.foo() {}
|
||||
fun J?.bar() {}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
Vendored
-40
@@ -1,40 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
public class J {
|
||||
@NotNull
|
||||
public static J staticNN;
|
||||
@Nullable
|
||||
public static J staticN;
|
||||
public static J staticJ;
|
||||
|
||||
public void foo() {}
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
// @NotNull platform type
|
||||
val platformNN = J.staticNN
|
||||
// @Nullable platform type
|
||||
val platformN = J.staticN
|
||||
// platform type with no annotation
|
||||
val platformJ = J.staticJ
|
||||
|
||||
platformNN.foo()
|
||||
platformN.<!UNSAFE_CALL!>foo<!>()
|
||||
platformJ.foo()
|
||||
|
||||
with(platformNN) {
|
||||
foo()
|
||||
}
|
||||
with(platformN) {
|
||||
<!UNSAFE_CALL!>foo<!>()
|
||||
}
|
||||
with(platformJ) {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ public class J {
|
||||
|
||||
fun test() {
|
||||
J.staticNN()
|
||||
J.<!UNSAFE_CALL!>staticN<!>()
|
||||
J<!UNSAFE_CALL!>.<!>staticN()
|
||||
J.staticJ()
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// KT-6829 False warning on map to @Nullable
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
public class J {
|
||||
|
||||
@Nullable
|
||||
public String method() { return ""; }
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun foo(collection: Collection<J>) {
|
||||
val mapped = collection.map { it.method() }
|
||||
mapped[0].<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
|
||||
public fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
|
||||
null!!
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// KT-6829 False warning on map to @Nullable
|
||||
|
||||
Vendored
+2
-2
@@ -8,8 +8,8 @@ class E : B1() {
|
||||
fun baz() {
|
||||
val x: String? = ""
|
||||
|
||||
x.<!UNSAFE_CALL!>foo<!>(x)
|
||||
x.<!UNSAFE_CALL!>foo<!>("")
|
||||
x<!UNSAFE_CALL!>.<!>foo(x)
|
||||
x<!UNSAFE_CALL!>.<!>foo("")
|
||||
x.<!INAPPLICABLE_CANDIDATE!>bar<!>(x)
|
||||
x.bar("")
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class C(override val t: Any?) : B<Any?, Any>
|
||||
fun f(b: B<*, Any>) {
|
||||
val y = b.t
|
||||
if (y is String?) {
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ fun Array<String>.length() : Int {
|
||||
}
|
||||
|
||||
fun test(array : Array<String?>?) {
|
||||
array?.sure<Array<String?>>().<!UNSAFE_CALL!>length<!>()
|
||||
array?.sure<Array<String?>>()<!UNSAFE_CALL!>.<!>length()
|
||||
}
|
||||
|
||||
+6
-6
@@ -12,7 +12,7 @@ class Another1 {
|
||||
|
||||
fun Another1.main(x: Bar1<String>?) {
|
||||
x?.value {}
|
||||
x?.value.<!UNSAFE_CALL!>invoke<!>({})
|
||||
x?.value<!UNSAFE_CALL!>.<!>invoke({})
|
||||
}
|
||||
|
||||
// Test case 2: additional receiver, non-generic invoke
|
||||
@@ -26,7 +26,7 @@ class Another2 {
|
||||
|
||||
fun Another2.main(x: Bar2<String>?) {
|
||||
x?.value(1)
|
||||
x?.value.<!UNSAFE_CALL!>invoke<!>(1)
|
||||
x?.value<!UNSAFE_CALL!>.<!>invoke(1)
|
||||
}
|
||||
|
||||
// Test case 3: additional generic receiver, generic invoke
|
||||
@@ -40,7 +40,7 @@ class Another3<T> {
|
||||
|
||||
fun <K> Another3<K>.main(x: Bar3<K>?) {
|
||||
x?.value(1)
|
||||
x?.value.<!UNSAFE_CALL!>invoke<!>(1)
|
||||
x?.value<!UNSAFE_CALL!>.<!>invoke(1)
|
||||
}
|
||||
|
||||
// Test case 4: additional receiver, generic invoke with nullable receiver
|
||||
@@ -68,7 +68,7 @@ class Another5 {
|
||||
|
||||
fun Another5.main(x: Bar5?) {
|
||||
x?.value {}
|
||||
x?.value.<!UNSAFE_CALL!>invoke<!>({})
|
||||
x?.value<!UNSAFE_CALL!>.<!>invoke({})
|
||||
}
|
||||
|
||||
// Test case 6: top-level generic invoke
|
||||
@@ -96,7 +96,7 @@ operator fun <T> Foo7<T>.invoke(x: Int) {}
|
||||
|
||||
fun Another7.main(x: Bar7<String>?) {
|
||||
x?.value(1)
|
||||
x?.value.<!UNSAFE_CALL!>invoke<!>(1)
|
||||
x?.value<!UNSAFE_CALL!>.<!>invoke(1)
|
||||
}
|
||||
|
||||
// Test case 8: top-level non-generic invoke
|
||||
@@ -136,5 +136,5 @@ class Another10 {
|
||||
|
||||
fun Another10.main(x: Bar10<String>?) {
|
||||
x?.value {}
|
||||
x?.value.<!UNSAFE_CALL!>invoke<!>({})
|
||||
x?.value<!UNSAFE_CALL!>.<!>invoke({})
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ fun test(a: A) {
|
||||
(a.x)("")
|
||||
}
|
||||
"".<!UNRESOLVED_REFERENCE!>(a.x)()<!>
|
||||
a.<!UNSAFE_CALL!>x<!>("")
|
||||
a<!UNSAFE_CALL!>.<!>x("")
|
||||
<!UNSAFE_CALL!>(a.x)("")<!>
|
||||
|
||||
with("") {
|
||||
|
||||
@@ -30,7 +30,7 @@ fun testNullableReceiver(nullable: Cls?) {
|
||||
}
|
||||
|
||||
fun testNotNullableReceiver(notNullable: Cls) {
|
||||
notNullable.<!UNSAFE_CALL!>nullableExtensionProperty<!>()
|
||||
notNullable<!UNSAFE_CALL!>.<!>nullableExtensionProperty()
|
||||
notNullable?.extensionProperty()
|
||||
}
|
||||
|
||||
@@ -38,6 +38,6 @@ fun testFlexibleReceiver() {
|
||||
val flexible = JavaClass.createFlexible()
|
||||
flexible.extensionProperty()
|
||||
flexible?.extensionProperty()
|
||||
flexible.<!UNSAFE_CALL!>nullableExtensionProperty<!>()
|
||||
flexible<!UNSAFE_CALL!>.<!>nullableExtensionProperty()
|
||||
flexible?.<!UNSAFE_CALL!>nullableExtensionProperty<!>()
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
|
||||
fun f(s: String, action: (String.() -> Unit)?) {
|
||||
s.foo().bar().<!UNSAFE_CALL!>action<!>()
|
||||
s.foo().bar()<!UNSAFE_CALL!>.<!>action()
|
||||
}
|
||||
|
||||
fun String.foo() = ""
|
||||
|
||||
@@ -3,7 +3,7 @@ fun foo(): String {
|
||||
var s: String?
|
||||
s = null
|
||||
s?.length
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
if (s == null) return s!!
|
||||
var t: String? = "y"
|
||||
if (t == null) t = "x"
|
||||
|
||||
@@ -13,7 +13,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val b = (a as? SomeSubClass)?.foo
|
||||
@@ -21,7 +21,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val c = a as? SomeSubClass
|
||||
@@ -29,7 +29,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' and 'c' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val b = (a as? SomeSubClass)?.foo
|
||||
@@ -21,7 +21,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val c = a as? SomeSubClass
|
||||
@@ -29,7 +29,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' and 'c' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
|
||||
@@ -18,18 +18,18 @@ fun g(a: SomeClass?) {
|
||||
b = "Hello"
|
||||
if (b != null) {
|
||||
// 'a' cannot be cast to SomeSubClass!
|
||||
a.<!UNSAFE_CALL!>hashCode<!>()
|
||||
a<!UNSAFE_CALL!>.<!>hashCode()
|
||||
a.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
var c = a as? SomeSubClass
|
||||
c = Impl
|
||||
if (c != null) {
|
||||
// 'a' cannot be cast to SomeSubClass
|
||||
a.<!UNSAFE_CALL!>hashCode<!>()
|
||||
a<!UNSAFE_CALL!>.<!>hashCode()
|
||||
a.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
@@ -41,18 +41,18 @@ fun f(a: SomeClass?) {
|
||||
if (aa as? SomeSubClass != null) {
|
||||
aa = null
|
||||
// 'aa' cannot be cast to SomeSubClass
|
||||
aa.<!UNSAFE_CALL!>hashCode<!>()
|
||||
aa<!UNSAFE_CALL!>.<!>hashCode()
|
||||
aa.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(aa as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(aa as SomeSubClass).foo
|
||||
}
|
||||
val b = (aa as? SomeSubClass)?.foo
|
||||
aa = null
|
||||
if (b != null) {
|
||||
// 'aa' cannot be cast to SomeSubClass
|
||||
aa.<!UNSAFE_CALL!>hashCode<!>()
|
||||
aa<!UNSAFE_CALL!>.<!>hashCode()
|
||||
aa.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(aa as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(aa as SomeSubClass).foo
|
||||
}
|
||||
aa = a
|
||||
@@ -61,7 +61,7 @@ fun f(a: SomeClass?) {
|
||||
// 'c' can be cast to SomeSubClass
|
||||
aa.hashCode()
|
||||
aa.foo
|
||||
(aa as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
|
||||
@@ -6,30 +6,30 @@ fun foo(x : String?, y : String?) {
|
||||
y.length
|
||||
}
|
||||
else {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
if (y != null || x == y) {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
// y == null but x != y
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
if (y == null && x != y) {
|
||||
// y == null but x != y
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
if (y == null || x != y) {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
// Both not null
|
||||
|
||||
@@ -3,21 +3,21 @@ fun foo(x: String?, y: String?, z: String?, w: String?) {
|
||||
if (x != null && y != null && (x == z || y == z))
|
||||
z.length
|
||||
else
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
if (x != null || y != null || (x != z && y != z))
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
else
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
if (x == null || y == null || (x != z && y != z))
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
else
|
||||
z.length
|
||||
if (x != null && y == x && z == y && w == z)
|
||||
w.length
|
||||
else
|
||||
w.<!UNSAFE_CALL!>length<!>
|
||||
w<!UNSAFE_CALL!>.<!>length
|
||||
if ((x != null && y == x) || (z != null && y == z))
|
||||
y.length
|
||||
else
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,26 +1,26 @@
|
||||
fun foo(x: String?, y: String?, z: String?) {
|
||||
if ((x!!.hashCode() == 0 || y!!.hashCode() == 1) && z!!.hashCode() == 2) {
|
||||
x.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
// condition is true => z!! after and is called
|
||||
z.length
|
||||
}
|
||||
else {
|
||||
x.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// First element is always analyzed
|
||||
x.length
|
||||
var xx = y ?: z
|
||||
if ((xx!!.hashCode() == 0 && y!!.hashCode() == 1) || z!!.hashCode() == 2) {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
// condition is false => z!! after or is called
|
||||
z.length
|
||||
}
|
||||
@@ -35,16 +35,16 @@ fun foo(x: String?, y: String?, z: String?) {
|
||||
}
|
||||
else {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// First element is always analyzed
|
||||
x.length
|
||||
xx = y ?: z
|
||||
if (xx!!.hashCode() == 0 || y!!.hashCode() == 1 || z!!.hashCode() == 2) {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
// all three are called
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// !LANGUAGE: -BooleanElvisBoundSmartCasts
|
||||
|
||||
interface Order {
|
||||
val expired: Boolean?
|
||||
|
||||
fun notExpired(): Boolean
|
||||
|
||||
fun doSomething()
|
||||
}
|
||||
|
||||
fun foo(o: Any) {
|
||||
val order = o as? Order
|
||||
if (order?.expired ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
if (order?.notExpired() ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(o: Any) {
|
||||
val order = o as? Order
|
||||
if (order?.expired ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
order!!.doSomething()
|
||||
}
|
||||
if (order?.notExpired() ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
order!!.doSomething()
|
||||
}
|
||||
}
|
||||
|
||||
fun baz(o: Boolean?) {
|
||||
if (o ?: false) {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
if (o ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: -BooleanElvisBoundSmartCasts
|
||||
|
||||
interface Order {
|
||||
|
||||
@@ -11,13 +11,13 @@ interface Order {
|
||||
fun foo(o: Any) {
|
||||
val order = o as? Order
|
||||
if (order?.expired ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
order<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
if (order?.notExpired() ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
order<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ fun bar(o: Any) {
|
||||
|
||||
fun baz(o: Boolean?) {
|
||||
if (o ?: false) {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
o<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
if (o ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
o<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Based on KT-9100
|
||||
fun test(x: Any?, y: Any?): Any {
|
||||
val z = x ?: y!!
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
// !! / ?. is necessary here, because y!! above may not be executed
|
||||
y?.hashCode()
|
||||
y!!.hashCode()
|
||||
return z
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// Based on KT-9100
|
||||
fun test(x: Any?, y: Any?): Any {
|
||||
val z = x ?: y!!
|
||||
|
||||
@@ -4,7 +4,7 @@ class C {
|
||||
|
||||
fun test(a: C?, nn: () -> Nothing?) {
|
||||
a ?: nn()
|
||||
a.<!UNSAFE_CALL!>foo<!>()
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
|
||||
a ?: return
|
||||
a.foo()
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun printMessages() {
|
||||
Message.HELLO.text!!
|
||||
Message.HELLO.text.length
|
||||
|
||||
Message.NOTHING.text.<!UNSAFE_CALL!>length<!>
|
||||
Message.NOTHING.text<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
Message.NOTHING.text!!
|
||||
Message.NOTHING.text.length
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun printMessages() {
|
||||
Message.HELLO.text!!
|
||||
Message.HELLO.text.length
|
||||
|
||||
Message.NOTHING.text.<!UNSAFE_CALL!>length<!>
|
||||
Message.NOTHING.text<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
Message.NOTHING.text!!
|
||||
Message.NOTHING.text.length
|
||||
|
||||
@@ -2,12 +2,12 @@ class D(val a: String, val b: Boolean)
|
||||
|
||||
fun foo(p: Boolean, v: D?): String {
|
||||
if (p && v!!.b) v.a
|
||||
else v.<!UNSAFE_CALL!>a<!>
|
||||
else v<!UNSAFE_CALL!>.<!>a
|
||||
if (p && v!! == D("?", false)) v.a
|
||||
else v.<!UNSAFE_CALL!>a<!>
|
||||
if (p || v!!.b) v.<!UNSAFE_CALL!>a<!>
|
||||
else v<!UNSAFE_CALL!>.<!>a
|
||||
if (p || v!!.b) v<!UNSAFE_CALL!>.<!>a
|
||||
else v.a
|
||||
if (p || v!! == D("?", false)) v.<!UNSAFE_CALL!>a<!>
|
||||
if (p || v!! == D("?", false)) v<!UNSAFE_CALL!>.<!>a
|
||||
else v.a
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ fun <T> T?.let(f: (T) -> Unit) {
|
||||
fun test(your: Your?) {
|
||||
(your?.foo() as? Any)?.let {}
|
||||
// strange smart cast to 'Your' at this point
|
||||
your.<!UNSAFE_CALL!>hashCode<!>()
|
||||
your<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_NOT_NULL_ASSERTION
|
||||
// See KT-9126: Variable change does not affect data flow info for its fields
|
||||
|
||||
class My(val x: Int?)
|
||||
|
||||
fun foo() {
|
||||
var y: My? = My(42)
|
||||
if (y!!.x != null) {
|
||||
y = My(null)
|
||||
y!!.x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNNECESSARY_NOT_NULL_ASSERTION
|
||||
// See KT-9126: Variable change does not affect data flow info for its fields
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ fun foo() {
|
||||
var y: My? = My(42)
|
||||
if (y!!.x != null) {
|
||||
y = My(null)
|
||||
(y + My(0)).x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
(y + My(0)).x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ class A<E> {
|
||||
class B(var a: A<*>?) {
|
||||
fun bar() {
|
||||
if (a != null) {
|
||||
a.<!UNSAFE_CALL!>foo<!>()
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ inline fun <R> callItContracted(fn: () -> R): R {
|
||||
|
||||
fun smartIt(p1: String?, p2: String?) {
|
||||
p1 ?: callIt { return }
|
||||
p1.<!UNSAFE_CALL!>length<!>
|
||||
p1<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
p2 ?: callItContracted { return }
|
||||
p2.length
|
||||
|
||||
@@ -6,5 +6,5 @@ fun <R> callIt(fn: () -> R): R = TODO()
|
||||
|
||||
fun smartIt(p1: String?, p2: String?) {
|
||||
p1 ?: callIt { TODO() }
|
||||
p1.<!UNSAFE_CALL!>length<!> // smartcast
|
||||
p1<!UNSAFE_CALL!>.<!>length // smartcast
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ fun kt6840_2(s: String?) {
|
||||
|
||||
fun kt1635(s: String?) {
|
||||
s?.hashCode()!!
|
||||
s.<!UNSAFE_CALL!>hashCode<!>()
|
||||
s<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
|
||||
fun kt2127() {
|
||||
|
||||
Vendored
+1
-1
@@ -9,5 +9,5 @@ fun checkJump(x: Int?, y: Int?) {
|
||||
y.hashCode()
|
||||
}
|
||||
// Smart cast here is erroneous: y is nullable
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
y<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -4,8 +4,8 @@ public fun foo(x: String?, y: String?): Int {
|
||||
// z is not null in both branches
|
||||
z.length
|
||||
// y is nullable if x != null
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// y is null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
return y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
+1
-1
@@ -13,5 +13,5 @@ public fun foo(x: String?): Int {
|
||||
checkSubtype<Int>(y)
|
||||
}
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ public fun foo(x: String?, z: String?, w: String?): Int {
|
||||
// w is not null because of w!!
|
||||
w.length
|
||||
// z is nullable despite of z!!
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ public fun foo(x: String?, z: String?): Int {
|
||||
gav(if (x == null) break else x, z!!)
|
||||
} while (bar())
|
||||
// z is nullable despite of z!!
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ public fun foo(x: String?): Int {
|
||||
} while (bar())
|
||||
y.hashCode()
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@ public fun foo(x: String?, z: String?): Int {
|
||||
// z is not null because of z!!
|
||||
z.length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@ public fun foo(x: String?, z: String?, w: String?): Int {
|
||||
// z is not null because of z!!
|
||||
z.length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
fun y(): Boolean { return false }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
do {
|
||||
if (y()) break
|
||||
// We do not always reach this statement
|
||||
p!!.length
|
||||
} while (!x())
|
||||
// Here we have do while loop but p is still nullable due to break before
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
fun y(): Boolean { return false }
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
do {
|
||||
if (bar()) break
|
||||
} while (s!!.length > 0)
|
||||
// This call is unsafe due to break
|
||||
return s.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
// See KT-6283
|
||||
do {
|
||||
if (p != null) break
|
||||
} while (!x())
|
||||
// p can be null despite of the break
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
do {
|
||||
if (bar()) break
|
||||
} while (s==null)
|
||||
// This call is unsafe due to break
|
||||
return s.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ public fun foo(x: String?): Int {
|
||||
x.length
|
||||
} while (true)
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
x ?: if (y == null) break
|
||||
// y is nullable if x != null
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
// y is null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
x ?: if (y == null) break
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
(if (x != null) break else y) ?: y!!
|
||||
// y is not null in both branches but it's hard to determine
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
// y can be null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
(if (x != null) break else y) ?: y!!
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ public fun foo(x: String?): Int {
|
||||
} while (bar())
|
||||
y.hashCode()
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ public fun foo(x: String?): Int {
|
||||
// In future we can infer this initialization
|
||||
<!UNINITIALIZED_VARIABLE!>y<!>.hashCode()
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user