K2: fix visibility checks for static overrides via imported from static

#KT-53441 In Progress
This commit is contained in:
Mikhail Glukhikh
2022-10-27 12:11:21 +02:00
committed by Space Team
parent cc1a094b6c
commit f070401bb5
13 changed files with 107 additions and 43 deletions
@@ -1,4 +1,4 @@
FILE: main.kt FILE: main.kt
public final fun test(list: R|kotlin/collections/List<kotlin/String>|, string: R|kotlin/String|): R|kotlin/Unit| { public final fun test(list: R|kotlin/collections/List<kotlin/String>|, string: R|kotlin/String|): R|kotlin/Unit| {
R|/Matchers.assertThat|<R|ft<kotlin/collections/List<kotlin/String>, kotlin/collections/List<kotlin/String>?>|>(R|<local>/list|, R|/Matchers.hasItem|<R|kotlin/String!|>(R|<local>/string|)) Q|Matchers|.R|/Matchers.assertThat|<R|ft<kotlin/collections/List<kotlin/String>, kotlin/collections/List<kotlin/String>?>|>(R|<local>/list|, Q|Matchers|.R|/Matchers.hasItem|<R|kotlin/String!|>(R|<local>/string|))
} }
@@ -1,4 +1,4 @@
FILE: FlexiblePrimitiveOverloading.kt FILE: FlexiblePrimitiveOverloading.kt
public final fun foo(): R|kotlin/Unit| { public final fun foo(): R|kotlin/Unit| {
R|java/lang/Integer.getInteger|(String(text), Int(239)) Q|java/lang/Integer|.R|java/lang/Integer.getInteger|(String(text), Int(239))
} }
@@ -102,7 +102,7 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
if (isExpectAndActual(declaration, conflicting)) return if (isExpectAndActual(declaration, conflicting)) return
if ( if (
conflicting is FirMemberDeclaration && conflicting is FirMemberDeclaration &&
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), null) !session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
) return ) return
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations) val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations) val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
@@ -171,7 +171,7 @@ object FirOverrideChecker : FirClassChecker() {
context.session, context.session,
file, file,
containingDeclarations, containingDeclarations,
null, dispatchReceiver = null,
skipCheckForContainingClassVisibility = true skipCheckForContainingClassVisibility = true
) )
} }
@@ -281,7 +281,7 @@ object FirOverrideChecker : FirClassChecker() {
context.session, context.session,
file, file,
containingDeclarations, containingDeclarations,
null, dispatchReceiver = null,
skipCheckForContainingClassVisibility = true skipCheckForContainingClassVisibility = true
) )
}?.originalOrSelf() ?: return }?.originalOrSelf() ?: return
@@ -35,9 +35,8 @@ object FirVisibilityQualifierChecker : FirResolvedQualifierChecker() {
val firFile = context.containingDeclarations.firstOrNull() as? FirFile ?: return val firFile = context.containingDeclarations.firstOrNull() as? FirFile ?: return
val firClassLikeDeclaration = symbol.fir val firClassLikeDeclaration = symbol.fir
if (!context.session.visibilityChecker.isVisible( if (!context.session.visibilityChecker.isClassLikeVisible(
firClassLikeDeclaration, context.session, firFile, context.containingDeclarations, firClassLikeDeclaration, context.session, firFile, context.containingDeclarations,
dispatchReceiver = null,
) )
) { ) {
reporter.reportOn(expression.source, FirErrors.INVISIBLE_REFERENCE, symbol, context) reporter.reportOn(expression.source, FirErrors.INVISIBLE_REFERENCE, symbol, context)
@@ -72,6 +72,25 @@ abstract class FirVisibilityChecker : FirSessionComponent {
} }
} }
fun isClassLikeVisible(
declaration: FirClassLikeDeclaration,
session: FirSession,
useSiteFile: FirFile,
containingDeclarations: List<FirDeclaration>,
): Boolean {
return isVisible(
declaration,
session,
useSiteFile,
containingDeclarations,
dispatchReceiver = null,
isCallToPropertySetter = false,
staticQualifierClassForCallable = null,
skipCheckForContainingClassVisibility = false,
supertypeSupplier = SupertypeSupplier.Default
)
}
fun isVisible( fun isVisible(
declaration: FirMemberDeclaration, declaration: FirMemberDeclaration,
session: FirSession, session: FirSession,
@@ -79,6 +98,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
containingDeclarations: List<FirDeclaration>, containingDeclarations: List<FirDeclaration>,
dispatchReceiver: ReceiverValue?, dispatchReceiver: ReceiverValue?,
isCallToPropertySetter: Boolean = false, isCallToPropertySetter: Boolean = false,
staticQualifierClassForCallable: FirRegularClass? = null,
// There's no need to check if containing class is visible in case we check if a member might be overridden in a subclass // There's no need to check if containing class is visible in case we check if a member might be overridden in a subclass
// because visibility for its supertype that contain overridden member is being checked when resolving the type reference. // because visibility for its supertype that contain overridden member is being checked when resolving the type reference.
// Such flag is not necessary in FE1.0, since there are full structure of fake overrides and containing declaration for overridden // Such flag is not necessary in FE1.0, since there are full structure of fake overrides and containing declaration for overridden
@@ -108,8 +128,14 @@ abstract class FirVisibilityChecker : FirSessionComponent {
supertypeSupplier supertypeSupplier
) ?: return true ) ?: return true
return generateSequence(parentClass) { it.containingNonLocalClass(session) }.all { parent -> return generateSequence(parentClass) { it.containingNonLocalClass(session) }.all { parent ->
val classLikeToCheck =
if (staticQualifierClassForCallable?.isSubClass(parent.symbol.toLookupTag(), session, supertypeSupplier) == true) {
staticQualifierClassForCallable
} else {
parent
}
isSpecificDeclarationVisible( isSpecificDeclarationVisible(
parent, classLikeToCheck,
session, session,
useSiteFile, useSiteFile,
containingDeclarations, containingDeclarations,
@@ -61,9 +61,14 @@ abstract class FirAbstractImportingScope(
for (import in imports) { for (import in imports) {
val importedName = name ?: import.importedName ?: continue val importedName = name ?: import.importedName ?: continue
if (isExcluded(import, importedName)) continue if (isExcluded(import, importedName)) continue
val staticsScope = import.resolvedParentClassId?.let(::getStaticsScope) val parentClassId = import.resolvedParentClassId
val staticsScope = parentClassId?.let { getStaticsScope(it) }
if (staticsScope != null) { if (staticsScope != null) {
staticsScope.processFunctionsByName(importedName, processor) staticsScope.processFunctionsByName(importedName) {
if (it.isStatic) processor(it.fir.buildImportedCopy(parentClassId).symbol)
else processor(it)
}
} else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) { } else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) {
for (symbol in provider.getTopLevelFunctionSymbols(import.packageFqName, importedName)) { for (symbol in provider.getTopLevelFunctionSymbols(import.packageFqName, importedName)) {
processor(symbol) processor(symbol)
@@ -76,9 +81,18 @@ abstract class FirAbstractImportingScope(
for (import in imports) { for (import in imports) {
val importedName = name ?: import.importedName ?: continue val importedName = name ?: import.importedName ?: continue
if (isExcluded(import, importedName)) continue if (isExcluded(import, importedName)) continue
val staticsScope = import.resolvedParentClassId?.let(::getStaticsScope) val parentClassId = import.resolvedParentClassId
val staticsScope = parentClassId?.let { getStaticsScope(it) }
if (staticsScope != null) { if (staticsScope != null) {
staticsScope.processPropertiesByName(importedName, processor) staticsScope.processPropertiesByName(importedName) {
if (it is FirPropertySymbol) {
if (it.isStatic) processor(it.fir.buildImportedCopy(parentClassId).symbol)
else processor(it)
} else {
processor(it)
}
}
} else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) { } else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) {
for (symbol in provider.getTopLevelPropertySymbols(import.packageFqName, importedName)) { for (symbol in provider.getTopLevelPropertySymbols(import.packageFqName, importedName)) {
processor(symbol) processor(symbol)
@@ -5,10 +5,7 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
@@ -26,13 +23,7 @@ class FirObjectImportedCallableScope(
) : FirContainingNamesAwareScope() { ) : FirContainingNamesAwareScope() {
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
objectUseSiteScope.processFunctionsByName(name) wrapper@{ symbol -> objectUseSiteScope.processFunctionsByName(name) wrapper@{ symbol ->
val function = symbol.fir val syntheticFunction = symbol.fir.buildImportedCopy(importedClassId)
val syntheticFunction = buildSimpleFunctionCopy(function) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirNamedFunctionSymbol(CallableId(importedClassId, name))
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, function)
}
processor(syntheticFunction.symbol) processor(syntheticFunction.symbol)
} }
} }
@@ -43,14 +34,7 @@ class FirObjectImportedCallableScope(
processor(symbol) processor(symbol)
return@wrapper return@wrapper
} }
val property = symbol.fir val syntheticProperty = symbol.fir.buildImportedCopy(importedClassId)
val syntheticProperty = buildPropertyCopy(property) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirPropertySymbol(CallableId(importedClassId, name))
this.delegateFieldSymbol = null
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, property)
}
processor(syntheticProperty.symbol) processor(syntheticProperty.symbol)
} }
} }
@@ -60,6 +44,25 @@ class FirObjectImportedCallableScope(
override fun getClassifierNames(): Set<Name> = emptySet() override fun getClassifierNames(): Set<Name> = emptySet()
} }
internal fun FirSimpleFunction.buildImportedCopy(importedClassId: ClassId): FirSimpleFunction {
return buildSimpleFunctionCopy(this) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirNamedFunctionSymbol(CallableId(importedClassId, name))
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, this@buildImportedCopy)
}
}
internal fun FirProperty.buildImportedCopy(importedClassId: ClassId): FirProperty {
return buildPropertyCopy(this) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirPropertySymbol(CallableId(importedClassId, name))
this.delegateFieldSymbol = null
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, this@buildImportedCopy)
}
}
private object ImportedFromObjectOrStaticClassIdKey : FirDeclarationDataKey() private object ImportedFromObjectOrStaticClassIdKey : FirDeclarationDataKey()
class ImportedFromObjectOrStaticData<D : FirCallableDeclaration>( class ImportedFromObjectOrStaticData<D : FirCallableDeclaration>(
@@ -48,13 +48,11 @@ fun BodyResolveComponents.resolveRootPartOfQualifier(
for (scope in createCurrentScopeList()) { for (scope in createCurrentScopeList()) {
scope.getSingleVisibleClassifier(session, this, name)?.let { scope.getSingleVisibleClassifier(session, this, name)?.let {
if (it is FirRegularClassSymbol) { if (it is FirRegularClassSymbol) {
val isVisible = session.visibilityChecker.isVisible( val isVisible = session.visibilityChecker.isClassLikeVisible(
it.fir, it.fir,
session, session,
file, file,
containingDeclarations, containingDeclarations,
null,
false,
) )
if (!isVisible) { if (!isVisible) {
return@let return@let
@@ -9,12 +9,11 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirBackingField import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.builder.buildSmartCastExpression import org.jetbrains.kotlin.fir.expressions.builder.buildSmartCastExpression
@@ -23,20 +22,27 @@ import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isNullableNothing import org.jetbrains.kotlin.fir.types.isNullableNothing
import org.jetbrains.kotlin.fir.types.makeConeTypeDefinitelyNotNullOrNotNull import org.jetbrains.kotlin.fir.types.makeConeTypeDefinitelyNotNullOrNotNull
import org.jetbrains.kotlin.fir.types.typeContext import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.utils.addToStdlib.runIf
fun FirVisibilityChecker.isVisible( fun FirVisibilityChecker.isVisible(
declaration: FirMemberDeclaration, declaration: FirMemberDeclaration,
callInfo: CallInfo, callInfo: CallInfo,
dispatchReceiverValue: ReceiverValue? dispatchReceiverValue: ReceiverValue?
): Boolean = ): Boolean {
isVisible( val staticQualifierForCallable = runIf(declaration is FirCallableDeclaration && declaration.isStatic) {
val explicitReceiver = callInfo.explicitReceiver ?: (dispatchReceiverValue as? ExpressionReceiverValue)?.explicitReceiver
(explicitReceiver as? FirResolvedQualifier)?.symbol?.fir as? FirRegularClass
}
return isVisible(
declaration, declaration,
callInfo.session, callInfo.session,
callInfo.containingFile, callInfo.containingFile,
callInfo.containingDeclarations, callInfo.containingDeclarations,
dispatchReceiverValue, dispatchReceiverValue,
callInfo.callSite is FirVariableAssignment staticQualifierClassForCallable = staticQualifierForCallable,
isCallToPropertySetter = callInfo.callSite is FirVariableAssignment
) )
}
fun FirVisibilityChecker.isVisible( fun FirVisibilityChecker.isVisible(
declaration: FirMemberDeclaration, declaration: FirMemberDeclaration,
@@ -132,12 +132,11 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val symbol = val symbol =
fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false
val declaration = symbol.fir as? FirRegularClass ?: return true val declaration = symbol.fir as? FirRegularClass ?: return true
visibilityChecker.isVisible( visibilityChecker.isClassLikeVisible(
declaration, declaration,
components.session, components.session,
components.context.file, components.context.file,
components.context.containers, components.context.containers,
dispatchReceiver = null
) )
} }
is ConeTypeParameterType -> true is ConeTypeParameterType -> true
@@ -6,6 +6,8 @@ package foo;
class Base { class Base {
protected static void foo() {} protected static void foo() {}
protected void bar() {} protected void bar() {}
public static void baz() {}
} }
// FILE: foo/Derived.java // FILE: foo/Derived.java
@@ -24,3 +26,15 @@ class Impl : Derived() {
bar() bar()
} }
} }
fun test() {
Derived.baz()
}
// FILE: withImport.kt
import foo.Derived.baz
fun test() {
baz()
}
@@ -1,6 +1,9 @@
package package
public fun test(): kotlin.Unit
package bar { package bar {
public fun test(): kotlin.Unit
public final class Impl : foo.Derived { public final class Impl : foo.Derived {
public constructor Impl() public constructor Impl()
@@ -22,6 +25,7 @@ package foo {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members // Static members
public open fun baz(): kotlin.Unit
protected/*protected static*/ open fun foo(): kotlin.Unit protected/*protected static*/ open fun foo(): kotlin.Unit
} }
@@ -33,6 +37,7 @@ package foo {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members // Static members
public open override /*1*/ /*fake_override*/ fun baz(): kotlin.Unit
protected/*protected static*/ open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit protected/*protected static*/ open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
} }
} }