Refactoring move DataFlowValue back to frontend module.
This commit is contained in:
-92
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.smartcasts
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
private val KotlinType.immanentNullability: Nullability
|
||||
get() = if (TypeUtils.isNullableType(this)) Nullability.UNKNOWN else Nullability.NOT_NULL
|
||||
|
||||
/**
|
||||
* This class describes an arbitrary object which has some value in data flow analysis.
|
||||
* In general case it's some r-value.
|
||||
*/
|
||||
class DataFlowValue(val identifierInfo: IdentifierInfo,
|
||||
val type: KotlinType,
|
||||
val immanentNullability: Nullability = type.immanentNullability) {
|
||||
|
||||
val kind: Kind get() = identifierInfo.kind
|
||||
|
||||
enum class Kind(private val str: String, val description: String = str) {
|
||||
// Local value, or parameter, or private / internal member value without open / custom getter,
|
||||
// or protected / public member value from the same module without open / custom getter
|
||||
// Smart casts are completely safe
|
||||
STABLE_VALUE("stable val"),
|
||||
// Member value with open / custom getter
|
||||
// Smart casts are not safe
|
||||
PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),
|
||||
// Protected / public member value from another module
|
||||
// Smart casts are not safe
|
||||
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
|
||||
// Local variable not yet captured by a changing closure
|
||||
// Smart casts are safe but possible changes in loops / closures ahead must be taken into account
|
||||
STABLE_VARIABLE("stable var", "local variable that can be changed since the check in a loop"),
|
||||
// Local variable already captured by a changing closure
|
||||
// Smart casts are not safe
|
||||
CAPTURED_VARIABLE("captured var", "local variable that is captured by a changing closure"),
|
||||
// Member variable regardless of its visibility
|
||||
// Smart casts are not safe
|
||||
MUTABLE_PROPERTY("member", "mutable property that could have been changed by this time"),
|
||||
// Some complex expression
|
||||
// Smart casts are not safe
|
||||
OTHER("other", "complex expression");
|
||||
|
||||
override fun toString() = str
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable means here we do not expect some sudden change of their values,
|
||||
* like accessing mutable properties in another thread, so smart casts can be used safely.
|
||||
*/
|
||||
val isStable = (kind == Kind.STABLE_VALUE || kind == Kind.STABLE_VARIABLE)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is DataFlowValue) return false
|
||||
|
||||
if (identifierInfo != other.identifierInfo) return false
|
||||
if (type != other.type) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString() = "$kind $identifierInfo $immanentNullability"
|
||||
|
||||
override fun hashCode() = type.hashCode() + 31 * identifierInfo.hashCode()
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun nullValue(builtIns: KotlinBuiltIns) = DataFlowValue(IdentifierInfo.NULL, builtIns.nullableNothingType, Nullability.NULL)
|
||||
|
||||
@JvmField
|
||||
val ERROR = DataFlowValue(IdentifierInfo.ERROR, ErrorUtils.createErrorType("Error type for data flow"), Nullability.IMPOSSIBLE)
|
||||
}
|
||||
}
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.smartcasts
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue.Kind.OTHER
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue.Kind.STABLE_VALUE
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IdentifierInfo {
|
||||
|
||||
val kind: DataFlowValue.Kind get() = OTHER
|
||||
|
||||
object NO : IdentifierInfo {
|
||||
override fun toString() = "NO_IDENTIFIER_INFO"
|
||||
}
|
||||
|
||||
object NULL : IdentifierInfo {
|
||||
override fun toString() = "NULL"
|
||||
}
|
||||
|
||||
object ERROR : IdentifierInfo {
|
||||
override fun toString() = "ERROR"
|
||||
}
|
||||
|
||||
class Variable(
|
||||
val variable: VariableDescriptor,
|
||||
override val kind: DataFlowValue.Kind,
|
||||
val bound: DataFlowValue?
|
||||
) : IdentifierInfo {
|
||||
|
||||
override fun equals(other: Any?) = other is Variable && variable == other.variable
|
||||
|
||||
override fun hashCode() = variable.hashCode()
|
||||
|
||||
override fun toString() = variable.toString()
|
||||
}
|
||||
|
||||
data class Receiver(val value: ReceiverValue) : IdentifierInfo {
|
||||
|
||||
override val kind = STABLE_VALUE
|
||||
|
||||
override fun toString() = value.toString()
|
||||
}
|
||||
|
||||
data class PackageOrClass(val descriptor: DeclarationDescriptor) : IdentifierInfo {
|
||||
|
||||
override val kind = STABLE_VALUE
|
||||
|
||||
override fun toString() = descriptor.toString()
|
||||
}
|
||||
|
||||
class Qualified(
|
||||
val receiverInfo: IdentifierInfo,
|
||||
val selectorInfo: IdentifierInfo,
|
||||
val safe: Boolean,
|
||||
val receiverType: KotlinType?
|
||||
) : IdentifierInfo {
|
||||
override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind == STABLE_VALUE) selectorInfo.kind else OTHER
|
||||
|
||||
override fun equals(other: Any?) = other is Qualified && receiverInfo == other.receiverInfo && selectorInfo == other.selectorInfo
|
||||
|
||||
override fun hashCode() = 31 * receiverInfo.hashCode() + selectorInfo.hashCode()
|
||||
|
||||
override fun toString() = "$receiverInfo${if (safe) "?." else "."}$selectorInfo"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun qualified(
|
||||
receiverInfo: IdentifierInfo,
|
||||
receiverType: KotlinType?,
|
||||
selectorInfo: IdentifierInfo,
|
||||
safe: Boolean
|
||||
) = when (receiverInfo) {
|
||||
NO -> NO
|
||||
is PackageOrClass -> selectorInfo
|
||||
else -> Qualified(receiverInfo, selectorInfo, safe, receiverType)
|
||||
}
|
||||
}
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.smartcasts;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum Nullability {
|
||||
NULL(true, false),
|
||||
NOT_NULL(false, true),
|
||||
UNKNOWN(true, true),
|
||||
IMPOSSIBLE(false, false);
|
||||
|
||||
@NotNull
|
||||
public static Nullability fromFlags(boolean canBeNull, boolean canBeNonNull) {
|
||||
if (!canBeNull && !canBeNonNull) return IMPOSSIBLE;
|
||||
if (!canBeNull && canBeNonNull) return NOT_NULL;
|
||||
if (canBeNull && !canBeNonNull) return NULL;
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
private final boolean canBeNull;
|
||||
private final boolean canBeNonNull;
|
||||
|
||||
Nullability(boolean canBeNull, boolean canBeNonNull) {
|
||||
this.canBeNull = canBeNull;
|
||||
this.canBeNonNull = canBeNonNull;
|
||||
}
|
||||
|
||||
public boolean canBeNull() {
|
||||
return canBeNull;
|
||||
}
|
||||
|
||||
public boolean canBeNonNull() {
|
||||
return canBeNonNull;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Nullability refine(@NotNull Nullability other) {
|
||||
switch (this) {
|
||||
case UNKNOWN:
|
||||
return other;
|
||||
case IMPOSSIBLE:
|
||||
return other;
|
||||
case NULL:
|
||||
switch (other) {
|
||||
case NOT_NULL: return NOT_NULL;
|
||||
default: return NULL;
|
||||
}
|
||||
case NOT_NULL:
|
||||
switch (other) {
|
||||
case NULL: return NOT_NULL;
|
||||
default: return NOT_NULL;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Nullability invert() {
|
||||
switch (this) {
|
||||
case NULL:
|
||||
return NOT_NULL;
|
||||
case NOT_NULL:
|
||||
return UNKNOWN;
|
||||
case UNKNOWN:
|
||||
return UNKNOWN;
|
||||
case IMPOSSIBLE:
|
||||
return UNKNOWN;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Nullability and(@NotNull Nullability other) {
|
||||
return fromFlags(this.canBeNull && other.canBeNull, this.canBeNonNull && other.canBeNonNull);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Nullability or(@NotNull Nullability other) {
|
||||
return fromFlags(this.canBeNull || other.canBeNull, this.canBeNonNull || other.canBeNonNull);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user