[FIR] KT-45972, KT-49072: Add visibility checks to the type resolution

This commit is contained in:
Nikolay Lunyak
2021-10-15 16:42:41 +03:00
committed by TeamCityServer
parent 2dc2a90755
commit 0eb2d117ef
17 changed files with 223 additions and 42 deletions
@@ -12477,6 +12477,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt");
}
@Test
@TestMetadata("InaccessiblePrivateInFile.kt")
public void testInaccessiblePrivateInFile() throws Exception {
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateInFile.kt");
}
@Test
@TestMetadata("invisibleFakeReferenceInImport.kt")
public void testInvisibleFakeReferenceInImport() throws Exception {
@@ -12477,6 +12477,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt");
}
@Test
@TestMetadata("InaccessiblePrivateInFile.kt")
public void testInaccessiblePrivateInFile() throws Exception {
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateInFile.kt");
}
@Test
@TestMetadata("invisibleFakeReferenceInImport.kt")
public void testInvisibleFakeReferenceInImport() throws Exception {
@@ -12477,6 +12477,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt");
}
@Test
@TestMetadata("InaccessiblePrivateInFile.kt")
public void testInaccessiblePrivateInFile() throws Exception {
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateInFile.kt");
}
@Test
@TestMetadata("invisibleFakeReferenceInImport.kt")
public void testInvisibleFakeReferenceInImport() throws Exception {
@@ -7,12 +7,19 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
abstract class FirTypeResolver : FirSessionComponent {
abstract fun resolveType(typeRef: FirTypeRef, scopeClassDeclaration: ScopeClassDeclaration, areBareTypesAllowed: Boolean, isOperandOfIsOperator: Boolean): ConeKotlinType
abstract fun resolveType(
typeRef: FirTypeRef,
scopeClassDeclaration: ScopeClassDeclaration,
areBareTypesAllowed: Boolean,
isOperandOfIsOperator: Boolean,
useSiteFile: FirFile?
): ConeKotlinType
}
val FirSession.typeResolver: FirTypeResolver by FirSession.sessionComponentAccessor()
@@ -7,8 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
@@ -23,7 +22,6 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeWrongNumberOfTypeArgumen
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -54,9 +52,52 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
}
}
private fun resolveSymbol(
symbol: FirBasedSymbol<*>,
qualifier: List<FirQualifierPart>,
qualifierResolver: FirQualifierResolver,
): FirBasedSymbol<*>? {
return when (symbol) {
is FirClassLikeSymbol<*> -> {
if (qualifier.size == 1) {
symbol
} else {
resolveLocalClassChain(symbol, qualifier)
?: qualifierResolver.resolveSymbolWithPrefix(qualifier, symbol.classId)
?: qualifierResolver.resolveEnumEntrySymbol(qualifier, symbol.classId)
}
}
is FirTypeParameterSymbol -> {
assert(qualifier.size == 1)
symbol
}
else -> error("!")
}
}
private fun FirBasedSymbol<*>?.isVisible(
useSiteFile: FirFile?,
containingDeclarations: List<FirDeclaration>,
): Boolean {
val declaration = this?.fir
return if (useSiteFile != null && declaration is FirMemberDeclaration) {
session.visibilityChecker.isVisible(
declaration,
session,
useSiteFile,
containingDeclarations,
null,
false,
)
} else {
true
}
}
private fun resolveToSymbol(
typeRef: FirTypeRef,
scopes: List<FirScope>,
scopeClassDeclaration: ScopeClassDeclaration,
useSiteFile: FirFile?,
): Pair<FirBasedSymbol<*>?, ConeSubstitutor?> {
return when (typeRef) {
is FirResolvedTypeRef -> {
@@ -66,37 +107,39 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
is FirUserTypeRef -> {
val qualifierResolver = session.qualifierResolver
var resolvedSymbol: FirBasedSymbol<*>? = null
var acceptedSymbol: FirBasedSymbol<*>? = null
var firstNonApplicable: FirBasedSymbol<*>? = null
var substitutor: ConeSubstitutor? = null
val qualifier = typeRef.qualifier
val scopes = scopeClassDeclaration.scopes
val containingDeclarations = scopeClassDeclaration.containingDeclarations
for (scope in scopes) {
if (resolvedSymbol != null) {
if (acceptedSymbol != null) {
break
}
scope.processClassifiersByNameWithSubstitution(qualifier.first().name) { symbol, substitutorFromScope ->
if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution
resolvedSymbol = when (symbol) {
is FirClassLikeSymbol<*> -> {
if (qualifier.size == 1) {
symbol
} else {
resolveLocalClassChain(symbol, qualifier)
?: qualifierResolver.resolveSymbolWithPrefix(qualifier, symbol.classId)
?: qualifierResolver.resolveEnumEntrySymbol(qualifier, symbol.classId)
}
}
is FirTypeParameterSymbol -> {
assert(qualifier.size == 1)
symbol
}
else -> error("!")
if (acceptedSymbol != null) {
return@processClassifiersByNameWithSubstitution
}
val resolvedSymbol = resolveSymbol(symbol, qualifier, qualifierResolver)
if (resolvedSymbol.isVisible(useSiteFile, containingDeclarations)) {
acceptedSymbol = resolvedSymbol
substitutor = substitutorFromScope
} else {
firstNonApplicable = resolvedSymbol
}
substitutor = substitutorFromScope
}
}
if (acceptedSymbol == null) {
acceptedSymbol = firstNonApplicable
}
// TODO: Imports
val resultSymbol: FirBasedSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(qualifier)
val resultSymbol: FirBasedSymbol<*>? = acceptedSymbol ?: qualifierResolver.resolveSymbol(qualifier)
resultSymbol to substitutor
}
@@ -377,18 +420,19 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
typeRef: FirTypeRef,
scopeClassDeclaration: ScopeClassDeclaration,
areBareTypesAllowed: Boolean,
isOperandOfIsOperator: Boolean
isOperandOfIsOperator: Boolean,
useSiteFile: FirFile?,
): ConeKotlinType {
return when (typeRef) {
is FirResolvedTypeRef -> typeRef.type
is FirUserTypeRef -> {
val (symbol, substitutor) = resolveToSymbol(typeRef, scopeClassDeclaration.scopes)
val (symbol, substitutor) = resolveToSymbol(typeRef, scopeClassDeclaration, useSiteFile)
resolveUserType(
typeRef,
symbol,
substitutor,
areBareTypesAllowed,
scopeClassDeclaration.topDeclaration,
scopeClassDeclaration.containingDeclarations.lastOrNull(),
isOperandOfIsOperator
)
}
@@ -73,7 +73,16 @@ class FirSpecificTypeResolverTransformer(
val scopeOwnerLookupNames = data.scopes.flatMap { it.scopeOwnerLookupNames }
session.lookupTracker?.recordTypeLookup(typeRef, scopeOwnerLookupNames, currentFile?.source)
typeRef.transformChildren(this, data)
return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed, isOperandOfIsOperator))
return transformType(
typeRef,
typeResolver.resolveType(
typeRef,
data,
areBareTypesAllowed,
isOperandOfIsOperator,
currentFile,
)
)
}
@OptIn(PrivateForInline::class)
@@ -84,7 +93,13 @@ class FirSpecificTypeResolverTransformer(
functionTypeRef.transformChildren(this, data)
val scopeOwnerLookupNames = data.scopes.flatMap { it.scopeOwnerLookupNames }
session.lookupTracker?.recordTypeLookup(functionTypeRef, scopeOwnerLookupNames, currentFile?.source)
val resolvedType = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed, isOperandOfIsOperator).takeIfAcceptable()
val resolvedType = typeResolver.resolveType(
functionTypeRef,
data,
areBareTypesAllowed,
isOperandOfIsOperator,
currentFile,
).takeIfAcceptable()
return if (resolvedType != null && resolvedType !is ConeClassErrorType) {
buildResolvedTypeRef {
source = functionTypeRef.source
@@ -84,13 +84,17 @@ fun <F : FirClassLikeDeclaration> F.runSupertypeResolvePhaseForLocalClass(
currentScopeList: List<FirScope>,
localClassesNavigationInfo: LocalClassesNavigationInfo,
firProviderInterceptor: FirProviderInterceptor?,
useSiteFile: FirFile,
containingDeclarations: List<FirDeclaration>,
): F {
val supertypeComputationSession = SupertypeComputationSession()
val supertypeResolverVisitor = FirSupertypeResolverVisitor(
session, supertypeComputationSession, scopeSession,
currentScopeList.toPersistentList(),
localClassesNavigationInfo,
firProviderInterceptor
firProviderInterceptor,
useSiteFile,
containingDeclarations,
)
this.accept(supertypeResolverVisitor, null)
@@ -204,10 +208,20 @@ open class FirSupertypeResolverVisitor(
private val scopeForLocalClass: PersistentList<FirScope>? = null,
private val localClassesNavigationInfo: LocalClassesNavigationInfo? = null,
private val firProviderInterceptor: FirProviderInterceptor? = null,
private val useSiteFile: FirFile? = null,
containingDeclarations: List<FirDeclaration> = emptyList(),
) : FirDefaultVisitor<Unit, Any?>() {
private val supertypeGenerationExtensions = session.extensionService.supertypeGenerators
private val classDeclarationsStack = ArrayDeque<FirRegularClass>()
init {
containingDeclarations.forEach {
if (it is FirRegularClass) {
classDeclarationsStack.add(it)
}
}
}
private fun getFirClassifierContainerFileIfAny(symbol: FirClassLikeSymbol<*>): FirFile? =
if (firProviderInterceptor != null) firProviderInterceptor.getFirClassifierContainerFileIfAny(symbol)
else session.firProvider.getFirClassifierContainerFileIfAny(symbol.classId)
@@ -301,10 +315,12 @@ open class FirSupertypeResolverVisitor(
val scopes = prepareScopes(classLikeDeclaration)
val transformer = FirSpecificTypeResolverTransformer(session)
val resolvedTypesRefs = resolveSuperTypeRefs(
transformer,
ScopeClassDeclaration(scopes, classDeclarationsStack.lastOrNull())
)
val resolvedTypesRefs = transformer.withFile(useSiteFile) {
resolveSuperTypeRefs(
transformer,
ScopeClassDeclaration(scopes, classDeclarationsStack)
)
}
supertypeComputationSession.storeSupertypes(classLikeDeclaration, resolvedTypesRefs)
return resolvedTypesRefs
@@ -178,7 +178,7 @@ open class FirTypeResolveTransformer(
return typeResolverTransformer.withFile(currentFile) {
typeRef.transform(
typeResolverTransformer,
ScopeClassDeclaration(towerScope, classDeclarationsStack.lastOrNull())
ScopeClassDeclaration(towerScope, classDeclarationsStack)
)
}
}
@@ -10,5 +10,5 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
data class ScopeClassDeclaration(
val scopes: List<FirScope>,
val topDeclaration: FirRegularClass?
val containingDeclarations: List<FirRegularClass>
)
@@ -70,7 +70,7 @@ open class FirBodyResolveTransformer(
typeRef,
ScopeClassDeclaration(
components.createCurrentScopeList(),
context.topClassDeclaration
context.containingClassDeclarations
)
)
}
@@ -37,7 +37,9 @@ fun <F : FirClassLikeDeclaration> F.runAllPhasesForLocalClass(
components.scopeSession,
components.createCurrentScopeList(),
localClassesNavigationInfo,
firProviderInterceptor
firProviderInterceptor,
components.file,
components.containingDeclarations,
)
runTypeResolvePhaseForLocalClass(
components.session,
@@ -115,7 +115,7 @@ private class FirAnnotationResolveTransformer(
): FirStatement {
return annotation.transformAnnotationTypeRef(
typeResolverTransformer,
ScopeClassDeclaration(scopes, classDeclarationsStack.lastOrNull())
ScopeClassDeclaration(scopes, classDeclarationsStack)
)
}
@@ -14,5 +14,5 @@ package p1
import p2.*
val <!EXPOSED_PROPERTY_TYPE!>x<!>: X = <!INITIALIZER_TYPE_MISMATCH, TYPE_MISMATCH!>X()<!>
val x: X = X()
val <!EXPOSED_PROPERTY_TYPE!>y<!>: Y = <!INVISIBLE_REFERENCE!>Y<!>()
@@ -0,0 +1,30 @@
// FIR_IDENTICAL
// MODULE: m1
// FILE: f11.kt
package api
interface ApplicabilityResult
// FILE: f12.kt
package api
interface ArgumentMapping {
fun highlightingApplicabilities(): ApplicabilityResult
}
// MODULE: m2(m1)
// FILE: f21.kt
package impl
private data class ApplicabilityResult(val applicable: Boolean)
// FILE: f22.kt
package impl
import api.*
class NullArgumentMapping : ArgumentMapping {
// This is api.ApplicabilityResult
override fun highlightingApplicabilities(): ApplicabilityResult = object : ApplicabilityResult {
}
}
@@ -0,0 +1,43 @@
// -- Module: <m1> --
package
package api {
public interface ApplicabilityResult {
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 interface ArgumentMapping {
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 abstract fun highlightingApplicabilities(): api.ApplicabilityResult
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
// -- Module: <m2> --
package
package impl {
private final data class ApplicabilityResult {
public constructor ApplicabilityResult(/*0*/ applicable: kotlin.Boolean)
public final val applicable: kotlin.Boolean
public final operator /*synthesized*/ fun component1(): kotlin.Boolean
public final /*synthesized*/ fun copy(/*0*/ applicable: kotlin.Boolean = ...): impl.ApplicabilityResult
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
public final class NullArgumentMapping : api.ArgumentMapping {
public constructor NullArgumentMapping()
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*/ fun highlightingApplicabilities(): api.ApplicabilityResult
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -10,6 +10,6 @@ package kotlin.sequences
import p.*
interface I {
val v1: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>FilteringSequence<!>
val v1: FilteringSequence
val <!EXPOSED_PROPERTY_TYPE!>v2<!>: IndexingSequence<String>
}
@@ -12483,6 +12483,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt");
}
@Test
@TestMetadata("InaccessiblePrivateInFile.kt")
public void testInaccessiblePrivateInFile() throws Exception {
runTest("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateInFile.kt");
}
@Test
@TestMetadata("invisibleFakeReferenceInImport.kt")
public void testInvisibleFakeReferenceInImport() throws Exception {