@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)
            + ")");
  }
Example #2
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);
  }
 @Nullable
 private static JetFunction getFunctionDeclaration(@NotNull ResolvedCall<?> resolvedCall) {
   PsiElement result = QuickFixUtil.safeGetDeclaration(resolvedCall.getResultingDescriptor());
   if (result instanceof JetFunction) {
     return (JetFunction) result;
   }
   return null;
 }
Example #4
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();
 }
Example #5
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;
  }
Example #6
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);
  }
  // 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;
  }
  @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);
  }