Refactoring of getQualifiedExpressionTypeInfo

This commit is contained in:
Mikhail Glukhikh
2015-11-24 16:13:35 +03:00
parent ea4f167091
commit 97cdaba8b0
@@ -350,6 +350,7 @@ public class CallExpressionResolver {
@NotNull KtQualifiedExpression expression, @NotNull final ExpressionTypingContext context @NotNull KtQualifiedExpression expression, @NotNull final ExpressionTypingContext context
) { ) {
ExpressionTypingContext currentContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); ExpressionTypingContext currentContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
BindingTrace trace = currentContext.trace;
Function1<KtSimpleNameExpression, Boolean> isValueFunction = new Function1<KtSimpleNameExpression, Boolean>() { Function1<KtSimpleNameExpression, Boolean> isValueFunction = new Function1<KtSimpleNameExpression, Boolean>() {
@Override @Override
@@ -381,7 +382,7 @@ public class CallExpressionResolver {
CallExpressionElement firstElement = elementChain.iterator().next(); CallExpressionElement firstElement = elementChain.iterator().next();
KtExpression firstReceiver = firstElement.getReceiver(); KtExpression firstReceiver = firstElement.getReceiver();
Qualifier firstQualifier = context.trace.get(BindingContext.QUALIFIER, firstReceiver); Qualifier firstQualifier = trace.get(BindingContext.QUALIFIER, firstReceiver);
if (firstQualifier == null) { if (firstQualifier == null) {
receiverTypeInfo = expressionTypingServices.getTypeInfo(firstReceiver, currentContext); receiverTypeInfo = expressionTypingServices.getTypeInfo(firstReceiver, currentContext);
receiverType = receiverTypeInfo.getType(); receiverType = receiverTypeInfo.getType();
@@ -398,46 +399,49 @@ public class CallExpressionResolver {
boolean unconditional = true; boolean unconditional = true;
DataFlowInfo unconditionalDataFlowInfo = receiverDataFlowInfo; DataFlowInfo unconditionalDataFlowInfo = receiverDataFlowInfo;
ExpressionTypingContext contextForSelector = currentContext;
for (CallExpressionElement element : elementChain) { for (CallExpressionElement element : elementChain) {
if (receiverType == null) { if (receiverType == null) {
receiverType = ErrorUtils.createErrorType("Type for " + expression.getText()); receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
} }
QualifierReceiver qualifierReceiver = (QualifierReceiver) context.trace.get(BindingContext.QUALIFIER, element.getReceiver()); QualifierReceiver qualifierReceiver = (QualifierReceiver) trace.get(BindingContext.QUALIFIER, element.getReceiver());
Receiver receiver = qualifierReceiver == null Receiver receiver = qualifierReceiver == null
? ExpressionReceiver.Companion.create(element.getReceiver(), receiverType, context.trace.getBindingContext()) ? ExpressionReceiver.Companion.create(element.getReceiver(), receiverType, trace.getBindingContext())
: qualifierReceiver; : qualifierReceiver;
boolean lastStage = element.getQualified() == expression; boolean lastStage = element.getQualified() == expression;
// Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage // Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage
// But receiver data flow info changes should be always applied, while we are inside call chain // But receiver data flow info changes should be always applied, while we are inside call chain
ExpressionTypingContext baseContext = lastStage ? context : currentContext; ExpressionTypingContext baseContext = lastStage ? context : currentContext;
currentContext = baseContext.replaceDataFlowInfo(receiverDataFlowInfo); contextForSelector = baseContext.replaceDataFlowInfo(receiverDataFlowInfo);
if (receiver.exists() && receiver instanceof ReceiverValue) { if (receiver.exists() && receiver instanceof ReceiverValue) {
DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context); DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
// Additional "receiver != null" information // Additional "receiver != null" information
// Should be applied if we consider a safe call // Should be applied if we consider a safe call
if (element.getSafe()) { if (element.getSafe()) {
DataFlowInfo dataFlowInfo = currentContext.dataFlowInfo; DataFlowInfo dataFlowInfo = contextForSelector.dataFlowInfo;
if (!dataFlowInfo.getNullability(receiverDataFlowValue).canBeNull()) { if (dataFlowInfo.getNullability(receiverDataFlowValue).canBeNull()) {
reportUnnecessarySafeCall(context.trace, receiverType, element.getNode(), receiver); contextForSelector = contextForSelector.replaceDataFlowInfo(
dataFlowInfo.disequate(receiverDataFlowValue, DataFlowValue.nullValue(builtIns)));
}
else {
reportUnnecessarySafeCall(trace, receiverType, element.getNode(), receiver);
} }
currentContext = currentContext.replaceDataFlowInfo(
dataFlowInfo.disequate(receiverDataFlowValue, DataFlowValue.nullValue(builtIns)));
} }
} }
KtExpression selectorExpression = element.getSelector(); KtExpression selectorExpression = element.getSelector();
KotlinTypeInfo selectorReturnTypeInfo = KotlinTypeInfo selectorReturnTypeInfo =
getSelectorReturnTypeInfo(receiver, element.getNode(), selectorExpression, currentContext); getSelectorReturnTypeInfo(receiver, element.getNode(), selectorExpression, contextForSelector);
KotlinType selectorReturnType = selectorReturnTypeInfo.getType(); KotlinType selectorReturnType = selectorReturnTypeInfo.getType();
if (qualifierReceiver != null) { if (qualifierReceiver != null) {
resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, element.getQualified(), currentContext); resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, element.getQualified(), contextForSelector);
} }
checkNestedClassAccess(element.getQualified(), currentContext); checkNestedClassAccess(element.getQualified(), contextForSelector);
boolean safeCall = element.getSafe(); boolean safeCall = element.getSafe();
if (safeCall && selectorReturnType != null && TypeUtils.isNullableType(receiverType)) { if (safeCall && selectorReturnType != null && TypeUtils.isNullableType(receiverType)) {
@@ -447,16 +451,17 @@ public class CallExpressionResolver {
// TODO : this is suspicious: remove this code? // TODO : this is suspicious: remove this code?
if (selectorExpression != null && selectorReturnType != null) { if (selectorExpression != null && selectorReturnType != null) {
currentContext.trace.recordType(selectorExpression, selectorReturnType); trace.recordType(selectorExpression, selectorReturnType);
} }
resultTypeInfo = selectorReturnTypeInfo; resultTypeInfo = selectorReturnTypeInfo;
CompileTimeConstant<?> value = constantExpressionEvaluator.evaluateExpression(element.getQualified(), currentContext.trace, currentContext.expectedType); CompileTimeConstant<?> value = constantExpressionEvaluator.evaluateExpression(
element.getQualified(), trace, contextForSelector.expectedType);
if (value != null && value.isPure()) { if (value != null && value.isPure()) {
resultTypeInfo = dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, element.getQualified(), currentContext); resultTypeInfo = dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, element.getQualified(), contextForSelector);
if (lastStage) return resultTypeInfo; if (lastStage) return resultTypeInfo;
} }
if (currentContext.contextDependency == INDEPENDENT) { if (contextForSelector.contextDependency == INDEPENDENT) {
dataFlowAnalyzer.checkType(resultTypeInfo.getType(), element.getQualified(), currentContext); dataFlowAnalyzer.checkType(resultTypeInfo.getType(), element.getQualified(), contextForSelector);
} }
// For the next stage, if any, current stage selector is the receiver! // For the next stage, if any, current stage selector is the receiver!
receiverTypeInfo = selectorReturnTypeInfo; receiverTypeInfo = selectorReturnTypeInfo;
@@ -470,14 +475,15 @@ public class CallExpressionResolver {
unconditionalDataFlowInfo = receiverDataFlowInfo; unconditionalDataFlowInfo = receiverDataFlowInfo;
} }
//noinspection ConstantConditions //noinspection ConstantConditions
if (!lastStage && !currentContext.trace.get(BindingContext.PROCESSED, element.getQualified())) { if (!lastStage && !trace.get(BindingContext.PROCESSED, element.getQualified())) {
// Store type information (to prevent problems in call completer) // Store type information (to prevent problems in call completer)
currentContext.trace.record(BindingContext.PROCESSED, element.getQualified()); trace.record(BindingContext.PROCESSED, element.getQualified());
currentContext.trace.record(BindingContext.EXPRESSION_TYPE_INFO, element.getQualified(), trace.record(BindingContext.EXPRESSION_TYPE_INFO, element.getQualified(),
resultTypeInfo.replaceDataFlowInfo(unconditionalDataFlowInfo)); resultTypeInfo.replaceDataFlowInfo(unconditionalDataFlowInfo));
// save scope before analyze and fix debugger: see CodeFragmentAnalyzer.correctContextForExpression // save scope before analyze and fix debugger: see CodeFragmentAnalyzer.correctContextForExpression
BindingContextUtilsKt.recordScope(currentContext.trace, currentContext.scope, element.getQualified()); BindingContextUtilsKt.recordScope(trace, contextForSelector.scope, element.getQualified());
BindingContextUtilsKt.recordDataFlowInfo(currentContext.replaceDataFlowInfo(unconditionalDataFlowInfo), element.getQualified()); BindingContextUtilsKt.recordDataFlowInfo(contextForSelector.replaceDataFlowInfo(unconditionalDataFlowInfo),
element.getQualified());
} }
} }
// if we are at last stage, we should just take result type info and set unconditional data flow info // if we are at last stage, we should just take result type info and set unconditional data flow info