From c051edcbee8ab1e9d6ecaaad838eace5614ec683 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 15 Mar 2022 12:49:01 +0300 Subject: [PATCH] FIR: add visibility filtering for qualifier resolve #KT-51621 Fixed --- .../visibleVsInvisibleQualifier.fir.txt | 2 +- .../resolve/visibleVsInvisibleQualifier.kt | 2 +- .../jetbrains/kotlin/fir/FirCallResolver.kt | 4 +- .../kotlin/fir/QualifiedNameResolution.kt | 7 +-- .../resolve/calls/ConstructorProcessing.kt | 53 ++++++++++++------- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.fir.txt b/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.fir.txt index 4f33249562a..ad445bfd495 100644 --- a/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.fir.txt @@ -2,5 +2,5 @@ FILE: test.kt package test public final fun test(): R|kotlin/Unit| { - R|kotlin/Unit|.R|first/Some.foo|() + Q|first/Some|.R|first/Some.foo|() } diff --git a/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.kt b/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.kt index a4cf6ce81f7..d4b17c4c28d 100644 --- a/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.kt +++ b/compiler/fir/analysis-tests/testData/resolve/visibleVsInvisibleQualifier.kt @@ -22,5 +22,5 @@ import first.* import second.* fun test() { - Some.foo() + Some.foo() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 28f0a99b4fa..227490dab85 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -288,9 +288,9 @@ class FirCallResolver( qualifiedAccess.source, qualifiedAccess.typeArguments, nonFatalDiagnosticFromExpression, + session, components - ) - ?.let { return it } + )?.let { return it } } var result = basicResult diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt index 8b1c6db1ada..b638c873a3b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt @@ -13,11 +13,11 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.calls.getSingleVisibleClassifier import org.jetbrains.kotlin.fir.resolve.createCurrentScopeList import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDeprecated import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.typeForQualifier -import org.jetbrains.kotlin.fir.scopes.getSingleClassifier import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.FirTypeProjection @@ -45,7 +45,7 @@ fun BodyResolveComponents.resolveRootPartOfQualifier( } for (scope in createCurrentScopeList()) { - scope.getSingleClassifier(name)?.let { + scope.getSingleVisibleClassifier(session, this, name)?.let { if (it is FirRegularClassSymbol) { val isVisible = session.visibilityChecker.isVisible( it.fir, @@ -88,6 +88,7 @@ fun FirResolvedQualifier.continueQualifier( source: KtSourceElement?, typeArguments: List, nonFatalDiagnosticsFromExpression: List?, + session: FirSession, components: BodyResolveComponents, ): FirResolvedQualifier? { val name = namedReference.name @@ -95,7 +96,7 @@ fun FirResolvedQualifier.continueQualifier( val firClass = outerClassSymbol.fir if (firClass !is FirClass) return null return firClass.scopeProvider.getNestedClassifierScope(firClass, components.session, components.scopeSession) - ?.getSingleClassifier(name) + ?.getSingleVisibleClassifier(session, components, name) ?.takeIf { it is FirClassLikeSymbol<*> } ?.let { nestedClassSymbol -> buildResolvedQualifier { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt index 153f8b2d7d6..b1f31663a84 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -19,10 +19,12 @@ import org.jetbrains.kotlin.fir.symbols.ensureResolved import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator +import org.jetbrains.kotlin.fir.scopes.processClassifiersByName import org.jetbrains.kotlin.fir.scopes.scopeForClass import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visibilityChecker +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue private operator fun Pair?.component1() = this?.first @@ -75,6 +77,37 @@ internal fun FirScope.processFunctionsAndConstructorsByName( private data class SymbolWithSubstitutor(val symbol: FirClassifierSymbol<*>, val substitutor: ConeSubstitutor) +fun FirScope.getSingleVisibleClassifier( + session: FirSession, + bodyResolveComponents: BodyResolveComponents, + name: Name +): FirClassifierSymbol<*>? = mutableSetOf>().apply { + processClassifiersByName(name) { classifierSymbol -> + if (!classifierSymbol.fir.isInvisibleOrHidden(session, bodyResolveComponents)) { + this.add(classifierSymbol) + } + } +}.singleOrNull() + +private fun FirDeclaration.isInvisibleOrHidden(session: FirSession, bodyResolveComponents: BodyResolveComponents): Boolean { + if (this is FirMemberDeclaration) { + if (!session.visibilityChecker.isVisible( + this, + session, + bodyResolveComponents.file, + bodyResolveComponents.containingDeclarations, + dispatchReceiver = null, + isCallToPropertySetter = false + ) + ) { + return true + } + } + + val deprecation = symbol.getDeprecationForCallSite() + return deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN +} + private fun FirScope.getFirstClassifierOrNull( callInfo: CallInfo, session: FirSession, @@ -85,25 +118,7 @@ private fun FirScope.getFirstClassifierOrNull( var result: SymbolWithSubstitutor? = null processClassifiersByNameWithSubstitution(callInfo.name) { symbol, substitutor -> val classifierDeclaration = symbol.fir - var isSuccessCandidate = true - if (classifierDeclaration is FirMemberDeclaration) { - if (!session.visibilityChecker.isVisible( - classifierDeclaration, - session, - bodyResolveComponents.file, - bodyResolveComponents.containingDeclarations, - dispatchReceiver = null, - isCallToPropertySetter = false - ) - ) { - isSuccessCandidate = false - } - } - - val deprecation = symbol.getDeprecationForCallSite() - if (deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN) { - isSuccessCandidate = false - } + val isSuccessCandidate = !classifierDeclaration.isInvisibleOrHidden(session, bodyResolveComponents) when { isSuccessCandidate && !isSuccessResult -> {