Convert InlineChecker to Kotlin
This commit is contained in:
+157
-173
@@ -14,291 +14,275 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.checkers;
|
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.builtins.*
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.lexer.KtToken;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.resolve.calls.callUtil.*
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.NON_LOCAL_RETURN_NOT_ALLOWED;
|
import org.jetbrains.kotlin.diagnostics.Errors.NON_LOCAL_RETURN_NOT_ALLOWED
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.USAGE_IS_NOT_INLINABLE;
|
import org.jetbrains.kotlin.diagnostics.Errors.USAGE_IS_NOT_INLINABLE
|
||||||
import static org.jetbrains.kotlin.resolve.inline.InlineUtil.allowsNonLocalReturns;
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil.allowsNonLocalReturns
|
||||||
import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturnUsage;
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturnUsage
|
||||||
|
|
||||||
class InlineChecker implements CallChecker {
|
internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallChecker {
|
||||||
private final FunctionDescriptor descriptor;
|
private val inlinableParameters = LinkedHashSet<CallableDescriptor>()
|
||||||
private final Set<CallableDescriptor> inlinableParameters = new LinkedHashSet<>();
|
private val inlineFunEffectiveVisibility: EffectiveVisibility
|
||||||
private final EffectiveVisibility inlineFunEffectiveVisibility;
|
private val isEffectivelyPrivateApiFunction: Boolean
|
||||||
private final boolean isEffectivelyPrivateApiFunction;
|
|
||||||
|
|
||||||
public InlineChecker(@NotNull FunctionDescriptor descriptor) {
|
init {
|
||||||
assert InlineUtil.isInline(descriptor) : "This extension should be created only for inline functions: " + descriptor;
|
assert(InlineUtil.isInline(descriptor)) { "This extension should be created only for inline functions: " + descriptor }
|
||||||
this.descriptor = descriptor;
|
this.inlineFunEffectiveVisibility = descriptor.effectiveVisibility(descriptor.visibility, true)
|
||||||
this.inlineFunEffectiveVisibility = EffectiveVisibilityKt.effectiveVisibility(descriptor, descriptor.getVisibility(), true);
|
this.isEffectivelyPrivateApiFunction = descriptor.isEffectivelyPrivateApi
|
||||||
this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor);
|
for (param in descriptor.valueParameters) {
|
||||||
for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
|
|
||||||
if (isInlinableParameter(param)) {
|
if (isInlinableParameter(param)) {
|
||||||
inlinableParameters.add(param);
|
inlinableParameters.add(param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
public void check(@NotNull ResolvedCall<?> resolvedCall, @NotNull PsiElement reportOn, @NotNull CallCheckerContext context) {
|
val expression = resolvedCall.call.calleeExpression ?: return
|
||||||
KtExpression expression = resolvedCall.getCall().getCalleeExpression();
|
|
||||||
if (expression == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//checking that only invoke or inlinable extension called on function parameter
|
//checking that only invoke or inlinable extension called on function parameter
|
||||||
CallableDescriptor targetDescriptor = resolvedCall.getResultingDescriptor();
|
val targetDescriptor = resolvedCall.resultingDescriptor
|
||||||
checkCallWithReceiver(context, targetDescriptor, resolvedCall.getDispatchReceiver(), expression);
|
checkCallWithReceiver(context, targetDescriptor, resolvedCall.dispatchReceiver, expression)
|
||||||
checkCallWithReceiver(context, targetDescriptor, resolvedCall.getExtensionReceiver(), expression);
|
checkCallWithReceiver(context, targetDescriptor, resolvedCall.extensionReceiver, expression)
|
||||||
|
|
||||||
if (inlinableParameters.contains(targetDescriptor)) {
|
if (inlinableParameters.contains(targetDescriptor)) {
|
||||||
if (!isInsideCall(expression)) {
|
if (!isInsideCall(expression)) {
|
||||||
context.getTrace().report(USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor));
|
context.trace.report(USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
|
for ((valueDescriptor, value) in resolvedCall.valueArguments) {
|
||||||
ResolvedValueArgument value = entry.getValue();
|
if (value !is DefaultValueArgument) {
|
||||||
ValueParameterDescriptor valueDescriptor = entry.getKey();
|
for (argument in value.arguments) {
|
||||||
if (!(value instanceof DefaultValueArgument)) {
|
checkValueParameter(context, targetDescriptor, argument, valueDescriptor)
|
||||||
for (ValueArgument argument : value.getArguments()) {
|
|
||||||
checkValueParameter(context, targetDescriptor, argument, valueDescriptor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkVisibilityAndAccess(targetDescriptor, expression, context);
|
checkVisibilityAndAccess(targetDescriptor, expression, context)
|
||||||
checkRecursion(context, targetDescriptor, expression);
|
checkRecursion(context, targetDescriptor, expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInsideCall(KtExpression expression) {
|
private fun isInsideCall(expression: KtExpression): Boolean {
|
||||||
KtElement parent = KtPsiUtil.getParentCallIfPresent(expression);
|
val parent = KtPsiUtil.getParentCallIfPresent(expression)
|
||||||
if (parent instanceof KtBinaryExpression) {
|
if (parent is KtBinaryExpression) {
|
||||||
KtToken token = KtPsiUtil.getOperationToken((KtOperationExpression) parent);
|
val token = KtPsiUtil.getOperationToken((parent as KtOperationExpression?)!!)
|
||||||
if (token == KtTokens.EQ || token == KtTokens.ANDAND || token == KtTokens.OROR) {
|
if (token === KtTokens.EQ || token === KtTokens.ANDAND || token === KtTokens.OROR) {
|
||||||
//assignment
|
//assignment
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
//UGLY HACK
|
//UGLY HACK
|
||||||
//check there is no casts
|
//check there is no casts
|
||||||
PsiElement current = expression;
|
var current: PsiElement = expression
|
||||||
while (current != parent) {
|
while (current !== parent) {
|
||||||
if (current instanceof KtBinaryExpressionWithTypeRHS) {
|
if (current is KtBinaryExpressionWithTypeRHS) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
current = current.getParent();
|
current = current.parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent != null;
|
return parent != null
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkValueParameter(
|
private fun checkValueParameter(
|
||||||
@NotNull CallCheckerContext context,
|
context: CallCheckerContext,
|
||||||
@NotNull CallableDescriptor targetDescriptor,
|
targetDescriptor: CallableDescriptor,
|
||||||
@NotNull ValueArgument targetArgument,
|
targetArgument: ValueArgument,
|
||||||
@NotNull ValueParameterDescriptor targetParameterDescriptor
|
targetParameterDescriptor: ValueParameterDescriptor
|
||||||
) {
|
) {
|
||||||
KtExpression argumentExpression = targetArgument.getArgumentExpression();
|
val argumentExpression = targetArgument.getArgumentExpression() ?: return
|
||||||
if (argumentExpression == null) {
|
val argumentCallee = getCalleeDescriptor(context, argumentExpression, false)
|
||||||
return;
|
|
||||||
}
|
|
||||||
CallableDescriptor argumentCallee = getCalleeDescriptor(context, argumentExpression, false);
|
|
||||||
|
|
||||||
if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) {
|
if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) {
|
||||||
if (InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor)) {
|
if (InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor)) {
|
||||||
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
|
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
|
||||||
context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression));
|
context.trace.report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkNonLocalReturn(context, argumentCallee, argumentExpression);
|
checkNonLocalReturn(context, argumentCallee, argumentExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
context.getTrace().report(USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor));
|
context.trace.report(USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkCallWithReceiver(
|
private fun checkCallWithReceiver(
|
||||||
@NotNull CallCheckerContext context,
|
context: CallCheckerContext,
|
||||||
@NotNull CallableDescriptor targetDescriptor,
|
targetDescriptor: CallableDescriptor,
|
||||||
@Nullable ReceiverValue receiver,
|
receiver: ReceiverValue?,
|
||||||
@Nullable KtExpression expression
|
expression: KtExpression?
|
||||||
) {
|
) {
|
||||||
if (receiver == null) return;
|
if (receiver == null) return
|
||||||
|
|
||||||
CallableDescriptor varDescriptor = null;
|
val varDescriptor: CallableDescriptor?
|
||||||
KtExpression receiverExpression = null;
|
val receiverExpression: KtExpression?
|
||||||
if (receiver instanceof ExpressionReceiver) {
|
if (receiver is ExpressionReceiver) {
|
||||||
receiverExpression = ((ExpressionReceiver) receiver).getExpression();
|
receiverExpression = receiver.expression
|
||||||
varDescriptor = getCalleeDescriptor(context, receiverExpression, true);
|
varDescriptor = getCalleeDescriptor(context, receiverExpression, true)
|
||||||
}
|
}
|
||||||
else if (receiver instanceof ExtensionReceiver) {
|
else if (receiver is ExtensionReceiver) {
|
||||||
ExtensionReceiver extensionReceiver = (ExtensionReceiver) receiver;
|
val extension = receiver.declarationDescriptor
|
||||||
CallableDescriptor extension = extensionReceiver.getDeclarationDescriptor();
|
|
||||||
|
|
||||||
varDescriptor = extension.getExtensionReceiverParameter();
|
varDescriptor = extension.extensionReceiverParameter
|
||||||
assert varDescriptor != null : "Extension should have receiverParameterDescriptor: " + extension;
|
assert(varDescriptor != null) { "Extension should have receiverParameterDescriptor: " + extension }
|
||||||
|
|
||||||
receiverExpression = expression;
|
receiverExpression = expression
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
varDescriptor = null
|
||||||
|
receiverExpression = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inlinableParameters.contains(varDescriptor)) {
|
if (inlinableParameters.contains(varDescriptor)) {
|
||||||
//check that it's invoke or inlinable extension
|
//check that it's invoke or inlinable extension
|
||||||
checkLambdaInvokeOrExtensionCall(context, varDescriptor, targetDescriptor, receiverExpression);
|
checkLambdaInvokeOrExtensionCall(context, varDescriptor!!, targetDescriptor, receiverExpression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun getCalleeDescriptor(
|
||||||
private static CallableDescriptor getCalleeDescriptor(
|
context: CallCheckerContext,
|
||||||
@NotNull CallCheckerContext context,
|
expression: KtExpression,
|
||||||
@NotNull KtExpression expression,
|
unwrapVariableAsFunction: Boolean
|
||||||
boolean unwrapVariableAsFunction
|
): CallableDescriptor? {
|
||||||
) {
|
if (!(expression is KtSimpleNameExpression || expression is KtThisExpression)) return null
|
||||||
if (!(expression instanceof KtSimpleNameExpression || expression instanceof KtThisExpression)) return null;
|
|
||||||
|
|
||||||
ResolvedCall<?> thisCall = CallUtilKt.getResolvedCall(expression, context.getTrace().getBindingContext());
|
val thisCall = expression.getResolvedCall(context.trace.bindingContext)
|
||||||
if (unwrapVariableAsFunction && thisCall instanceof VariableAsFunctionResolvedCall) {
|
if (unwrapVariableAsFunction && thisCall is VariableAsFunctionResolvedCall) {
|
||||||
return ((VariableAsFunctionResolvedCall) thisCall).getVariableCall().getResultingDescriptor();
|
return (thisCall as VariableAsFunctionResolvedCall).variableCall.resultingDescriptor
|
||||||
}
|
}
|
||||||
return thisCall != null ? thisCall.getResultingDescriptor() : null;
|
return thisCall?.resultingDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLambdaInvokeOrExtensionCall(
|
private fun checkLambdaInvokeOrExtensionCall(
|
||||||
@NotNull CallCheckerContext context,
|
context: CallCheckerContext,
|
||||||
@NotNull CallableDescriptor lambdaDescriptor,
|
lambdaDescriptor: CallableDescriptor,
|
||||||
@NotNull CallableDescriptor callDescriptor,
|
callDescriptor: CallableDescriptor,
|
||||||
@NotNull KtExpression receiverExpression
|
receiverExpression: KtExpression
|
||||||
) {
|
) {
|
||||||
boolean inlinableCall = isInvokeOrInlineExtension(callDescriptor);
|
val inlinableCall = isInvokeOrInlineExtension(callDescriptor)
|
||||||
if (!inlinableCall) {
|
if (!inlinableCall) {
|
||||||
context.getTrace().report(USAGE_IS_NOT_INLINABLE.on(receiverExpression, receiverExpression, descriptor));
|
context.trace.report(USAGE_IS_NOT_INLINABLE.on(receiverExpression, receiverExpression, descriptor))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkNonLocalReturn(context, lambdaDescriptor, receiverExpression);
|
checkNonLocalReturn(context, lambdaDescriptor, receiverExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRecursion(
|
private fun checkRecursion(
|
||||||
@NotNull CallCheckerContext context,
|
context: CallCheckerContext,
|
||||||
@NotNull CallableDescriptor targetDescriptor,
|
targetDescriptor: CallableDescriptor,
|
||||||
@NotNull KtElement expression
|
expression: KtElement
|
||||||
) {
|
) {
|
||||||
if (targetDescriptor.getOriginal() == descriptor) {
|
if (targetDescriptor.original === descriptor) {
|
||||||
context.getTrace().report(Errors.RECURSION_IN_INLINE.on(expression, expression, descriptor));
|
context.trace.report(Errors.RECURSION_IN_INLINE.on(expression, expression, descriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInlinableParameter(@NotNull ParameterDescriptor descriptor) {
|
private fun isInlinableParameter(descriptor: ParameterDescriptor): Boolean {
|
||||||
return InlineUtil.isInlineLambdaParameter(descriptor) && !descriptor.getType().isMarkedNullable();
|
return InlineUtil.isInlineLambdaParameter(descriptor) && !descriptor.type.isMarkedNullable
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInvokeOrInlineExtension(@NotNull CallableDescriptor descriptor) {
|
private fun isInvokeOrInlineExtension(descriptor: CallableDescriptor): Boolean {
|
||||||
if (!(descriptor instanceof SimpleFunctionDescriptor)) {
|
if (descriptor !is SimpleFunctionDescriptor) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
val containingDeclaration = descriptor.getContainingDeclaration()
|
||||||
boolean isInvoke =
|
val isInvoke = descriptor.getName() == OperatorNameConventions.INVOKE &&
|
||||||
descriptor.getName().equals(OperatorNameConventions.INVOKE) &&
|
containingDeclaration is ClassDescriptor &&
|
||||||
containingDeclaration instanceof ClassDescriptor &&
|
containingDeclaration.defaultType.isFunctionType
|
||||||
FunctionTypesKt.isFunctionType(((ClassDescriptor) containingDeclaration).getDefaultType());
|
|
||||||
|
|
||||||
return isInvoke || InlineUtil.isInline(descriptor);
|
return isInvoke || InlineUtil.isInline(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkVisibilityAndAccess(
|
private fun checkVisibilityAndAccess(
|
||||||
@NotNull CallableDescriptor calledDescriptor,
|
calledDescriptor: CallableDescriptor,
|
||||||
@NotNull KtElement expression,
|
expression: KtElement,
|
||||||
@NotNull CallCheckerContext context
|
context: CallCheckerContext
|
||||||
) {
|
) {
|
||||||
EffectiveVisibility calledFunEffectiveVisibility =
|
val calledFunEffectiveVisibility = if (isDefinedInInlineFunction(calledDescriptor))
|
||||||
isDefinedInInlineFunction(calledDescriptor) ?
|
EffectiveVisibility.Public
|
||||||
EffectiveVisibility.Public.INSTANCE :
|
else
|
||||||
EffectiveVisibilityKt.effectiveVisibility(calledDescriptor, calledDescriptor.getVisibility(), true);
|
calledDescriptor.effectiveVisibility(calledDescriptor.visibility, true)
|
||||||
|
|
||||||
boolean isCalledFunPublicOrPublishedApi = calledFunEffectiveVisibility.getPublicApi();
|
val isCalledFunPublicOrPublishedApi = calledFunEffectiveVisibility.publicApi
|
||||||
boolean isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.getPublicApi();
|
val isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.publicApi
|
||||||
if (isInlineFunPublicOrPublishedApi &&
|
if (isInlineFunPublicOrPublishedApi &&
|
||||||
!isCalledFunPublicOrPublishedApi &&
|
!isCalledFunPublicOrPublishedApi &&
|
||||||
calledDescriptor.getVisibility() != Visibilities.LOCAL) {
|
calledDescriptor.visibility !== Visibilities.LOCAL) {
|
||||||
context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor, descriptor));
|
context.trace.report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor, descriptor))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkPrivateClassMemberAccess(calledDescriptor, expression, context);
|
checkPrivateClassMemberAccess(calledDescriptor, expression, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(calledDescriptor instanceof ConstructorDescriptor) &&
|
if (calledDescriptor !is ConstructorDescriptor &&
|
||||||
isInlineFunPublicOrPublishedApi &&
|
isInlineFunPublicOrPublishedApi &&
|
||||||
inlineFunEffectiveVisibility.toVisibility() != Visibilities.PROTECTED &&
|
inlineFunEffectiveVisibility.toVisibility() !== Visibilities.PROTECTED &&
|
||||||
calledFunEffectiveVisibility.toVisibility() == Visibilities.PROTECTED) {
|
calledFunEffectiveVisibility.toVisibility() === Visibilities.PROTECTED) {
|
||||||
context.getTrace().report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor));
|
context.trace.report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPrivateClassMemberAccess(
|
private fun checkPrivateClassMemberAccess(
|
||||||
@NotNull DeclarationDescriptor declarationDescriptor,
|
declarationDescriptor: DeclarationDescriptor,
|
||||||
@NotNull KtElement expression,
|
expression: KtElement,
|
||||||
@NotNull CallCheckerContext context
|
context: CallCheckerContext
|
||||||
) {
|
) {
|
||||||
if (!isEffectivelyPrivateApiFunction) {
|
if (!isEffectivelyPrivateApiFunction) {
|
||||||
if (DescriptorUtilsKt.isInsidePrivateClass(declarationDescriptor)) {
|
if (declarationDescriptor.isInsidePrivateClass) {
|
||||||
context.getTrace().report(Errors.PRIVATE_CLASS_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor));
|
context.trace.report(Errors.PRIVATE_CLASS_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDefinedInInlineFunction(@NotNull DeclarationDescriptorWithVisibility startDescriptor) {
|
private fun isDefinedInInlineFunction(startDescriptor: DeclarationDescriptorWithVisibility): Boolean {
|
||||||
DeclarationDescriptorWithVisibility parent = startDescriptor;
|
var parent: DeclarationDescriptorWithVisibility? = startDescriptor
|
||||||
|
|
||||||
while (parent != null) {
|
while (parent != null) {
|
||||||
if (parent.getContainingDeclaration() == descriptor) return true;
|
if (parent.containingDeclaration === descriptor) return true
|
||||||
|
|
||||||
parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
|
parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNonLocalReturn(
|
private fun checkNonLocalReturn(
|
||||||
@NotNull CallCheckerContext context,
|
context: CallCheckerContext,
|
||||||
@NotNull CallableDescriptor inlinableParameterDescriptor,
|
inlinableParameterDescriptor: CallableDescriptor,
|
||||||
@NotNull KtExpression parameterUsage
|
parameterUsage: KtExpression
|
||||||
) {
|
) {
|
||||||
if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return;
|
if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return
|
||||||
|
|
||||||
if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getResolutionContext())) {
|
if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.resolutionContext)) {
|
||||||
context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage));
|
context.trace.report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user