From 65b77558a1180a0c82e89505f6c5d0b8f1be0216 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 16 Sep 2015 16:56:15 +0300 Subject: [PATCH] Data flow value converted to Kotlin --- .../jvm/platform/JvmPlatformConfigurator.kt | 2 +- .../resolve/calls/GenericCandidateResolver.kt | 2 +- .../calls/smartcasts/DataFlowValue.java | 123 ------------------ .../resolve/calls/smartcasts/DataFlowValue.kt | 78 +++++++++++ .../DataFlowInfoUtilForCompletion.kt | 4 +- 5 files changed, 82 insertions(+), 127 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.java create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 352faea2493..50fd3e7f6bd 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -418,7 +418,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker { private fun doIfNotNull(dataFlowValue: DataFlowValue, c: ResolutionContext<*>, body: () -> T): T? { if (c.dataFlowInfo.getNullability(dataFlowValue).canBeNull() - && dataFlowValue.getType().mustNotBeNull() == NullabilityInformationSource.JAVA) { + && dataFlowValue.type.mustNotBeNull() == NullabilityInformationSource.JAVA) { return body() } return null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 949605e2f6e..d2b6c54f282 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -184,7 +184,7 @@ class GenericCandidateResolver( if (deparenthesizedArgument == null || type == null) return type val dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context) - if (!dataFlowValue.isPredictable()) return type + if (!dataFlowValue.isPredictable) return type val possibleTypes = context.dataFlowInfo.getPossibleTypes(dataFlowValue) if (possibleTypes.isEmpty()) return type diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.java deleted file mode 100644 index cc0ab53dd40..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010-2015 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; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.types.ErrorUtils; -import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; - -/** - * This class describes an arbitrary object which has some value in data flow analysis. - * In general case it's some r-value. - */ -public class DataFlowValue { - - public enum Kind { - STABLE_VALUE("stable"), - PREDICTABLE_VARIABLE("predictable"), - UNPREDICTABLE_VARIABLE("unpredictable"), - OTHER("other"); - - @Override - public String toString() { - return name; - } - - Kind(String name) { - this.name = name; - } - - private final String name; - - public boolean isStable() { - return this == STABLE_VALUE; - } - } - - public static final DataFlowValue NULL = new DataFlowValue(new Object(), KotlinBuiltIns.getInstance().getNullableNothingType(), Kind.OTHER, Nullability.NULL); - public static final DataFlowValue ERROR = new DataFlowValue(new Object(), ErrorUtils.createErrorType("Error type for data flow"), Kind.OTHER, Nullability.IMPOSSIBLE); - - private final Kind kind; - private final JetType type; - private final Object id; - private final Nullability immanentNullability; - - // Use DataFlowValueFactory - /*package*/ DataFlowValue(Object id, JetType type, Kind kind, Nullability immanentNullability) { - this.kind = kind; - this.type = type; - this.id = id; - this.immanentNullability = immanentNullability; - } - - @Nullable - public Object getId() { - return id; - } - - @NotNull - public Nullability getImmanentNullability() { - return immanentNullability; - } - - public Kind getKind() { - return kind; - } - - /** - * Both stable values and local variables (regardless captured or not) are considered "predictable". - * Predictable means here we do not expect some sudden change of their values, - * like accessing mutable properties in another thread. - */ - public boolean isPredictable() { - return kind == Kind.STABLE_VALUE || kind == Kind.PREDICTABLE_VARIABLE; - } - - @NotNull - public JetType getType() { - return type; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - DataFlowValue that = (DataFlowValue) o; - - if (kind.isStable() != that.kind.isStable()) return false; - if (id != null ? !id.equals(that.id) : that.id != null) return false; - if (type != null ? !type.equals(that.type) : that.type != null) return false; - - return true; - } - - @Override - public String toString() { - return kind.toString() + (id == null ? null : id.toString()) + " " + immanentNullability; - } - - @Override - public int hashCode() { - int result = kind.isStable() ? 1 : 0; - result = 31 * result + (type != null ? type.hashCode() : 0); - result = 31 * result + (id != null ? id.hashCode() : 0); - return result; - } -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt new file mode 100644 index 00000000000..92f0e5e8051 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2015 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.JetType + +/** + * 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: JetType, val kind: DataFlowValue.Kind, val immanentNullability: Nullability) { + + enum class Kind(private val name: String) { + // Smart casts are completely safe + STABLE_VALUE("stable"), + // Smart casts are safe but possible changes in loops / closures ahead must be taken into account + PREDICTABLE_VARIABLE("predictable"), + // Smart casts are not safe + UNPREDICTABLE_VARIABLE("unpredictable"), + OTHER("other"); + + override fun toString() = name + + fun isStable() = this == STABLE_VALUE + } + + /** + * Both stable values and predictable local variables are considered "predictable". + * Predictable 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 isPredictable = (kind == Kind.STABLE_VALUE || kind == Kind.PREDICTABLE_VARIABLE) + @JvmName("isPredictable") get + + override fun equals(other: Any?): Boolean { + 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 (type != other.type) return false + + return true + } + + override fun toString(): String { + return kind.toString() + (id?.toString()) + " " + immanentNullability + } + + override fun hashCode(): Int { + var result = if (kind.isStable()) 1 else 0 + result = 31 * result + (type?.hashCode() ?: 0) + result = 31 * result + (id?.hashCode() ?: 0) + return result + } + + companion object { + + val NULL = DataFlowValue(Object(), KotlinBuiltIns.getInstance().nullableNothingType, Kind.OTHER, Nullability.NULL) + val ERROR = DataFlowValue(Object(), ErrorUtils.createErrorType("Error type for data flow"), Kind.OTHER, Nullability.IMPOSSIBLE) + } +} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DataFlowInfoUtilForCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DataFlowInfoUtilForCompletion.kt index f5447fba29e..8ba368a1e27 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DataFlowInfoUtilForCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DataFlowInfoUtilForCompletion.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.descriptors.PackageViewDescriptor fun renderDataFlowValue(value: DataFlowValue): String? { // If it is not a stable identifier, there's no point in rendering it - if (!value.isPredictable()) return null + if (!value.isPredictable) return null fun renderId(id: Any?): String? { return when (id) { @@ -36,5 +36,5 @@ fun renderDataFlowValue(value: DataFlowValue): String? { else -> null } } - return renderId(value.getId()) + return renderId(value.id) }