DataFlowValue & DataFlowValueFactory major refactoring, get rid of DataFlowValue.id : Any?
Instead, DataFlowValue now requires IdentifierInfo implementation to be created DataFlowValue is compared using IdentifierInfo
This commit is contained in:
committed by
Mikhail Glukhikh
parent
7f9b9ddb45
commit
9001b9bcc0
+14
-12
@@ -19,12 +19,20 @@ 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 id: Any?, val type: KotlinType, val kind: DataFlowValue.Kind, val immanentNullability: Nullability) {
|
||||
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,
|
||||
@@ -69,32 +77,26 @@ class DataFlowValue(val id: Any?, val type: KotlinType, val kind: DataFlowValue.
|
||||
if (this === other) return true
|
||||
if (other !is DataFlowValue) return false
|
||||
|
||||
if (kind.isStable() != other.kind.isStable()) return false
|
||||
if (id != other.id) return false
|
||||
if (identifierInfo != other.identifierInfo) return false
|
||||
if (type != other.type) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return kind.toString() + " " + id?.toString() + " " + immanentNullability
|
||||
}
|
||||
override fun toString() = "$kind $identifierInfo $immanentNullability"
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = if (kind.isStable()) 1 else 0
|
||||
var result = identifierInfo.hashCode()
|
||||
result = 31 * result + type.hashCode()
|
||||
result = 31 * result + (id?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun nullValue(builtIns: KotlinBuiltIns) = DataFlowValue(
|
||||
Object(), builtIns.nullableNothingType, Kind.OTHER, Nullability.NULL
|
||||
)
|
||||
fun nullValue(builtIns: KotlinBuiltIns) = DataFlowValue(IdentifierInfo.NULL, builtIns.nullableNothingType, Nullability.NULL)
|
||||
|
||||
@JvmField
|
||||
val ERROR = DataFlowValue(Object(), ErrorUtils.createErrorType("Error type for data flow"), Kind.OTHER, Nullability.IMPOSSIBLE)
|
||||
val ERROR = DataFlowValue(IdentifierInfo.ERROR, ErrorUtils.createErrorType("Error type for data flow"), Nullability.IMPOSSIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.PackageViewDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
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.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
|
||||
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) : IdentifierInfo {
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is Variable && variable == other.variable && kind.isStable() == other.kind.isStable()
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = if (kind.isStable()) 1 else 0
|
||||
result = 31 * result + variable.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
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
|
||||
) : IdentifierInfo {
|
||||
override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind.isStable()) selectorInfo.kind else OTHER
|
||||
|
||||
override fun equals(other: Any?) = other is Qualified && receiverInfo == other.receiverInfo && selectorInfo == other.selectorInfo
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = receiverInfo.hashCode()
|
||||
result = 31 * result + selectorInfo.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString() = "$receiverInfo(?).$selectorInfo"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun qualified(receiverInfo: IdentifierInfo?, selectorInfo: IdentifierInfo, safe: Boolean): IdentifierInfo {
|
||||
return if (selectorInfo == NO || receiverInfo === NO) {
|
||||
NO
|
||||
}
|
||||
else if (receiverInfo == null || receiverInfo is PackageOrClass) {
|
||||
selectorInfo
|
||||
}
|
||||
else {
|
||||
Qualified(receiverInfo, selectorInfo, safe)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user