From 29502ba12681236aac4c3cd1363c3b42bccca8f8 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Fri, 7 Oct 2022 11:22:24 +0300 Subject: [PATCH] [Analysis API FIR] add check for public api --- .../components/KtFe10VisibilityChecker.kt | 7 +++++++ .../api/fir/components/KtFirVisibilityChecker.kt | 14 ++++++++++++++ .../api/components/KtVisibilityCheckerMixIn.kt | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10VisibilityChecker.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10VisibilityChecker.kt index 7d148c132b4..96869114fdc 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10VisibilityChecker.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10VisibilityChecker.kt @@ -23,7 +23,9 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension +import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy @@ -72,6 +74,11 @@ internal class KtFe10VisibilityChecker( return false } + + override fun isPublicApi(symbol: KtSymbolWithVisibility): Boolean { + val descriptor = getSymbolDescriptor(symbol) as? DeclarationDescriptorWithVisibility ?: return false + return descriptor.isEffectivelyPublicApi || descriptor.isPublishedApi() + } } private fun findContainingNonLocalDeclaration(element: PsiElement): KtCallableDeclaration? { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt index 726ad176215..9a24288d35e 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.components.KtVisibilityChecker import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFileSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol +import org.jetbrains.kotlin.analysis.api.fir.utils.firSymbol import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol @@ -19,8 +20,12 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue +import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.visibilityChecker import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject @@ -61,6 +66,15 @@ internal class KtFirVisibilityChecker( ) } + override fun isPublicApi(symbol: KtSymbolWithVisibility): Boolean { + require(symbol is KtFirSymbol<*>) + val declaration = symbol.firSymbol.fir as? FirMemberDeclaration ?: return false + + // Inspecting visibility requires resolving to status + declaration.lazyResolveToPhase(FirResolvePhase.STATUS) + return declaration.effectiveVisibility.publicApi || declaration.publishedApiEffectiveVisibility?.publicApi == true + } + private fun collectContainingDeclarations(position: PsiElement): List { val nonLocalContainer = findContainingNonLocalDeclaration(position) val nonLocalContainerFir = nonLocalContainer?.getOrBuildFirSafe(analysisSession.firResolveSession) diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtVisibilityCheckerMixIn.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtVisibilityCheckerMixIn.kt index 73d3122b12a..6e31ac05591 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtVisibilityCheckerMixIn.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtVisibilityCheckerMixIn.kt @@ -18,6 +18,8 @@ public abstract class KtVisibilityChecker : KtAnalysisSessionComponent() { position: PsiElement, receiverExpression: KtExpression? ): Boolean + + public abstract fun isPublicApi(symbol: KtSymbolWithVisibility): Boolean } public interface KtVisibilityCheckerMixIn : KtAnalysisSessionMixIn { @@ -29,4 +31,13 @@ public interface KtVisibilityCheckerMixIn : KtAnalysisSessionMixIn { ): Boolean = withValidityAssertion { analysisSession.visibilityChecker.isVisible(candidateSymbol, useSiteFile, position, receiverExpression) } + + /** + * Returns true for effectively public symbols, including internal declarations with @PublishedApi annotation. + * In 'Explicit API' mode explicit visibility modifier and explicit return types are required for such symbols. + * See FirExplicitApiDeclarationChecker.kt + */ + public fun isPublicApi(symbol: KtSymbolWithVisibility): Boolean = withValidityAssertion { + analysisSession.visibilityChecker.isPublicApi(symbol) + } }