예제 #1
0
  private void checkValueParameter(
      @NotNull CallCheckerContext context,
      @NotNull CallableDescriptor targetDescriptor,
      @NotNull ValueArgument targetArgument,
      @NotNull ValueParameterDescriptor targetParameterDescriptor) {
    KtExpression argumentExpression = targetArgument.getArgumentExpression();
    if (argumentExpression == null) {
      return;
    }
    CallableDescriptor argumentCallee = getCalleeDescriptor(context, argumentExpression, false);

    if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) {
      if (InlineUtil.isInline(targetDescriptor)
          && isInlinableParameter(targetParameterDescriptor)) {
        if (allowsNonLocalReturns(argumentCallee)
            && !allowsNonLocalReturns(targetParameterDescriptor)) {
          context
              .getTrace()
              .report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression));
        } else {
          checkNonLocalReturn(context, argumentCallee, argumentExpression);
        }
      } else {
        context
            .getTrace()
            .report(USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor));
      }
    }
  }
예제 #2
0
  private void checkNonLocalReturn(
      @NotNull CallCheckerContext context,
      @NotNull CallableDescriptor inlinableParameterDescriptor,
      @NotNull KtExpression parameterUsage) {
    if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return;

    if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getResolutionContext())) {
      context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage));
    }
  }
예제 #3
0
 private void checkRecursion(
     @NotNull CallCheckerContext context,
     @NotNull CallableDescriptor targetDescriptor,
     @NotNull KtElement expression) {
   if (targetDescriptor.getOriginal() == descriptor) {
     context.getTrace().report(Errors.RECURSION_IN_INLINE.on(expression, expression, descriptor));
   }
 }
예제 #4
0
 private void checkPrivateClassMemberAccess(
     @NotNull DeclarationDescriptor declarationDescriptor,
     @NotNull KtElement expression,
     @NotNull CallCheckerContext context) {
   if (!isEffectivelyPrivateApiFunction) {
     if (DescriptorUtilsKt.isInsidePrivateClass(declarationDescriptor)) {
       context
           .getTrace()
           .report(
               Errors.PRIVATE_CLASS_MEMBER_FROM_INLINE.on(
                   expression, declarationDescriptor, descriptor));
     }
   }
 }
예제 #5
0
 private void checkLambdaInvokeOrExtensionCall(
     @NotNull CallCheckerContext context,
     @NotNull CallableDescriptor lambdaDescriptor,
     @NotNull CallableDescriptor callDescriptor,
     @NotNull KtExpression receiverExpression) {
   boolean inlinableCall = isInvokeOrInlineExtension(callDescriptor);
   if (!inlinableCall) {
     context
         .getTrace()
         .report(USAGE_IS_NOT_INLINABLE.on(receiverExpression, receiverExpression, descriptor));
   } else {
     checkNonLocalReturn(context, lambdaDescriptor, receiverExpression);
   }
 }
예제 #6
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;
  }
예제 #7
0
 private void checkVisibilityAndAccess(
     @NotNull CallableDescriptor declarationDescriptor,
     @NotNull KtElement expression,
     @NotNull CallCheckerContext context) {
   boolean declarationDescriptorIsPublicApi =
       DescriptorUtilsKt.isEffectivelyPublicApi(declarationDescriptor)
           || isDefinedInInlineFunction(declarationDescriptor);
   if (isEffectivelyPublicApiFunction
       && !declarationDescriptorIsPublicApi
       && declarationDescriptor.getVisibility() != Visibilities.LOCAL) {
     context
         .getTrace()
         .report(
             Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(
                 expression, declarationDescriptor, descriptor));
   } else {
     checkPrivateClassMemberAccess(declarationDescriptor, expression, context);
   }
 }
예제 #8
0
  @Override
  public void check(
      @NotNull ResolvedCall<?> resolvedCall,
      @NotNull PsiElement reportOn,
      @NotNull CallCheckerContext context) {
    KtExpression expression = resolvedCall.getCall().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.getTrace().report(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);
        }
      }
    }

    checkVisibilityAndAccess(targetDescriptor, expression, context);
    checkRecursion(context, targetDescriptor, expression);
  }