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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
import org.jetbrains.kotlin.lexer.KtToken;
|
import org.jetbrains.kotlin.lexer.KtToken;
|
||||||
@@ -51,13 +50,13 @@ import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturn
|
|||||||
class InlineChecker implements CallChecker {
|
class InlineChecker implements CallChecker {
|
||||||
private final FunctionDescriptor descriptor;
|
private final FunctionDescriptor descriptor;
|
||||||
private final Set<CallableDescriptor> inlinableParameters = new LinkedHashSet<CallableDescriptor>();
|
private final Set<CallableDescriptor> inlinableParameters = new LinkedHashSet<CallableDescriptor>();
|
||||||
private final boolean isEffectivelyPublicOrPublishedApiFunction;
|
private final EffectiveVisibility inlineFunEffectiveVisibility;
|
||||||
private final boolean isEffectivelyPrivateApiFunction;
|
private final boolean isEffectivelyPrivateApiFunction;
|
||||||
|
|
||||||
public InlineChecker(@NotNull FunctionDescriptor descriptor) {
|
public InlineChecker(@NotNull FunctionDescriptor descriptor) {
|
||||||
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.descriptor = descriptor;
|
||||||
this.isEffectivelyPublicOrPublishedApiFunction = isEffectivelyPublicOrPublishedApi(descriptor);
|
this.inlineFunEffectiveVisibility = EffectiveVisibilityKt.effectiveVisibility(descriptor, descriptor.getVisibility(), true);
|
||||||
this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor);
|
this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor);
|
||||||
for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
|
for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
|
||||||
if (isInlinableParameter(param)) {
|
if (isInlinableParameter(param)) {
|
||||||
@@ -239,31 +238,33 @@ class InlineChecker implements CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkVisibilityAndAccess(
|
private void checkVisibilityAndAccess(
|
||||||
@NotNull CallableDescriptor declarationDescriptor,
|
@NotNull CallableDescriptor calledDescriptor,
|
||||||
@NotNull KtElement expression,
|
@NotNull KtElement expression,
|
||||||
@NotNull CallCheckerContext context
|
@NotNull CallCheckerContext context
|
||||||
) {
|
) {
|
||||||
boolean declarationDescriptorIsPublicOrPublishedApi = isEffectivelyPublicOrPublishedApi(declarationDescriptor) ||
|
EffectiveVisibility calledFunEffectiveVisibility =
|
||||||
isDefinedInInlineFunction(declarationDescriptor);
|
isDefinedInInlineFunction(calledDescriptor) ?
|
||||||
if (isEffectivelyPublicOrPublishedApiFunction &&
|
EffectiveVisibility.Public.INSTANCE :
|
||||||
!declarationDescriptorIsPublicOrPublishedApi &&
|
EffectiveVisibilityKt.effectiveVisibility(calledDescriptor, calledDescriptor.getVisibility(), true);
|
||||||
declarationDescriptor.getVisibility() != Visibilities.LOCAL) {
|
|
||||||
context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor, descriptor));
|
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 {
|
else {
|
||||||
checkPrivateClassMemberAccess(declarationDescriptor, expression, context);
|
checkPrivateClassMemberAccess(calledDescriptor, expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEffectivelyPublicOrPublishedApiFunction && declarationDescriptor.getVisibility() == Visibilities.PROTECTED) {
|
if (isInlineFunPublicOrPublishedApi &&
|
||||||
context.getTrace().report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor));
|
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(
|
private void checkPrivateClassMemberAccess(
|
||||||
@NotNull DeclarationDescriptor declarationDescriptor,
|
@NotNull DeclarationDescriptor declarationDescriptor,
|
||||||
@NotNull KtElement expression,
|
@NotNull KtElement expression,
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
// !DIAGNOSTICS: -EXPOSED_PARAMETER_TYPE -NOTHING_TO_INLINE
|
// !DIAGNOSTICS: -EXPOSED_PARAMETER_TYPE -NOTHING_TO_INLINE
|
||||||
|
|
||||||
|
// FILE: JavaClass.java
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class JavaClass {
|
||||||
|
protected void bind() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
open class A {
|
open class A {
|
||||||
protected fun test() {}
|
protected fun test() {}
|
||||||
|
|
||||||
@@ -28,6 +36,13 @@ open class A {
|
|||||||
zVar
|
zVar
|
||||||
<!PROTECTED_CALL_FROM_PUBLIC_INLINE!>zVar<!> = "123"
|
<!PROTECTED_CALL_FROM_PUBLIC_INLINE!>zVar<!> = "123"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected inline fun callFromProtected() {
|
||||||
|
test()
|
||||||
|
zVar
|
||||||
|
zVar = "123"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class B : A() {
|
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 {
|
internal class AInternal {
|
||||||
protected fun test() {}
|
protected fun test() {}
|
||||||
@@ -54,4 +88,14 @@ internal class AInternal {
|
|||||||
internal inline fun call2() {
|
internal inline fun call2() {
|
||||||
test()
|
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 var zVar: kotlin.String
|
||||||
public final inline fun call(): kotlin.Unit
|
public final inline fun call(): kotlin.Unit
|
||||||
internal final inline fun callFromInternal(): 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
|
@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 equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
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 override /*1*/ /*fake_override*/ var zVar: kotlin.String
|
||||||
public final inline override /*1*/ /*fake_override*/ fun call(): kotlin.Unit
|
public final inline override /*1*/ /*fake_override*/ fun call(): kotlin.Unit
|
||||||
internal final inline override /*1*/ /*fake_override*/ fun callFromInternal(): 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
|
@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 equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
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 final inline fun testB(): kotlin.Unit
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
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>() {
|
public class AppServiceModule : AbstractModule<String>() {
|
||||||
inline fun <reified T> AbstractModule<Int>.bind() {
|
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
|
x checkType { _<String>() } // check that Class receiver is used instead of extension one
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user