diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.java index b317507514b..2015345d589 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.java @@ -40,12 +40,23 @@ public interface DataFlowInfo { @NotNull Nullability getNullability(@NotNull DataFlowValue key); + /** + * Gets a set of all possible types for this value, INCLUDING the original (native) type + */ + @NotNull + Set getPossibleTypes(@NotNull DataFlowValue key, boolean withOriginalType); + + /** + * IMPORTANT: by default, the original (native) type for this value + * are NOT included. So it's quite possible to get an empty set here. + * If you need also the original type, use getPossibleTypes(key, true) + */ @NotNull Set getPossibleTypes(@NotNull DataFlowValue key); /** * Call this function to clear all data flow information about - * the given data flow value. + * the given data flow value. Useful when we are not sure how this value can be changed, e.g. in a loop. */ @NotNull DataFlowInfo clearValueInfo(@NotNull DataFlowValue value); 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 index b58edb95a48..77c9a5a2af2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.java @@ -33,17 +33,17 @@ public class DataFlowValue { public static final DataFlowValue ERROR = new DataFlowValue(new Object(), ErrorUtils.createErrorType("Error type for data flow"), false, false, Nullability.IMPOSSIBLE); private final boolean stableIdentifier; - private final boolean uncapturedlocalVariable; + private final boolean uncapturedLocalVariable; private final JetType type; private final Object id; private final Nullability immanentNullability; // Use DataFlowValueFactory - /*package*/ DataFlowValue(Object id, JetType type, boolean stableIdentifier, boolean uncapturedlocalVariable, Nullability immanentNullability) { - assert !stableIdentifier || !uncapturedlocalVariable : - "data flow value cannot be together a stable identifier and an uncaptured local variable"; + /*package*/ DataFlowValue(Object id, JetType type, boolean stableIdentifier, boolean uncapturedLocalVariable, Nullability immanentNullability) { + assert !stableIdentifier || !uncapturedLocalVariable : + "data flow value for object " + id + " cannot be together a stable identifier and an uncaptured local variable"; this.stableIdentifier = stableIdentifier; - this.uncapturedlocalVariable = uncapturedlocalVariable; + this.uncapturedLocalVariable = uncapturedLocalVariable; this.type = type; this.id = id; this.immanentNullability = immanentNullability; @@ -73,7 +73,7 @@ public class DataFlowValue { * Identifier is considered a local variable here if it's mutable (var), local and not captured in a closure */ public boolean isUncapturedLocalVariable() { - return uncapturedlocalVariable; + return uncapturedLocalVariable; } /** @@ -82,7 +82,7 @@ public class DataFlowValue { * like accessing mutable properties in another thread or mutable variables from closures. */ public boolean isPredictable() { - return stableIdentifier || uncapturedlocalVariable; + return stableIdentifier || uncapturedLocalVariable; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.java index 3fa0f73f2c2..f924e2e8d65 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.java @@ -146,6 +146,7 @@ public class DataFlowValueFactory { public final boolean isPackage; private IdentifierInfo(Object id, boolean isStable, boolean isLocal, boolean isPackage) { + assert !isStable || !isLocal : "Identifier info for object " + id + " cannot be stable and local at one time"; this.id = id; this.isStable = isStable; this.isLocal = isLocal; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java index 74327cce9a3..fddf2ef8e3d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java @@ -131,13 +131,22 @@ import static org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability.NOT_NULL @Override @NotNull public Set getPossibleTypes(@NotNull DataFlowValue key) { + return getPossibleTypes(key, false); + } + + @Override + @NotNull + public Set getPossibleTypes(@NotNull DataFlowValue key, boolean withOriginalType) { + JetType originalType = key.getType(); Set types = collectTypesFromMeAndParents(key); + if (withOriginalType) { + types.add(originalType); + } if (getNullability(key).canBeNull()) { return types; } Set enrichedTypes = Sets.newHashSetWithExpectedSize(types.size() + 1); - JetType originalType = key.getType(); if (originalType.isMarkedNullable()) { enrichedTypes.add(TypeUtils.makeNotNullable(originalType)); } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index 75fb0bd79bf..2fdc8e1432e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -657,7 +657,7 @@ private fun ExtractionData.inferParametersInfo( receiverToExtract is ThisReceiver -> { val calleeExpression = resolvedCall!!.getCall().getCalleeExpression() bindingContext[BindingContext.EXPRESSION_DATA_FLOW_INFO, calleeExpression]?.let { dataFlowInfo -> - val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract)) + val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract), true) CommonSupertypes.commonSupertype(possibleTypes) } ?: receiverToExtract.getType() }