Refactoring move DataFlowValue back to frontend module.

This commit is contained in:
Stanislav Erokhin
2016-08-24 15:28:17 +03:00
parent 58fd24943d
commit d4a2cad35c
3 changed files with 0 additions and 0 deletions
@@ -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)
}
}
@@ -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)
}
}
}
@@ -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);
}
}