[FIR] Abstract away symbol.fir in FirImportsChecker
It's easier to reason about correctness of `symbol.fir` when it's localized in small helper functions.
This commit is contained in:
committed by
Space Team
parent
52d712e110
commit
965d8d2fd5
+18
-22
@@ -19,10 +19,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.toInvisibleReferenceDiagnos
|
|||||||
import org.jetbrains.kotlin.fir.analysis.getLastImportedFqNameSegmentSource
|
import org.jetbrains.kotlin.fir.analysis.getLastImportedFqNameSegmentSource
|
||||||
import org.jetbrains.kotlin.fir.analysis.getSourceForImportSegment
|
import org.jetbrains.kotlin.fir.analysis.getSourceForImportSegment
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
|
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
|
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
@@ -31,7 +28,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.PackageResolutionResult
|
|||||||
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
|
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.visibilityChecker
|
import org.jetbrains.kotlin.fir.visibilityChecker
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
@@ -39,7 +36,6 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.filterIsInstanceWithChecker
|
import org.jetbrains.kotlin.utils.addToStdlib.filterIsInstanceWithChecker
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
|
||||||
object FirImportsChecker : FirFileChecker() {
|
object FirImportsChecker : FirFileChecker() {
|
||||||
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
declaration.imports.forEach { import ->
|
declaration.imports.forEach { import ->
|
||||||
@@ -83,7 +79,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
if (classSymbol != null && classSymbol.classKind.isObject) {
|
if (classSymbol != null && classSymbol.classKind.isObject) {
|
||||||
reporter.reportOn(import.source, FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, classSymbol.classId.shortClassName, context)
|
reporter.reportOn(import.source, FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, classSymbol.classId.shortClassName, context)
|
||||||
}
|
}
|
||||||
if (!classLike.fir.isVisible(context)) {
|
if (!classLike.isVisible(context)) {
|
||||||
val source = import.getLastImportedFqNameSegmentSource() ?: error("`${import.source}` does not contain `$fqName`")
|
val source = import.getLastImportedFqNameSegmentSource() ?: error("`${import.source}` does not contain `$fqName`")
|
||||||
reporter.report(classLike.toInvisibleReferenceDiagnostic(source), context)
|
reporter.report(classLike.toInvisibleReferenceDiagnostic(source), context)
|
||||||
}
|
}
|
||||||
@@ -101,7 +97,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
val parentClassSymbol = parentClassId.resolveToClass(context) ?: return
|
val parentClassSymbol = parentClassId.resolveToClass(context) ?: return
|
||||||
|
|
||||||
fun reportInvisibleParentClasses(classSymbol: FirRegularClassSymbol, depth: Int) {
|
fun reportInvisibleParentClasses(classSymbol: FirRegularClassSymbol, depth: Int) {
|
||||||
if (!classSymbol.fir.isVisible(context)) {
|
if (!classSymbol.isVisible(context)) {
|
||||||
val source = import.getSourceForImportSegment(indexFromLast = depth)
|
val source = import.getSourceForImportSegment(indexFromLast = depth)
|
||||||
reporter.report(classSymbol.toInvisibleReferenceDiagnostic(source), context)
|
reporter.report(classSymbol.toInvisibleReferenceDiagnostic(source), context)
|
||||||
}
|
}
|
||||||
@@ -130,12 +126,12 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolvedDeclaration: FirMemberDeclaration? = null
|
var resolvedDeclaration: FirBasedSymbol<*>? = null
|
||||||
|
|
||||||
ClassId.topLevel(importedFqName).resolveToClass(context)?.let {
|
ClassId.topLevel(importedFqName).resolveToClass(context)?.let {
|
||||||
resolvedDeclaration = it.fir
|
resolvedDeclaration = it
|
||||||
|
|
||||||
if (it.fir.isVisible(context)) {
|
if (it.isVisible(context)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,18 +141,18 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
val topLevelCallableSymbol = symbolProvider.getTopLevelCallableSymbols(importedFqName.parent(), importedName)
|
val topLevelCallableSymbol = symbolProvider.getTopLevelCallableSymbols(importedFqName.parent(), importedName)
|
||||||
|
|
||||||
for (it in topLevelCallableSymbol) {
|
for (it in topLevelCallableSymbol) {
|
||||||
if (it.fir.isVisible(context)) {
|
if (it.isVisible(context)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolvedDeclaration == null) {
|
if (resolvedDeclaration == null) {
|
||||||
resolvedDeclaration = it.fir
|
resolvedDeclaration = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedDeclaration?.let {
|
resolvedDeclaration?.let {
|
||||||
val source = import.getSourceForImportSegment(0) ?: import.source
|
val source = import.getSourceForImportSegment(0) ?: import.source
|
||||||
reporter.report(it.symbol.toInvisibleReferenceDiagnostic(source), context)
|
reporter.report(it.toInvisibleReferenceDiagnostic(source), context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,18 +163,18 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirMemberDeclaration.isVisible(context: CheckerContext): Boolean {
|
private fun FirBasedSymbol<*>.isVisible(context: CheckerContext): Boolean {
|
||||||
val useSiteFile = context.containingFile ?: return false
|
val useSiteFile = context.containingFile ?: return false
|
||||||
|
val fir = asMemberDeclarationResolvedTo(FirResolvePhase.STATUS) ?: return false
|
||||||
val visibility = visibility
|
val visibility = fir.visibility
|
||||||
|
|
||||||
if (visibility != Visibilities.Unknown && !visibility.mustCheckInImports()) return true
|
if (visibility != Visibilities.Unknown && !visibility.mustCheckInImports()) return true
|
||||||
if (visibility == Visibilities.Private || visibility == Visibilities.PrivateToThis) {
|
if (visibility == Visibilities.Private || visibility == Visibilities.PrivateToThis) {
|
||||||
return useSiteFile == context.session.firProvider.getContainingFile(symbol)
|
return useSiteFile == context.session.firProvider.getContainingFile(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.session.visibilityChecker.isVisible(
|
return context.session.visibilityChecker.isVisible(
|
||||||
this,
|
fir,
|
||||||
context.session,
|
context.session,
|
||||||
useSiteFile,
|
useSiteFile,
|
||||||
emptyList(),
|
emptyList(),
|
||||||
@@ -283,7 +279,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
|
|
||||||
// Next, we try static scope, which can provide static (Java) members from super classes. Note that it's not available
|
// Next, we try static scope, which can provide static (Java) members from super classes. Note that it's not available
|
||||||
// for pure Kotlin classes.
|
// for pure Kotlin classes.
|
||||||
fir.staticScope(context.sessionHolder),
|
staticScope(context.sessionHolder),
|
||||||
|
|
||||||
// Finally, we fall back to unsubstitutedScope to catch all
|
// Finally, we fall back to unsubstitutedScope to catch all
|
||||||
unsubstitutedScope(context)
|
unsubstitutedScope(context)
|
||||||
@@ -303,13 +299,13 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
|
|
||||||
for (scope in scopes) {
|
for (scope in scopes) {
|
||||||
scope.processFunctionsByName(name) { sym ->
|
scope.processFunctionsByName(name) { sym ->
|
||||||
if (sym.fir.isVisible(context) && isApplicable(sym)) found = true
|
if (sym.isVisible(context) && isApplicable(sym)) found = true
|
||||||
symbol = sym
|
symbol = sym
|
||||||
}
|
}
|
||||||
if (found) return ImportStatus.OK
|
if (found) return ImportStatus.OK
|
||||||
|
|
||||||
scope.processPropertiesByName(name) { sym ->
|
scope.processPropertiesByName(name) { sym ->
|
||||||
if (sym.fir.isVisible(context) && isApplicable(sym)) found = true
|
if (sym.isVisible(context) && isApplicable(sym)) found = true
|
||||||
symbol = sym
|
symbol = sym
|
||||||
}
|
}
|
||||||
if (found) return ImportStatus.OK
|
if (found) return ImportStatus.OK
|
||||||
|
|||||||
+4
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
|
|||||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
|
import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
@@ -303,6 +304,9 @@ fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement =
|
|||||||
fun FirScope.asTowerDataElementForStaticScope(staticScopeOwnerSymbol: FirRegularClassSymbol?): FirTowerDataElement =
|
fun FirScope.asTowerDataElementForStaticScope(staticScopeOwnerSymbol: FirRegularClassSymbol?): FirTowerDataElement =
|
||||||
FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = false, staticScopeOwnerSymbol = staticScopeOwnerSymbol)
|
FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = false, staticScopeOwnerSymbol = staticScopeOwnerSymbol)
|
||||||
|
|
||||||
|
fun FirClassSymbol<*>.staticScope(sessionHolder: SessionHolder): FirContainingNamesAwareScope? =
|
||||||
|
fir.staticScope(sessionHolder)
|
||||||
|
|
||||||
fun FirClass.staticScope(sessionHolder: SessionHolder): FirContainingNamesAwareScope? =
|
fun FirClass.staticScope(sessionHolder: SessionHolder): FirContainingNamesAwareScope? =
|
||||||
staticScope(sessionHolder.session, sessionHolder.scopeSession)
|
staticScope(sessionHolder.session, sessionHolder.scopeSession)
|
||||||
|
|
||||||
|
|||||||
+7
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.declarations.utils
|
|||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
import org.jetbrains.kotlin.fir.types.isNullableAny
|
import org.jetbrains.kotlin.fir.types.isNullableAny
|
||||||
@@ -59,6 +60,12 @@ val FirMemberDeclaration.nameOrSpecialName: Name
|
|||||||
is FirClassLikeDeclaration -> classId.shortClassName
|
is FirClassLikeDeclaration -> classId.shortClassName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirBasedSymbol<*>.asMemberDeclarationResolvedTo(phase: FirResolvePhase): FirMemberDeclaration? {
|
||||||
|
return (fir as? FirMemberDeclaration)?.also {
|
||||||
|
lazyResolveToPhase(phase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val FirNamedFunctionSymbol.isMethodOfAny: Boolean
|
val FirNamedFunctionSymbol.isMethodOfAny: Boolean
|
||||||
get() {
|
get() {
|
||||||
if (receiverParameter != null) return false
|
if (receiverParameter != null) return false
|
||||||
|
|||||||
Reference in New Issue
Block a user