001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve.calls.smartcasts;
018
019 import com.google.common.collect.Lists;
020 import com.google.common.collect.Sets;
021 import kotlin.CollectionsKt;
022 import kotlin.jvm.functions.Function1;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
026 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
027 import org.jetbrains.kotlin.psi.KtExpression;
028 import org.jetbrains.kotlin.resolve.BindingContext;
029 import org.jetbrains.kotlin.resolve.BindingTrace;
030 import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
031 import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
032 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
033 import org.jetbrains.kotlin.types.KotlinType;
034 import org.jetbrains.kotlin.types.TypeIntersector;
035 import org.jetbrains.kotlin.types.TypeUtils;
036 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
037
038 import java.util.Collection;
039 import java.util.List;
040 import java.util.Set;
041
042 import static org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE;
043 import static org.jetbrains.kotlin.resolve.BindingContext.IMPLICIT_RECEIVER_SMARTCAST;
044 import static org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST;
045
046 public class SmartCastManager {
047
048 @NotNull
049 public List<KotlinType> getSmartCastVariants(
050 @NotNull ReceiverValue receiverToCast,
051 @NotNull ResolutionContext context
052 ) {
053 return getSmartCastVariants(receiverToCast, context.trace.getBindingContext(), context.scope.getOwnerDescriptor(), context.dataFlowInfo);
054 }
055
056 @NotNull
057 public List<KotlinType> getSmartCastVariants(
058 @NotNull ReceiverValue receiverToCast,
059 @NotNull BindingContext bindingContext,
060 @NotNull DeclarationDescriptor containingDeclarationOrModule,
061 @NotNull DataFlowInfo dataFlowInfo
062 ) {
063 List<KotlinType> variants = Lists.newArrayList();
064 variants.add(receiverToCast.getType());
065 variants.addAll(getSmartCastVariantsExcludingReceiver(bindingContext, containingDeclarationOrModule, dataFlowInfo, receiverToCast));
066 return variants;
067 }
068
069 @NotNull
070 public List<KotlinType> getSmartCastVariantsWithLessSpecificExcluded(
071 @NotNull ReceiverValue receiverToCast,
072 @NotNull BindingContext bindingContext,
073 @NotNull DeclarationDescriptor containingDeclarationOrModule,
074 @NotNull DataFlowInfo dataFlowInfo
075 ) {
076 final List<KotlinType> variants = getSmartCastVariants(receiverToCast, bindingContext,
077 containingDeclarationOrModule, dataFlowInfo);
078 return CollectionsKt.filter(variants, new Function1<KotlinType, Boolean>() {
079 @Override
080 public Boolean invoke(final KotlinType type) {
081 return !CollectionsKt.any(variants, new Function1<KotlinType, Boolean>() {
082 @Override
083 public Boolean invoke(KotlinType another) {
084 return another != type && KotlinTypeChecker.DEFAULT.isSubtypeOf(another, type);
085 }
086 });
087 }
088 });
089 }
090
091 /**
092 * @return variants @param receiverToCast may be cast to according to context dataFlowInfo, receiverToCast itself is NOT included
093 */
094 @NotNull
095 public Collection<KotlinType> getSmartCastVariantsExcludingReceiver(
096 @NotNull ResolutionContext context,
097 @NotNull ReceiverValue receiverToCast
098 ) {
099 return getSmartCastVariantsExcludingReceiver(context.trace.getBindingContext(),
100 context.scope.getOwnerDescriptor(),
101 context.dataFlowInfo,
102 receiverToCast);
103 }
104
105 /**
106 * @return variants @param receiverToCast may be cast to according to @param dataFlowInfo, @param receiverToCast itself is NOT included
107 */
108 @NotNull
109 public Collection<KotlinType> getSmartCastVariantsExcludingReceiver(
110 @NotNull BindingContext bindingContext,
111 @NotNull DeclarationDescriptor containingDeclarationOrModule,
112 @NotNull DataFlowInfo dataFlowInfo,
113 @NotNull ReceiverValue receiverToCast
114 ) {
115 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(
116 receiverToCast, bindingContext, containingDeclarationOrModule
117 );
118
119 return dataFlowInfo.getPossibleTypes(dataFlowValue);
120 }
121
122 public boolean isSubTypeBySmartCastIgnoringNullability(
123 @NotNull ReceiverValue receiverArgument,
124 @NotNull KotlinType receiverParameterType,
125 @NotNull ResolutionContext context
126 ) {
127 List<KotlinType> smartCastTypes = getSmartCastVariants(receiverArgument, context);
128 return getSmartCastSubType(TypeUtils.makeNullable(receiverParameterType), smartCastTypes) != null;
129 }
130
131 @Nullable
132 private KotlinType getSmartCastSubType(
133 @NotNull KotlinType receiverParameterType,
134 @NotNull Collection<KotlinType> smartCastTypes
135 ) {
136 Set<KotlinType> subTypes = Sets.newHashSet();
137 for (KotlinType smartCastType : smartCastTypes) {
138 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(smartCastType, receiverParameterType)) {
139 subTypes.add(smartCastType);
140 }
141 }
142 if (subTypes.isEmpty()) return null;
143
144 KotlinType intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, subTypes);
145 if (intersection == null || !intersection.getConstructor().isDenotable()) {
146 return receiverParameterType;
147 }
148 return intersection;
149 }
150
151 private static void recordCastOrError(
152 @NotNull KtExpression expression,
153 @NotNull KotlinType type,
154 @NotNull BindingTrace trace,
155 @NotNull DataFlowValue dataFlowValue,
156 boolean recordExpressionType
157 ) {
158 if (KotlinBuiltIns.isNullableNothing(type)) return;
159 if (dataFlowValue.isPredictable()) {
160 trace.record(SMARTCAST, expression, type);
161 if (recordExpressionType) {
162 //TODO
163 //Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
164 trace.recordType(expression, type);
165 }
166 }
167 else {
168 trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.getText(), dataFlowValue.getKind().getDescription()));
169 }
170 }
171
172 @Nullable
173 public static SmartCastResult checkAndRecordPossibleCast(
174 @NotNull DataFlowValue dataFlowValue,
175 @NotNull KotlinType expectedType,
176 @Nullable KtExpression expression,
177 @NotNull ResolutionContext c,
178 @Nullable KtExpression calleeExpression,
179 boolean recordExpressionType
180 ) {
181 for (KotlinType possibleType : c.dataFlowInfo.getPossibleTypes(dataFlowValue)) {
182 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) {
183 if (expression != null) {
184 recordCastOrError(expression, possibleType, c.trace, dataFlowValue, recordExpressionType);
185 }
186 else if (calleeExpression != null && dataFlowValue.isPredictable()) {
187 c.trace.record(IMPLICIT_RECEIVER_SMARTCAST, calleeExpression, possibleType);
188 }
189 return new SmartCastResult(possibleType, dataFlowValue.isPredictable());
190 }
191 }
192
193 if (!c.dataFlowInfo.getNullability(dataFlowValue).canBeNull() && !expectedType.isMarkedNullable()) {
194 // Handling cases like:
195 // fun bar(x: Any) {}
196 // fun <T : Any?> foo(x: T) {
197 // if (x != null) {
198 // bar(x) // Should be allowed with smart cast
199 // }
200 // }
201 //
202 // It doesn't handled by lower code with getPossibleTypes because smart cast of T after `x != null` is still has same type T.
203 // But at the same time we're sure that `x` can't be null and just check for such cases manually
204
205 // E.g. in case x!! when x has type of T where T is type parameter with nullable upper bounds
206 // x!! is immanently not null (see DataFlowValueFactory.createDataFlowValue for expression)
207 boolean immanentlyNotNull = !dataFlowValue.getImmanentNullability().canBeNull();
208 KotlinType nullableExpectedType = TypeUtils.makeNullable(expectedType);
209
210 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.getType(), nullableExpectedType)) {
211 if (!immanentlyNotNull) {
212 if (expression != null) {
213 recordCastOrError(expression, dataFlowValue.getType(), c.trace, dataFlowValue, recordExpressionType);
214 }
215 }
216
217 return new SmartCastResult(dataFlowValue.getType(), immanentlyNotNull || dataFlowValue.isPredictable());
218 }
219 return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, calleeExpression, recordExpressionType);
220 }
221
222 return null;
223 }
224 }