[FIR] Add ReturnsImplies effect analyzer

This commit is contained in:
Oleg Ivanov
2020-08-11 12:41:43 +03:00
parent 3454ae7ca4
commit 21b8679799
37 changed files with 1110 additions and 89 deletions
@@ -0,0 +1,121 @@
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class)
fun test1(x: String?): Any? {
contract {
returnsNotNull() implies (!(x == null))
}
return x
}
@OptIn(ExperimentalContracts::class)
fun test2(x: String?): Any? {
contract {
returnsNotNull() implies (x is String && x != null)
}
return x
}
@OptIn(ExperimentalContracts::class)
fun test3(x: String?): Any? {
contract {
returnsNotNull() implies (x is String? || x is Any?)
}
return x
}
@OptIn(ExperimentalContracts::class)
fun test4(x: String?, y: String?): Any? {
contract {
returns(true) implies (x != null && y != null)
}
return x != null && y != null
}
@OptIn(ExperimentalContracts::class)
fun test5(x: Any?): Any? {
contract {
returns(true) implies (x != null || x is Any)
}
return x != null
}
@OptIn(ExperimentalContracts::class)
fun test6(x: Any?): Any? {
contract {
returns(true) implies (x is String? && x != null)
}
return x is String
}
@OptIn(ExperimentalContracts::class)
fun test7(x: Any?): Any? {
contract {
returns(true) implies (x is String? && x != null || x is Int)
}
return x is String
}
@OptIn(ExperimentalContracts::class)
fun test8(x: Any?): Any? {
contract {
returns(true) implies (x is String || x is Int)
}
return x is String || x is Int
}
@OptIn(ExperimentalContracts::class)
fun test9(x: Any?): Any? {
contract {
returns(true) implies (x is String || x is Int)
}
if(x is String){
return true
}
return x is Int
}
@OptIn(ExperimentalContracts::class)
fun test10(x: Any?): Any? {
contract {
returns(true) implies (x is Comparable<*> || x is CharSequence)
}
return x is String
}
@OptIn(ExperimentalContracts::class)
fun test11(x: Any?): Any? {
contract {
returns(true) implies (x is Comparable<*> && x is CharSequence)
}
return x is String
}
@OptIn(ExperimentalContracts::class)
fun test12(x: Any?): Any? {
contract {
returns(true) implies (x is Comparable<*> && (x is CharSequence || x is Number))
}
return x is String || x is Int
}
@OptIn(ExperimentalContracts::class)
fun test13(x: Any?): Any? {
contract {
returns(true) implies (!(x !is Comparable<*> || (x !is CharSequence && !(x is Number))))
}
return x is String || x is Int
}
@@ -0,0 +1,118 @@
FILE: conditionLogic.kt
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test1(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NOT_NULL) -> !x == null
>
{
[StubStatement]
^test1 R|<local>/x|
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test2(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
>
{
[StubStatement]
^test2 R|<local>/x|
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test3(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NOT_NULL) -> x is kotlin/String? || x is kotlin/Any?
>
{
[StubStatement]
^test3 R|<local>/x|
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test4(x: R|kotlin/String?|, y: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null && y != null
>
{
[StubStatement]
^test4 !=(R|<local>/x|, Null(null)) && !=(R|<local>/y|, Null(null))
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test5(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null || x is kotlin/Any
>
{
[StubStatement]
^test5 !=(R|<local>/x|, Null(null))
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test6(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
>
{
[StubStatement]
^test6 (R|<local>/x| is R|kotlin/String|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test7(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
>
{
[StubStatement]
^test7 (R|<local>/x| is R|kotlin/String|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test8(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x is kotlin/String || x is kotlin/Int
>
{
[StubStatement]
^test8 (R|<local>/x| is R|kotlin/String|) || (R|<local>/x| is R|kotlin/Int|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test9(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x is kotlin/String || x is kotlin/Int
>
{
[StubStatement]
when () {
(R|<local>/x| is R|kotlin/String|) -> {
^test9 Boolean(true)
}
}
^test9 (R|<local>/x| is R|kotlin/Int|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test10(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x is kotlin/Comparable<*> || x is kotlin/CharSequence
>
{
[StubStatement]
^test10 (R|<local>/x| is R|kotlin/String|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test11(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
>
{
[StubStatement]
^test11 (R|<local>/x| is R|kotlin/String|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test12(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
>
{
[StubStatement]
^test12 (R|<local>/x| is R|kotlin/String|) || (R|<local>/x| is R|kotlin/Int|)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test13(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
>
{
[StubStatement]
^test13 (R|<local>/x| is R|kotlin/String|) || (R|<local>/x| is R|kotlin/Int|)
}
@@ -0,0 +1,57 @@
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class)
fun wrongFalse(x: String?): Boolean {
contract {
returns(false) implies (x != null)
}
return true
}
@OptIn(ExperimentalContracts::class)
fun wrongTrue(x: String?): Boolean {
contract {
returns(true) implies (x != null)
}
return false
}
@OptIn(ExperimentalContracts::class)
fun nullableConstant(x: String?): Any? {
contract {
returns(null) implies (x != null)
}
return 1
}
fun string() : String = ""
@OptIn(ExperimentalContracts::class)
fun nullableReturn(x: String?): Any? {
contract {
returns(null) implies (x != null)
}
return string()
}
@OptIn(ExperimentalContracts::class)
fun returnsNull(x: String?): Any? {
contract {
returnsNotNull() implies (x != null)
}
return null
}
@OptIn(ExperimentalContracts::class)
fun wrongReturnType(x: String?): Any? {
contract {
returns(true) implies (x != null)
}
return "true"
}
@@ -0,0 +1,58 @@
FILE: inapplicable.kt
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun wrongFalse(x: R|kotlin/String?|): R|kotlin/Boolean|
[R|Contract description]
<
Returns(FALSE) -> x != null
>
{
[StubStatement]
^wrongFalse Boolean(true)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun wrongTrue(x: R|kotlin/String?|): R|kotlin/Boolean|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
^wrongTrue Boolean(false)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun nullableConstant(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NULL) -> x != null
>
{
[StubStatement]
^nullableConstant Int(1)
}
public final fun string(): R|kotlin/String| {
^string String()
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun nullableReturn(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NULL) -> x != null
>
{
[StubStatement]
^nullableReturn R|/string|()
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun returnsNull(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NOT_NULL) -> x != null
>
{
[StubStatement]
^returnsNull Null(null)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun wrongReturnType(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
^wrongReturnType String(true)
}
@@ -0,0 +1,56 @@
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class)
fun test1(x: String?): Boolean {
contract {
returns(false) implies (x != null)
}
return x == null
}
@OptIn(ExperimentalContracts::class)
fun test2(x: String?): Boolean {
contract {
returns(true) implies (x != null)
}
return x != null
}
@OptIn(ExperimentalContracts::class)
fun test3(x: String?): Any? {
contract {
returns(true) implies (x != null)
}
if(x != null){
return true
}
return false
}
@OptIn(ExperimentalContracts::class)
fun test4(x: String?): Any? {
contract {
returns(true) implies (x != null)
}
val y = x
if(y != null){
return true
}
return false
}
@OptIn(ExperimentalContracts::class)
fun test5(x: String?): Any? {
contract {
returns(true) implies (x != null)
}
return test2(x)
}
@@ -0,0 +1,59 @@
FILE: notNull.kt
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test1(x: R|kotlin/String?|): R|kotlin/Boolean|
[R|Contract description]
<
Returns(FALSE) -> x != null
>
{
[StubStatement]
^test1 ==(R|<local>/x|, Null(null))
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test2(x: R|kotlin/String?|): R|kotlin/Boolean|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
^test2 !=(R|<local>/x|, Null(null))
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test3(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
when () {
!=(R|<local>/x|, Null(null)) -> {
^test3 Boolean(true)
}
}
^test3 Boolean(false)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test4(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
lval y: R|kotlin/String?| = R|<local>/x|
when () {
!=(R|<local>/y|, Null(null)) -> {
^test4 Boolean(true)
}
}
^test4 Boolean(false)
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test5(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
^test5 R|/test2|(R|<local>/x|)
}
@@ -6,16 +6,16 @@ interface A {
var Any?.isNotNull: Boolean
get() {
contract {
<!WRONG_IMPLIES_CONDITION!>contract {
returns(true) implies (this@isNotNull != null)
}
}<!>
return this != null
}
set(value) {
contract {
<!WRONG_IMPLIES_CONDITION!>contract {
returns() implies (this@isNotNull != null)
require(this != null)
}
}<!>
}
fun test_1(a: A?) {
@@ -0,0 +1,19 @@
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class)
fun test1(x: String?): Int? {
contract {
returnsNotNull() implies (x != null)
}
return x?.length
}
@OptIn(ExperimentalContracts::class)
fun test2(x: String?): Int? {
<!WRONG_IMPLIES_CONDITION!>contract {
returnsNotNull() implies (x is Boolean)
}<!>
return x?.length
}
@@ -0,0 +1,19 @@
FILE: safeCall.kt
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test1(x: R|kotlin/String?|): R|kotlin/Int?|
[R|Contract description]
<
Returns(NOT_NULL) -> x != null
>
{
[StubStatement]
^test1 R|<local>/x|?.{ $subj$.R|kotlin/String.length| }
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test2(x: R|kotlin/String?|): R|kotlin/Int?|
[R|Contract description]
<
Returns(NOT_NULL) -> x is kotlin/Boolean
>
{
[StubStatement]
^test2 R|<local>/x|?.{ $subj$.R|kotlin/String.length| }
}
@@ -0,0 +1,39 @@
import kotlin.contracts.*
@OptIn(ExperimentalContracts::class)
fun test1(x: String?): Any? {
contract {
returnsNotNull() implies (x != null)
}
return x
}
@OptIn(ExperimentalContracts::class)
fun test2(x: String?): Any? {
contract {
returns(true) implies (x != null)
}
return if(x != null) true else false
}
@OptIn(ExperimentalContracts::class)
fun test3(x: Any?): Any? {
contract {
returnsNotNull() implies (x != null)
}
return if(true) x else null
}
@OptIn(ExperimentalContracts::class)
fun test4(x: Any?): Any? {
contract {
returnsNotNull() implies (x != null)
}
return if(x != null) {
if (true) x else false
} else {
null
}
}
@@ -0,0 +1,69 @@
FILE: trickyCases.kt
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test1(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NOT_NULL) -> x != null
>
{
[StubStatement]
^test1 R|<local>/x|
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test2(x: R|kotlin/String?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(TRUE) -> x != null
>
{
[StubStatement]
^test2 when () {
!=(R|<local>/x|, Null(null)) -> {
Boolean(true)
}
else -> {
Boolean(false)
}
}
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test3(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NOT_NULL) -> x != null
>
{
[StubStatement]
^test3 when () {
Boolean(true) -> {
R|<local>/x|
}
else -> {
Null(null)
}
}
}
@R|kotlin/OptIn|(vararg(<getClass>(Q|kotlin/contracts/ExperimentalContracts|))) public final fun test4(x: R|kotlin/Any?|): R|kotlin/Any?|
[R|Contract description]
<
Returns(NOT_NULL) -> x != null
>
{
[StubStatement]
^test4 when () {
!=(R|<local>/x|, Null(null)) -> {
when () {
Boolean(true) -> {
R|<local>/x|
}
else -> {
Boolean(false)
}
}
}
else -> {
Null(null)
}
}
}