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)); } } }
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)); } }
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)); } }
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)); } } }
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); } }
@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; }
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); } }
@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); }