示例#1
0
  @Override
  public <F extends CallableDescriptor> void check(
      @NotNull ResolvedCall<F> resolvedCall, @NotNull BasicCallResolutionContext context) {
    JetExpression expression = context.call.getCalleeExpression();
    if (expression == null) {
      return;
    }

    // checking that only invoke or inlinable extension called on function parameter
    CallableDescriptor targetDescriptor = resolvedCall.getResultingDescriptor();
    checkCallWithReceiver(
        context, targetDescriptor, resolvedCall.getDispatchReceiver(), expression);
    checkCallWithReceiver(
        context, targetDescriptor, resolvedCall.getExtensionReceiver(), expression);

    if (inlinableParameters.contains(targetDescriptor)) {
      if (!isInsideCall(expression)) {
        context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor));
      }
    }

    for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry :
        resolvedCall.getValueArguments().entrySet()) {
      ResolvedValueArgument value = entry.getValue();
      ValueParameterDescriptor valueDescriptor = entry.getKey();
      if (!(value instanceof DefaultValueArgument)) {
        for (ValueArgument argument : value.getArguments()) {
          checkValueParameter(context, targetDescriptor, argument, valueDescriptor);
        }
      }
    }

    checkVisibility(targetDescriptor, expression, context);
    checkRecursion(context, targetDescriptor, expression);
  }
示例#2
0
 @Nullable
 private ConstructorDescriptor getDelegatedConstructor(
     @NotNull ConstructorDescriptor constructor) {
   ResolvedCall<ConstructorDescriptor> call =
       trace.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructor);
   return call == null || !call.getStatus().isSuccess()
       ? null
       : call.getResultingDescriptor().getOriginal();
 }
  @NotNull
  private static FunctionDescriptor standardFunction(
      ClassDescriptor classDescriptor, String name, Project project, KotlinType... parameterTypes) {
    ModuleDescriptorImpl emptyModule = KotlinTestUtils.createEmptyModule();
    ContainerForTests container = InjectionKt.createContainerForTests(project, emptyModule);
    emptyModule.setDependencies(emptyModule);
    emptyModule.initialize(PackageFragmentProvider.Empty.INSTANCE);

    LexicalScopeImpl lexicalScope =
        new LexicalScopeImpl(
            ImportingScope.Empty.INSTANCE,
            classDescriptor,
            false,
            classDescriptor.getThisAsReceiverParameter(),
            LexicalScopeKind.SYNTHETIC);

    ExpressionTypingContext context =
        ExpressionTypingContext.newContext(
            new BindingTraceContext(),
            lexicalScope,
            DataFlowInfoFactory.EMPTY,
            TypeUtils.NO_EXPECTED_TYPE);

    OverloadResolutionResults<FunctionDescriptor> functions =
        container
            .getFakeCallResolver()
            .resolveFakeCall(
                context,
                null,
                Name.identifier(name),
                null,
                null,
                FakeCallKind.OTHER,
                parameterTypes);

    for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : functions.getResultingCalls()) {
      List<ValueParameterDescriptor> unsubstitutedValueParameters =
          resolvedCall.getResultingDescriptor().getValueParameters();
      for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size();
          i < unsubstitutedValueParametersSize;
          i++) {
        ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
        if (unsubstitutedValueParameter.getType().equals(parameterTypes[i])) {
          return resolvedCall.getResultingDescriptor();
        }
      }
    }
    throw new IllegalArgumentException(
        "Not found: kotlin::"
            + classDescriptor.getName()
            + "."
            + name
            + "("
            + Arrays.toString(parameterTypes)
            + ")");
  }
示例#4
0
  @Nullable
  private static CallableDescriptor getCalleeDescriptor(
      @NotNull CallCheckerContext context,
      @NotNull KtExpression expression,
      boolean unwrapVariableAsFunction) {
    if (!(expression instanceof KtSimpleNameExpression || expression instanceof KtThisExpression))
      return null;

    ResolvedCall<?> thisCall =
        CallUtilKt.getResolvedCall(expression, context.getTrace().getBindingContext());
    if (unwrapVariableAsFunction && thisCall instanceof VariableAsFunctionResolvedCall) {
      return ((VariableAsFunctionResolvedCall) thisCall).getVariableCall().getResultingDescriptor();
    }
    return thisCall != null ? thisCall.getResultingDescriptor() : null;
  }
示例#5
0
  public LambdaInfo(
      @NotNull KtExpression expression,
      @NotNull KotlinTypeMapper typeMapper,
      boolean isCrossInline,
      boolean isBoundCallableReference) {
    this.isCrossInline = isCrossInline;
    this.expression =
        expression instanceof KtLambdaExpression
            ? ((KtLambdaExpression) expression).getFunctionLiteral()
            : expression;

    this.typeMapper = typeMapper;
    this.isBoundCallableReference = isBoundCallableReference;
    BindingContext bindingContext = typeMapper.getBindingContext();
    FunctionDescriptor function = bindingContext.get(BindingContext.FUNCTION, this.expression);
    if (function == null && expression instanceof KtCallableReferenceExpression) {
      VariableDescriptor variableDescriptor =
          bindingContext.get(BindingContext.VARIABLE, this.expression);
      assert variableDescriptor instanceof VariableDescriptorWithAccessors
          : "Reference expression not resolved to variable descriptor with accessors: "
              + expression.getText();
      classDescriptor =
          CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
      closureClassType = typeMapper.mapClass(classDescriptor);
      SimpleFunctionDescriptor getFunction =
          PropertyReferenceCodegen.findGetFunction(variableDescriptor);
      functionDescriptor =
          PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor);
      ResolvedCall<?> resolvedCall =
          CallUtilKt.getResolvedCallWithAssert(
              ((KtCallableReferenceExpression) expression).getCallableReference(), bindingContext);
      propertyReferenceInfo =
          new PropertyReferenceInfo(
              (VariableDescriptor) resolvedCall.getResultingDescriptor(), getFunction);
    } else {
      propertyReferenceInfo = null;
      functionDescriptor = function;
      assert functionDescriptor != null
          : "Function is not resolved to descriptor: " + expression.getText();
      classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
      closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
    }

    closure = bindingContext.get(CLOSURE, classDescriptor);
    assert closure != null : "Closure for lambda should be not null " + expression.getText();

    labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor);
  }
示例#6
0
 protected void generateStub(
     @Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
   leaveTemps();
   assert resolvedCall != null;
   String message =
       "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
   AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
 }
 @Nullable
 private static JetFunction getFunctionDeclaration(@NotNull ResolvedCall<?> resolvedCall) {
   PsiElement result = QuickFixUtil.safeGetDeclaration(resolvedCall.getResultingDescriptor());
   if (result instanceof JetFunction) {
     return (JetFunction) result;
   }
   return null;
 }
  @NotNull
  public static JsNode translate(
      @NotNull JetCallExpression expression,
      @Nullable JsExpression receiver,
      @NotNull TranslationContext context) {
    ResolvedCall<? extends FunctionDescriptor> resolvedCall =
        getFunctionResolvedCallWithAssert(expression, context.bindingContext());

    if (isJsCall(resolvedCall)) {
      return (new CallExpressionTranslator(expression, receiver, context)).translateJsCode();
    }

    JsExpression callExpression =
        (new CallExpressionTranslator(expression, receiver, context)).translate();

    if (!resolvedCall.isSafeCall() && shouldBeInlined(expression, context)) {
      setInlineCallMetadata(callExpression, expression, resolvedCall, context);
    }

    return callExpression;
  }
示例#9
0
  // this is hack for a[b]++ -> a.set(b, a.get(b) + 1). Frontend generate fake expression for
  // a.get(b) + 1.
  @NotNull
  private TranslationContext contextWithValueParameterAliasInArrayGetAccess(
      @NotNull JsExpression toSetTo) {
    ResolvedCall<FunctionDescriptor> resolvedCall =
        BindingUtils.getResolvedCallForArrayAccess(
            bindingContext(), expression, /*isGetter = */ false);

    List<ResolvedValueArgument> arguments = resolvedCall.getValueArgumentsByIndex();
    if (arguments == null) {
      throw new IllegalStateException(
          "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor());
    }
    ResolvedValueArgument lastArgument = arguments.get(arguments.size() - 1);
    assert lastArgument instanceof ExpressionValueArgument
        : "Last argument of array-like setter must be ExpressionValueArgument: " + lastArgument;

    ValueArgument valueArgument = ((ExpressionValueArgument) lastArgument).getValueArgument();
    assert valueArgument != null;

    JetExpression element = valueArgument.getArgumentExpression();
    return context()
        .innerContextWithAliasesForExpressions(Collections.singletonMap(element, toSetTo));
  }
  @Nullable
  private KotlinType checkConventionForIterator(
      @NotNull ExpressionTypingContext context,
      @NotNull KtExpression loopRangeExpression,
      @NotNull KotlinType iteratorType,
      @NotNull String name,
      @NotNull DiagnosticFactory1<KtExpression, KotlinType> ambiguity,
      @NotNull DiagnosticFactory1<KtExpression, KotlinType> missing,
      @NotNull DiagnosticFactory1<KtExpression, KotlinType> noneApplicable,
      @NotNull WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> resolvedCallKey) {
    OverloadResolutionResults<FunctionDescriptor> nextResolutionResults =
        fakeCallResolver.resolveFakeCall(
            context,
            new TransientReceiver(iteratorType),
            Name.identifier(name),
            loopRangeExpression);
    if (nextResolutionResults.isAmbiguity()) {
      context.trace.report(ambiguity.on(loopRangeExpression, iteratorType));
    } else if (nextResolutionResults.isNothing()) {
      context.trace.report(missing.on(loopRangeExpression, iteratorType));
    } else if (!nextResolutionResults.isSuccess()) {
      context.trace.report(noneApplicable.on(loopRangeExpression, iteratorType));
    } else {
      assert nextResolutionResults.isSuccess();
      ResolvedCall<FunctionDescriptor> resolvedCall = nextResolutionResults.getResultingCall();
      context.trace.record(resolvedCallKey, loopRangeExpression, resolvedCall);
      FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
      symbolUsageValidator.validateCall(
          resolvedCall, functionDescriptor, context.trace, loopRangeExpression);

      checkIfOperatorModifierPresent(loopRangeExpression, functionDescriptor, context.trace);

      return functionDescriptor.getReturnType();
    }
    return null;
  }
示例#11
0
  @Nullable
  private DataFlowInfo resolveSecondaryConstructorDelegationCall(
      @NotNull DataFlowInfo outerDataFlowInfo,
      @NotNull BindingTrace trace,
      @NotNull LexicalScope scope,
      @NotNull JetSecondaryConstructor constructor,
      @NotNull ConstructorDescriptor descriptor,
      @NotNull CallChecker callChecker) {
    OverloadResolutionResults<?> results =
        callResolver.resolveConstructorDelegationCall(
            trace,
            scope,
            outerDataFlowInfo,
            descriptor,
            constructor.getDelegationCall(),
            callChecker);

    if (results != null && results.isSingleResult()) {
      ResolvedCall<? extends CallableDescriptor> resolvedCall = results.getResultingCall();
      recordConstructorDelegationCall(trace, descriptor, resolvedCall);
      return resolvedCall.getDataFlowInfoForArguments().getResultInfo();
    }
    return null;
  }
  @Nullable
  public KotlinType checkIterableConvention(
      @NotNull ExpressionReceiver loopRange, ExpressionTypingContext context) {
    KtExpression loopRangeExpression = loopRange.getExpression();

    // Make a fake call loopRange.iterator(), and try to resolve it
    Name iterator = Name.identifier("iterator");
    Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls =
        fakeCallResolver.makeAndResolveFakeCall(
            loopRange,
            context,
            Collections.<KtExpression>emptyList(),
            iterator,
            loopRangeExpression,
            FakeCallKind.ITERATOR,
            loopRangeExpression);
    OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = calls.getSecond();

    if (iteratorResolutionResults.isSuccess()) {
      ResolvedCall<FunctionDescriptor> iteratorResolvedCall =
          iteratorResolutionResults.getResultingCall();
      context.trace.record(
          LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall);
      FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();

      checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace);

      symbolUsageValidator.validateCall(
          iteratorResolvedCall, iteratorFunction, context.trace, loopRangeExpression);

      KotlinType iteratorType = iteratorFunction.getReturnType();
      KotlinType hasNextType =
          checkConventionForIterator(
              context,
              loopRangeExpression,
              iteratorType,
              "hasNext",
              HAS_NEXT_FUNCTION_AMBIGUITY,
              HAS_NEXT_MISSING,
              HAS_NEXT_FUNCTION_NONE_APPLICABLE,
              LOOP_RANGE_HAS_NEXT_RESOLVED_CALL);
      if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) {
        context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, hasNextType));
      }
      return checkConventionForIterator(
          context,
          loopRangeExpression,
          iteratorType,
          "next",
          NEXT_AMBIGUITY,
          NEXT_MISSING,
          NEXT_NONE_APPLICABLE,
          LOOP_RANGE_NEXT_RESOLVED_CALL);
    } else {
      if (iteratorResolutionResults.isAmbiguity()) {
        context.trace.report(
            ITERATOR_AMBIGUITY.on(
                loopRangeExpression, iteratorResolutionResults.getResultingCalls()));
      } else {
        context.trace.report(ITERATOR_MISSING.on(loopRangeExpression));
      }
    }
    return null;
  }
  public KotlinTypeInfo visitIfExpression(
      KtIfExpression ifExpression,
      ExpressionTypingContext contextWithExpectedType,
      boolean isStatement) {
    ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
    KtExpression condition = ifExpression.getCondition();
    DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context);

    KtExpression elseBranch = ifExpression.getElse();
    KtExpression thenBranch = ifExpression.getThen();

    LexicalWritableScope thenScope = newWritableScopeImpl(context, "Then scope");
    LexicalWritableScope elseScope = newWritableScopeImpl(context, "Else scope");
    DataFlowInfo thenInfo =
        components
            .dataFlowAnalyzer
            .extractDataFlowInfoFromCondition(condition, true, context)
            .and(conditionDataFlowInfo);
    DataFlowInfo elseInfo =
        components
            .dataFlowAnalyzer
            .extractDataFlowInfoFromCondition(condition, false, context)
            .and(conditionDataFlowInfo);

    if (elseBranch == null) {
      if (thenBranch != null) {
        KotlinTypeInfo result =
            getTypeInfoWhenOnlyOneBranchIsPresent(
                thenBranch,
                thenScope,
                thenInfo,
                elseInfo,
                contextWithExpectedType,
                ifExpression,
                isStatement);
        // If jump was possible, take condition check info as the jump info
        return result.getJumpOutPossible()
            ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo)
            : result;
      }
      return TypeInfoFactoryKt.createTypeInfo(
          components.dataFlowAnalyzer.checkImplicitCast(
              components.builtIns.getUnitType(),
              ifExpression,
              contextWithExpectedType,
              isStatement),
          thenInfo.or(elseInfo));
    }
    if (thenBranch == null) {
      return getTypeInfoWhenOnlyOneBranchIsPresent(
          elseBranch,
          elseScope,
          elseInfo,
          thenInfo,
          contextWithExpectedType,
          ifExpression,
          isStatement);
    }
    KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression);
    KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch);
    KtBlockExpression elseBlock = psiFactory.wrapInABlockWrapper(elseBranch);
    Call callForIf =
        createCallForSpecialConstruction(
            ifExpression, ifExpression, Lists.newArrayList(thenBlock, elseBlock));
    MutableDataFlowInfoForArguments dataFlowInfoForArguments =
        createDataFlowInfoForArgumentsForIfCall(callForIf, thenInfo, elseInfo);
    ResolvedCall<FunctionDescriptor> resolvedCall =
        components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
            callForIf,
            ResolveConstruct.IF,
            Lists.newArrayList("thenBranch", "elseBranch"),
            Lists.newArrayList(false, false),
            contextWithExpectedType,
            dataFlowInfoForArguments);

    BindingContext bindingContext = context.trace.getBindingContext();
    KotlinTypeInfo thenTypeInfo =
        BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
    KotlinTypeInfo elseTypeInfo =
        BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
    assert thenTypeInfo != null
        : "'Then' branch of if expression  was not processed: " + ifExpression;
    assert elseTypeInfo != null
        : "'Else' branch of if expression  was not processed: " + ifExpression;
    boolean loopBreakContinuePossible =
        thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible();

    KotlinType thenType = thenTypeInfo.getType();
    KotlinType elseType = elseTypeInfo.getType();
    DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo();
    DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo();

    boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType);
    boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType);

    DataFlowInfo resultDataFlowInfo;
    if (thenType == null && elseType == null) {
      resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo);
    } else if (thenType == null || (jumpInThen && !jumpInElse)) {
      resultDataFlowInfo = elseDataFlowInfo;
    } else if (elseType == null || (jumpInElse && !jumpInThen)) {
      resultDataFlowInfo = thenDataFlowInfo;
    } else {
      resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo);
    }

    KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
    // If break or continue was possible, take condition check info as the jump info
    return TypeInfoFactoryKt.createTypeInfo(
        components.dataFlowAnalyzer.checkImplicitCast(
            resultType, ifExpression, contextWithExpectedType, isStatement),
        resultDataFlowInfo,
        loopBreakContinuePossible,
        conditionDataFlowInfo);
  }
  @NotNull
  @Override
  protected List<IntentionAction> doCreateActions(@NotNull Diagnostic diagnostic) {
    List<IntentionAction> actions = new LinkedList<IntentionAction>();

    BindingContext context = ResolutionUtils.analyzeFully((JetFile) diagnostic.getPsiFile());

    PsiElement diagnosticElement = diagnostic.getPsiElement();
    if (!(diagnosticElement instanceof JetExpression)) {
      LOG.error("Unexpected element: " + diagnosticElement.getText());
      return Collections.emptyList();
    }

    JetExpression expression = (JetExpression) diagnosticElement;

    JetType expectedType;
    JetType expressionType;
    if (diagnostic.getFactory() == Errors.TYPE_MISMATCH) {
      DiagnosticWithParameters2<JetExpression, JetType, JetType> diagnosticWithParameters =
          Errors.TYPE_MISMATCH.cast(diagnostic);
      expectedType = diagnosticWithParameters.getA();
      expressionType = diagnosticWithParameters.getB();
    } else if (diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE) {
      DiagnosticWithParameters1<JetConstantExpression, JetType> diagnosticWithParameters =
          Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic);
      expectedType = diagnosticWithParameters.getA();
      expressionType = TypeUtilsKt.makeNullable(expectedType);
    } else if (diagnostic.getFactory() == Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) {
      DiagnosticWithParameters2<JetConstantExpression, String, JetType> diagnosticWithParameters =
          Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic);
      expectedType = diagnosticWithParameters.getB();
      expressionType = context.getType(expression);
      if (expressionType == null) {
        LOG.error("No type inferred: " + expression.getText());
        return Collections.emptyList();
      }
    } else {
      LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic));
      return Collections.emptyList();
    }

    // We don't want to cast a cast or type-asserted expression:
    if (!(expression instanceof JetBinaryExpressionWithTypeRHS)
        && !(expression.getParent() instanceof JetBinaryExpressionWithTypeRHS)) {
      actions.add(new CastExpressionFix(expression, expectedType));
    }

    // Property initializer type mismatch property type:
    JetProperty property = PsiTreeUtil.getParentOfType(expression, JetProperty.class);
    if (property != null) {
      JetPropertyAccessor getter = property.getGetter();
      JetExpression initializer = property.getInitializer();
      if (QuickFixUtil.canEvaluateTo(initializer, expression)
          || (getter != null
              && QuickFixUtil.canFunctionOrGetterReturnExpression(
                  property.getGetter(), expression))) {
        LexicalScope scope =
            CorePackage.getResolutionScope(
                property, context, ResolutionUtils.getResolutionFacade(property));
        JetType typeToInsert =
            TypeUtils.approximateWithResolvableType(expressionType, scope, false);
        actions.add(new ChangeVariableTypeFix(property, typeToInsert));
      }
    }

    PsiElement expressionParent = expression.getParent();

    // Mismatch in returned expression:

    JetCallableDeclaration function =
        expressionParent instanceof JetReturnExpression
            ? BindingContextUtilPackage.getTargetFunction(
                (JetReturnExpression) expressionParent, context)
            : PsiTreeUtil.getParentOfType(expression, JetFunction.class, true);
    if (function instanceof JetFunction
        && QuickFixUtil.canFunctionOrGetterReturnExpression(function, expression)) {
      LexicalScope scope =
          CorePackage.getResolutionScope(
              function, context, ResolutionUtils.getResolutionFacade(function));
      JetType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false);
      actions.add(new ChangeFunctionReturnTypeFix((JetFunction) function, typeToInsert));
    }

    // Fixing overloaded operators:
    if (expression instanceof JetOperationExpression) {
      ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
      if (resolvedCall != null) {
        JetFunction declaration = getFunctionDeclaration(resolvedCall);
        if (declaration != null) {
          actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType));
        }
      }
    }

    // Change function return type when TYPE_MISMATCH is reported on call expression:
    if (expression instanceof JetCallExpression) {
      ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
      if (resolvedCall != null) {
        JetFunction declaration = getFunctionDeclaration(resolvedCall);
        if (declaration != null) {
          actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType));
        }
      }
    }

    ResolvedCall<? extends CallableDescriptor> resolvedCall =
        CallUtilPackage.getParentResolvedCall(expression, context, true);
    if (resolvedCall != null) {
      // to fix 'type mismatch' on 'if' branches
      // todo: the same with 'when'
      JetExpression parentIf = QuickFixUtil.getParentIfForBranch(expression);
      JetExpression argumentExpression = (parentIf != null) ? parentIf : expression;
      ValueArgument valueArgument =
          CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), argumentExpression);
      if (valueArgument != null) {
        JetParameter correspondingParameter =
            QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument);
        JetType valueArgumentType =
            diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE
                ? expressionType
                : context.getType(valueArgument.getArgumentExpression());
        if (correspondingParameter != null && valueArgumentType != null) {
          JetCallableDeclaration callable =
              PsiTreeUtil.getParentOfType(
                  correspondingParameter, JetCallableDeclaration.class, true);
          LexicalScope scope =
              callable != null
                  ? CorePackage.getResolutionScope(
                      callable, context, ResolutionUtils.getResolutionFacade(callable))
                  : null;
          JetType typeToInsert =
              TypeUtils.approximateWithResolvableType(valueArgumentType, scope, true);
          actions.add(new ChangeParameterTypeFix(correspondingParameter, typeToInsert));
        }
      }
    }
    return actions;
  }