Published-api checker refactoring, support java package-protected visibility
This commit is contained in:
+19
-18
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.lexer.KtToken;
|
||||
@@ -51,13 +50,13 @@ import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturn
|
||||
class InlineChecker implements CallChecker {
|
||||
private final FunctionDescriptor descriptor;
|
||||
private final Set<CallableDescriptor> inlinableParameters = new LinkedHashSet<CallableDescriptor>();
|
||||
private final boolean isEffectivelyPublicOrPublishedApiFunction;
|
||||
private final EffectiveVisibility inlineFunEffectiveVisibility;
|
||||
private final boolean isEffectivelyPrivateApiFunction;
|
||||
|
||||
public InlineChecker(@NotNull FunctionDescriptor descriptor) {
|
||||
assert InlineUtil.isInline(descriptor) : "This extension should be created only for inline functions: " + descriptor;
|
||||
this.descriptor = descriptor;
|
||||
this.isEffectivelyPublicOrPublishedApiFunction = isEffectivelyPublicOrPublishedApi(descriptor);
|
||||
this.inlineFunEffectiveVisibility = EffectiveVisibilityKt.effectiveVisibility(descriptor, descriptor.getVisibility(), true);
|
||||
this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor);
|
||||
for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
|
||||
if (isInlinableParameter(param)) {
|
||||
@@ -239,31 +238,33 @@ class InlineChecker implements CallChecker {
|
||||
}
|
||||
|
||||
private void checkVisibilityAndAccess(
|
||||
@NotNull CallableDescriptor declarationDescriptor,
|
||||
@NotNull CallableDescriptor calledDescriptor,
|
||||
@NotNull KtElement expression,
|
||||
@NotNull CallCheckerContext context
|
||||
) {
|
||||
boolean declarationDescriptorIsPublicOrPublishedApi = isEffectivelyPublicOrPublishedApi(declarationDescriptor) ||
|
||||
isDefinedInInlineFunction(declarationDescriptor);
|
||||
if (isEffectivelyPublicOrPublishedApiFunction &&
|
||||
!declarationDescriptorIsPublicOrPublishedApi &&
|
||||
declarationDescriptor.getVisibility() != Visibilities.LOCAL) {
|
||||
context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor, descriptor));
|
||||
EffectiveVisibility calledFunEffectiveVisibility =
|
||||
isDefinedInInlineFunction(calledDescriptor) ?
|
||||
EffectiveVisibility.Public.INSTANCE :
|
||||
EffectiveVisibilityKt.effectiveVisibility(calledDescriptor, calledDescriptor.getVisibility(), true);
|
||||
|
||||
boolean isCalledFunPublicOrPublishedApi = calledFunEffectiveVisibility.getPublicApi();
|
||||
boolean isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.getPublicApi();
|
||||
if (isInlineFunPublicOrPublishedApi &&
|
||||
!isCalledFunPublicOrPublishedApi &&
|
||||
calledDescriptor.getVisibility() != Visibilities.LOCAL) {
|
||||
context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor, descriptor));
|
||||
}
|
||||
else {
|
||||
checkPrivateClassMemberAccess(declarationDescriptor, expression, context);
|
||||
checkPrivateClassMemberAccess(calledDescriptor, expression, context);
|
||||
}
|
||||
|
||||
if (isEffectivelyPublicOrPublishedApiFunction && declarationDescriptor.getVisibility() == Visibilities.PROTECTED) {
|
||||
context.getTrace().report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor));
|
||||
if (isInlineFunPublicOrPublishedApi &&
|
||||
inlineFunEffectiveVisibility.toVisibility() != Visibilities.PROTECTED &&
|
||||
calledFunEffectiveVisibility.toVisibility() == Visibilities.PROTECTED) {
|
||||
context.getTrace().report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEffectivelyPublicOrPublishedApi(@NotNull CallableDescriptor descriptor) {
|
||||
EffectiveVisibility visibility = EffectiveVisibilityKt.effectiveVisibility(descriptor, descriptor.getVisibility(), true);
|
||||
return visibility.getPublicApi();
|
||||
}
|
||||
|
||||
private void checkPrivateClassMemberAccess(
|
||||
@NotNull DeclarationDescriptor declarationDescriptor,
|
||||
@NotNull KtElement expression,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
// !DIAGNOSTICS: -EXPOSED_PARAMETER_TYPE -NOTHING_TO_INLINE
|
||||
|
||||
// FILE: JavaClass.java
|
||||
|
||||
|
||||
public abstract class JavaClass {
|
||||
protected void bind() {}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
open class A {
|
||||
protected fun test() {}
|
||||
|
||||
@@ -28,6 +36,13 @@ open class A {
|
||||
zVar
|
||||
<!PROTECTED_CALL_FROM_PUBLIC_INLINE!>zVar<!> = "123"
|
||||
}
|
||||
|
||||
protected inline fun callFromProtected() {
|
||||
test()
|
||||
zVar
|
||||
zVar = "123"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
@@ -36,6 +51,25 @@ class B : A() {
|
||||
}
|
||||
}
|
||||
|
||||
class C : JavaClass() {
|
||||
inline fun call() {
|
||||
<!PROTECTED_CALL_FROM_PUBLIC_INLINE!>bind<!>()
|
||||
}
|
||||
|
||||
internal inline fun callFromInternal() {
|
||||
bind()
|
||||
}
|
||||
|
||||
protected inline fun callFromProtected() {
|
||||
bind()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal inline fun callFromPublished() {
|
||||
<!PROTECTED_CALL_FROM_PUBLIC_INLINE!>bind<!>()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class AInternal {
|
||||
protected fun test() {}
|
||||
@@ -54,4 +88,14 @@ internal class AInternal {
|
||||
internal inline fun call2() {
|
||||
test()
|
||||
}
|
||||
}
|
||||
|
||||
private class X {
|
||||
|
||||
public class Z : A() {
|
||||
public inline fun effictivelyNonPublic() {
|
||||
test()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ public open class A {
|
||||
public final var zVar: kotlin.String
|
||||
public final inline fun call(): kotlin.Unit
|
||||
internal final inline fun callFromInternal(): kotlin.Unit
|
||||
protected final inline fun callFromProtected(): kotlin.Unit
|
||||
@kotlin.PublishedApi internal final inline fun callFromPublished(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
@@ -31,6 +32,7 @@ public final class B : A {
|
||||
public final override /*1*/ /*fake_override*/ var zVar: kotlin.String
|
||||
public final inline override /*1*/ /*fake_override*/ fun call(): kotlin.Unit
|
||||
internal final inline override /*1*/ /*fake_override*/ fun callFromInternal(): kotlin.Unit
|
||||
protected final inline override /*1*/ /*fake_override*/ fun callFromProtected(): kotlin.Unit
|
||||
@kotlin.PublishedApi internal final inline override /*1*/ /*fake_override*/ fun callFromPublished(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
@@ -38,3 +40,45 @@ public final class B : A {
|
||||
public final inline fun testB(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class C : JavaClass {
|
||||
public constructor C()
|
||||
protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun bind(): kotlin.Unit
|
||||
public final inline fun call(): kotlin.Unit
|
||||
internal final inline fun callFromInternal(): kotlin.Unit
|
||||
protected final inline fun callFromProtected(): kotlin.Unit
|
||||
@kotlin.PublishedApi internal final inline fun callFromPublished(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public abstract class JavaClass {
|
||||
public constructor JavaClass()
|
||||
protected/*protected and package*/ open fun bind(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
private final class X {
|
||||
public constructor X()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public final class Z : A {
|
||||
public constructor Z()
|
||||
protected final override /*1*/ /*fake_override*/ val z: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ var zVar: kotlin.String
|
||||
public final inline override /*1*/ /*fake_override*/ fun call(): kotlin.Unit
|
||||
internal final inline override /*1*/ /*fake_override*/ fun callFromInternal(): kotlin.Unit
|
||||
protected final inline override /*1*/ /*fake_override*/ fun callFromProtected(): kotlin.Unit
|
||||
@kotlin.PublishedApi internal final inline override /*1*/ /*fake_override*/ fun callFromPublished(): kotlin.Unit
|
||||
public final inline fun effictivelyNonPublic(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun test(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ fun <T> javaClass(): Class<T> = null!!
|
||||
|
||||
public class AppServiceModule : AbstractModule<String>() {
|
||||
inline fun <reified T> AbstractModule<Int>.bind() {
|
||||
val x = bind(javaClass<T>())
|
||||
val x = <!PROTECTED_CALL_FROM_PUBLIC_INLINE!>bind<!>(javaClass<T>())
|
||||
|
||||
x checkType { _<String>() } // check that Class receiver is used instead of extension one
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user