[FIR] Improve INVISIBLE_REFERENCE message
Report the nearest invisible containing declaration in cases where the declaration itself is visible. #KT-53820 Fixed
This commit is contained in:
committed by
Space Team
parent
6a073e0b17
commit
911e62257a
+2
@@ -256,6 +256,8 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic ->
|
add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic ->
|
||||||
InvisibleReferenceImpl(
|
InvisibleReferenceImpl(
|
||||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||||
|
firDiagnostic.b,
|
||||||
|
firDiagnostic.c,
|
||||||
firDiagnostic as KtPsiDiagnostic,
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
|
|||||||
+2
@@ -220,6 +220,8 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
interface InvisibleReference : KtFirDiagnostic<PsiElement> {
|
interface InvisibleReference : KtFirDiagnostic<PsiElement> {
|
||||||
override val diagnosticClass get() = InvisibleReference::class
|
override val diagnosticClass get() = InvisibleReference::class
|
||||||
val reference: KtSymbol
|
val reference: KtSymbol
|
||||||
|
val visible: Visibility
|
||||||
|
val containingDeclaration: ClassId?
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UnresolvedReference : KtFirDiagnostic<PsiElement> {
|
interface UnresolvedReference : KtFirDiagnostic<PsiElement> {
|
||||||
|
|||||||
+2
@@ -248,6 +248,8 @@ internal class InvisibleSetterImpl(
|
|||||||
|
|
||||||
internal class InvisibleReferenceImpl(
|
internal class InvisibleReferenceImpl(
|
||||||
override val reference: KtSymbol,
|
override val reference: KtSymbol,
|
||||||
|
override val visible: Visibility,
|
||||||
|
override val containingDeclaration: ClassId?,
|
||||||
firDiagnostic: KtPsiDiagnostic,
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InvisibleReference
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InvisibleReference
|
||||||
|
|||||||
+1
-1
@@ -17,4 +17,4 @@ KtErrorCallInfo:
|
|||||||
typeArgumentsMapping = {}
|
typeArgumentsMapping = {}
|
||||||
argumentMapping = {}
|
argumentMapping = {}
|
||||||
]
|
]
|
||||||
diagnostic = ERROR<INVISIBLE_REFERENCE: Symbol fun foo(): Unit is invisible>
|
diagnostic = ERROR<INVISIBLE_REFERENCE: Cannot access 'fun foo(): Unit': it is private in '/A'>
|
||||||
+1
-1
@@ -16,7 +16,7 @@ KtInapplicableCallCandidateInfo:
|
|||||||
isInBestCandidates = false
|
isInBestCandidates = false
|
||||||
|
|
||||||
KtInapplicableCallCandidateInfo:
|
KtInapplicableCallCandidateInfo:
|
||||||
diagnostic = ERROR<INVISIBLE_REFERENCE: Symbol constructor(p: String): A is invisible>
|
diagnostic = ERROR<INVISIBLE_REFERENCE: Cannot access 'constructor(p: String): A': it is private in '/A'>
|
||||||
candidate = KtDelegatedConstructorCall:
|
candidate = KtDelegatedConstructorCall:
|
||||||
kind = SUPER_CALL
|
kind = SUPER_CALL
|
||||||
partiallyAppliedSymbol = KtPartiallyAppliedSymbol:
|
partiallyAppliedSymbol = KtPartiallyAppliedSymbol:
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
KtInapplicableCallCandidateInfo:
|
KtInapplicableCallCandidateInfo:
|
||||||
diagnostic = ERROR<INVISIBLE_REFERENCE: Symbol fun foo(): Unit is invisible>
|
diagnostic = ERROR<INVISIBLE_REFERENCE: Cannot access 'fun foo(): Unit': it is private in '/A'>
|
||||||
candidate = KtSimpleFunctionCall:
|
candidate = KtSimpleFunctionCall:
|
||||||
isImplicitInvoke = false
|
isImplicitInvoke = false
|
||||||
partiallyAppliedSymbol = KtPartiallyAppliedSymbol:
|
partiallyAppliedSymbol = KtPartiallyAppliedSymbol:
|
||||||
|
|||||||
+3
-3
@@ -53,7 +53,7 @@ FILE: nestedVisibility.kt
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final fun foo(): R|kotlin/Unit| {
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
Q|Outer|.R|/Outer.PrivateNested.PrivateNested<HIDDEN: /Outer.PrivateNested.PrivateNested is invisible>#|()
|
Q|Outer|.R|/Outer.PrivateNested.PrivateNested<HIDDEN: Outer.PrivateNested is invisible>#|()
|
||||||
this@R|/Derived|.super<R|Outer|>.R|/Outer.PrivateInner.PrivateInner<HIDDEN: /Outer.PrivateInner.PrivateInner is invisible>#|()
|
this@R|/Derived|.super<R|Outer|>.R|/Outer.PrivateInner.PrivateInner<HIDDEN: /Outer.PrivateInner.PrivateInner is invisible>#|()
|
||||||
Q|Outer|.R|/Outer.ProtectedNested.ProtectedNested|()
|
Q|Outer|.R|/Outer.ProtectedNested.ProtectedNested|()
|
||||||
this@R|/Derived|.super<R|Outer|>.R|/Outer.ProtectedInner.ProtectedInner|()
|
this@R|/Derived|.super<R|Outer|>.R|/Outer.ProtectedInner.ProtectedInner|()
|
||||||
@@ -63,9 +63,9 @@ FILE: nestedVisibility.kt
|
|||||||
|
|
||||||
}
|
}
|
||||||
public final fun foo(): R|kotlin/Unit| {
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
Q|Outer|.R|/Outer.PrivateNested.PrivateNested<HIDDEN: /Outer.PrivateNested.PrivateNested is invisible>#|()
|
Q|Outer|.R|/Outer.PrivateNested.PrivateNested<HIDDEN: Outer.PrivateNested is invisible>#|()
|
||||||
R|/Outer.Outer|().R|/Outer.PrivateInner.PrivateInner<HIDDEN: /Outer.PrivateInner.PrivateInner is invisible>#|()
|
R|/Outer.Outer|().R|/Outer.PrivateInner.PrivateInner<HIDDEN: /Outer.PrivateInner.PrivateInner is invisible>#|()
|
||||||
Q|Outer|.R|/Outer.ProtectedNested.ProtectedNested<HIDDEN: /Outer.ProtectedNested.ProtectedNested is invisible>#|()
|
Q|Outer|.R|/Outer.ProtectedNested.ProtectedNested<HIDDEN: Outer.ProtectedNested is invisible>#|()
|
||||||
R|/Outer.Outer|().R|/Outer.ProtectedInner.ProtectedInner<HIDDEN: /Outer.ProtectedInner.ProtectedInner is invisible>#|()
|
R|/Outer.Outer|().R|/Outer.ProtectedInner.ProtectedInner<HIDDEN: /Outer.ProtectedInner.ProtectedInner is invisible>#|()
|
||||||
Q|Outer|.R|/Outer.PublicNested.PublicNested|()
|
Q|Outer|.R|/Outer.PublicNested.PublicNested|()
|
||||||
R|/Outer.Outer|().R|/Outer.PublicInner.PublicInner|()
|
R|/Outer.Outer|().R|/Outer.PublicInner.PublicInner|()
|
||||||
|
|||||||
+2
-2
@@ -96,11 +96,11 @@ FILE: first.kt
|
|||||||
R|/Private.Private|().R|/Private.baz|()
|
R|/Private.Private|().R|/Private.baz|()
|
||||||
R|/Private.Private|().R|/Private.Inner.Inner|()
|
R|/Private.Private|().R|/Private.Inner.Inner|()
|
||||||
R|/Private.Private|().R|/Private.bar<HIDDEN: /Private.bar is invisible>#|()
|
R|/Private.Private|().R|/Private.bar<HIDDEN: /Private.bar is invisible>#|()
|
||||||
Q|Private|.R|/Private.Nested.Nested<HIDDEN: /Private.Nested.Nested is invisible>#|()
|
Q|Private|.R|/Private.Nested.Nested<HIDDEN: Private.Nested is invisible>#|()
|
||||||
Q|Private|.R|/Private.Companion.fromCompanion<HIDDEN: /Private.Companion.fromCompanion is invisible>#|()
|
Q|Private|.R|/Private.Companion.fromCompanion<HIDDEN: /Private.Companion.fromCompanion is invisible>#|()
|
||||||
}
|
}
|
||||||
FILE: second.kt
|
FILE: second.kt
|
||||||
public final fun secondTest(): R|kotlin/Unit| {
|
public final fun secondTest(): R|kotlin/Unit| {
|
||||||
R|/foo<HIDDEN: /foo is invisible>#|()
|
R|/foo<HIDDEN: /foo is invisible>#|()
|
||||||
R|/Private.Private<HIDDEN: /Private.Private is invisible>#|()
|
R|/Private.Private<HIDDEN: Private is invisible>#|()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ FILE: protectedVisibility.kt
|
|||||||
R|/Protected.Protected|().R|/Protected.baz|()
|
R|/Protected.Protected|().R|/Protected.baz|()
|
||||||
R|/Protected.Protected|().R|/Protected.Inner.Inner|()
|
R|/Protected.Protected|().R|/Protected.Inner.Inner|()
|
||||||
R|/Protected.Protected|().R|/Protected.bar<HIDDEN: /Protected.bar is invisible>#|()
|
R|/Protected.Protected|().R|/Protected.bar<HIDDEN: /Protected.bar is invisible>#|()
|
||||||
Q|Protected|.R|/Protected.Nested.Nested<HIDDEN: /Protected.Nested.Nested is invisible>#|()
|
Q|Protected|.R|/Protected.Nested.Nested<HIDDEN: Protected.Nested is invisible>#|()
|
||||||
}
|
}
|
||||||
public open class Generic<T> : R|kotlin/Any| {
|
public open class Generic<T> : R|kotlin/Any| {
|
||||||
public constructor<T>(x: R|T|): R|Generic<T>| {
|
public constructor<T>(x: R|T|): R|Generic<T>| {
|
||||||
|
|||||||
+3
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|||||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -103,6 +104,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
||||||
val INVISIBLE_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
val INVISIBLE_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||||
parameter<Symbol>("reference")
|
parameter<Symbol>("reference")
|
||||||
|
parameter<Visibility>("visible")
|
||||||
|
parameter<ClassId?>("containingDeclaration")
|
||||||
}
|
}
|
||||||
val UNRESOLVED_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
val UNRESOLVED_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||||
parameter<String>("reference")
|
parameter<String>("reference")
|
||||||
|
|||||||
+2
-1
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|||||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||||
@@ -147,7 +148,7 @@ object FirErrors {
|
|||||||
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||||
|
|
||||||
// Unresolved
|
// Unresolved
|
||||||
val INVISIBLE_REFERENCE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val INVISIBLE_REFERENCE by error3<PsiElement, FirBasedSymbol<*>, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
val UNRESOLVED_REFERENCE by error1<PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
val UNRESOLVED_REFERENCE by error1<PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
val UNRESOLVED_LABEL by error0<PsiElement>(SourceElementPositioningStrategies.LABEL)
|
val UNRESOLVED_LABEL by error0<PsiElement>(SourceElementPositioningStrategies.LABEL)
|
||||||
val DESERIALIZATION_ERROR by error0<PsiElement>()
|
val DESERIALIZATION_ERROR by error0<PsiElement>()
|
||||||
|
|||||||
+2
-6
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
|||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.toInvisibleReferenceDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
@@ -176,12 +177,7 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ConeVisibilityError -> {
|
is ConeVisibilityError -> {
|
||||||
reporter.reportOn(
|
reporter.report(diagnostic.symbol.toInvisibleReferenceDiagnostic(property.source), context)
|
||||||
property.source,
|
|
||||||
FirErrors.INVISIBLE_REFERENCE,
|
|
||||||
diagnostic.symbol,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
else -> error("Unhandled error during a component function call")
|
else -> error("Unhandled error during a component function call")
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
|||||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.toInvisibleReferenceDiagnostic
|
||||||
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.isEnumClass
|
||||||
@@ -75,7 +76,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
fun reportInvisibleParentClasses(classSymbol: FirRegularClassSymbol, depth: Int) {
|
fun reportInvisibleParentClasses(classSymbol: FirRegularClassSymbol, depth: Int) {
|
||||||
if (!classSymbol.fir.isVisible(context)) {
|
if (!classSymbol.fir.isVisible(context)) {
|
||||||
val source = import.getSourceForImportSegment(indexFromLast = depth)
|
val source = import.getSourceForImportSegment(indexFromLast = depth)
|
||||||
reporter.reportOn(source, FirErrors.INVISIBLE_REFERENCE, classSymbol, context)
|
reporter.report(classSymbol.toInvisibleReferenceDiagnostic(source), context)
|
||||||
}
|
}
|
||||||
|
|
||||||
classSymbol.classId.outerClassId?.resolveToClass(context)?.let { reportInvisibleParentClasses(it, depth + 1) }
|
classSymbol.classId.outerClassId?.resolveToClass(context)?.let { reportInvisibleParentClasses(it, depth + 1) }
|
||||||
@@ -87,7 +88,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
ImportStatus.OK -> return
|
ImportStatus.OK -> return
|
||||||
is ImportStatus.Invisible -> {
|
is ImportStatus.Invisible -> {
|
||||||
val source = import.getSourceForImportSegment(0)
|
val source = import.getSourceForImportSegment(0)
|
||||||
reporter.reportOn(source, FirErrors.INVISIBLE_REFERENCE, status.symbol, context)
|
reporter.report(status.symbol.toInvisibleReferenceDiagnostic(source), context)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val classId = parentClassSymbol.classId.createNestedClassId(importedName)
|
val classId = parentClassSymbol.classId.createNestedClassId(importedName)
|
||||||
@@ -128,7 +129,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
|
|
||||||
resolvedDeclaration?.let {
|
resolvedDeclaration?.let {
|
||||||
val source = import.getSourceForImportSegment(0) ?: import.source
|
val source = import.getSourceForImportSegment(0) ?: import.source
|
||||||
reporter.reportOn(source, FirErrors.INVISIBLE_REFERENCE, it.symbol, context)
|
reporter.report(it.symbol.toInvisibleReferenceDiagnostic(source), context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -6,10 +6,9 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.toInvisibleReferenceDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirErrorResolvedQualifier
|
import org.jetbrains.kotlin.fir.expressions.FirErrorResolvedQualifier
|
||||||
@@ -45,7 +44,7 @@ object FirVisibilityQualifierChecker : FirResolvedQualifierChecker() {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (expression !is FirErrorResolvedQualifier || expression.diagnostic !is ConeVisibilityError) {
|
if (expression !is FirErrorResolvedQualifier || expression.diagnostic !is ConeVisibilityError) {
|
||||||
reporter.reportOn(expression.source, FirErrors.INVISIBLE_REFERENCE, symbol, context)
|
reporter.report(symbol.toInvisibleReferenceDiagnostic(expression.source), context)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
+5
-1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
|
|||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.renderReadableWithFqNames
|
import org.jetbrains.kotlin.fir.types.renderReadableWithFqNames
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
object FirDiagnosticRenderers {
|
object FirDiagnosticRenderers {
|
||||||
@OptIn(SymbolInternals::class)
|
@OptIn(SymbolInternals::class)
|
||||||
@@ -148,7 +149,10 @@ object FirDiagnosticRenderers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer { symbol: CallableId ->
|
val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer { symbol: CallableId ->
|
||||||
val classId = symbol.classId
|
NAME_OF_DECLARATION_OR_FILE.render(symbol.classId)
|
||||||
|
}
|
||||||
|
|
||||||
|
val NAME_OF_DECLARATION_OR_FILE = Renderer { classId: ClassId? ->
|
||||||
if (classId == null) {
|
if (classId == null) {
|
||||||
"file"
|
"file"
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-1
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNC
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS_ON_NEWLINE_WITH_INDENT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS_ON_NEWLINE_WITH_INDENT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.MODULE_DATA
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.MODULE_DATA
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME_OF_CONTAINING_DECLARATION_OR_FILE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME_OF_CONTAINING_DECLARATION_OR_FILE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME_OF_DECLARATION_OR_FILE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_COLLECTION_OF_TYPES
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_COLLECTION_OF_TYPES
|
||||||
@@ -704,7 +705,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
map.put(NULL_FOR_NONNULL_TYPE, "Null can not be a value of a non-null type")
|
map.put(NULL_FOR_NONNULL_TYPE, "Null can not be a value of a non-null type")
|
||||||
|
|
||||||
// Unresolved
|
// Unresolved
|
||||||
map.put(INVISIBLE_REFERENCE, "Symbol {0} is invisible", SYMBOL)
|
map.put(INVISIBLE_REFERENCE, "Cannot access ''{0}'': it is {1} in {2}", SYMBOL, VISIBILITY, NAME_OF_DECLARATION_OR_FILE)
|
||||||
map.put(
|
map.put(
|
||||||
INVISIBLE_SETTER,
|
INVISIBLE_SETTER,
|
||||||
"Cannot access ''{0}'': it is {1} in {2}",
|
"Cannot access ''{0}'': it is {1} in {2}",
|
||||||
|
|||||||
+10
-1
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.isInfix
|
import org.jetbrains.kotlin.fir.declarations.utils.isInfix
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
|
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
@@ -27,6 +28,7 @@ import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPo
|
|||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExpectedTypeConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExpectedTypeConstraintPosition
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
@@ -40,6 +42,7 @@ import org.jetbrains.kotlin.types.EmptyIntersectionTypeKind
|
|||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
||||||
|
|
||||||
private fun ConeDiagnostic.toKtDiagnostic(
|
private fun ConeDiagnostic.toKtDiagnostic(
|
||||||
source: KtSourceElement,
|
source: KtSourceElement,
|
||||||
@@ -73,7 +76,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is ConeVisibilityError -> FirErrors.INVISIBLE_REFERENCE.createOn(source, this.symbol)
|
is ConeVisibilityError -> symbol.toInvisibleReferenceDiagnostic(source)
|
||||||
is ConeInapplicableWrongReceiver -> FirErrors.UNRESOLVED_REFERENCE_WRONG_RECEIVER.createOn(source, this.candidateSymbols)
|
is ConeInapplicableWrongReceiver -> FirErrors.UNRESOLVED_REFERENCE_WRONG_RECEIVER.createOn(source, this.candidateSymbols)
|
||||||
is ConeNoCompanionObject -> FirErrors.NO_COMPANION_OBJECT.createOn(source, this.candidateSymbol as FirClassLikeSymbol<*>)
|
is ConeNoCompanionObject -> FirErrors.NO_COMPANION_OBJECT.createOn(source, this.candidateSymbol as FirClassLikeSymbol<*>)
|
||||||
is ConeAmbiguityError -> when {
|
is ConeAmbiguityError -> when {
|
||||||
@@ -150,6 +153,12 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
|||||||
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirBasedSymbol<*>.toInvisibleReferenceDiagnostic(source: KtSourceElement?): KtDiagnostic? = when (val symbol = this) {
|
||||||
|
is FirCallableSymbol<*> -> FirErrors.INVISIBLE_REFERENCE.createOn(source, symbol, symbol.visibility, symbol.callableId.classId)
|
||||||
|
is FirClassLikeSymbol<*> -> FirErrors.INVISIBLE_REFERENCE.createOn(source, symbol, symbol.visibility, symbol.classId.outerClassId)
|
||||||
|
else -> shouldNotBeCalled("Unexpected receiver $javaClass")
|
||||||
|
}
|
||||||
|
|
||||||
fun ConeDiagnostic.toFirDiagnostics(
|
fun ConeDiagnostic.toFirDiagnostics(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
source: KtSourceElement,
|
source: KtSourceElement,
|
||||||
|
|||||||
@@ -130,13 +130,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
supertypeSupplier
|
supertypeSupplier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val parentClass = declaration.containingNonLocalClass(
|
return declaration.parentDeclarationSequence(session, dispatchReceiver, containingDeclarations, supertypeSupplier)?.all { parent ->
|
||||||
session,
|
|
||||||
dispatchReceiver,
|
|
||||||
containingDeclarations,
|
|
||||||
supertypeSupplier
|
|
||||||
) ?: return true
|
|
||||||
return generateSequence(parentClass) { it.containingNonLocalClass(session) }.all { parent ->
|
|
||||||
isSpecificDeclarationVisible(
|
isSpecificDeclarationVisible(
|
||||||
parent,
|
parent,
|
||||||
session,
|
session,
|
||||||
@@ -146,7 +140,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
isCallToPropertySetter,
|
isCallToPropertySetter,
|
||||||
supertypeSupplier
|
supertypeSupplier
|
||||||
)
|
)
|
||||||
}
|
} ?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isVisibleForOverriding(
|
fun isVisibleForOverriding(
|
||||||
@@ -169,51 +163,6 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
else -> platformOverrideVisibilityCheck(symbolFromDerivedClass, candidateInBaseClass.symbol, candidateInBaseClass.visibility)
|
else -> platformOverrideVisibilityCheck(symbolFromDerivedClass, candidateInBaseClass.symbol, candidateInBaseClass.visibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirMemberDeclaration.containingNonLocalClass(
|
|
||||||
session: FirSession,
|
|
||||||
dispatchReceiver: FirExpression?,
|
|
||||||
containingUseSiteDeclarations: List<FirDeclaration>,
|
|
||||||
supertypeSupplier: SupertypeSupplier
|
|
||||||
): FirClassLikeDeclaration? {
|
|
||||||
return when (this) {
|
|
||||||
is FirCallableDeclaration -> {
|
|
||||||
if (dispatchReceiver != null) {
|
|
||||||
val baseReceiverType = dispatchReceiverClassTypeOrNull()
|
|
||||||
if (baseReceiverType != null) {
|
|
||||||
dispatchReceiver.typeRef.coneType.findClassRepresentation(baseReceiverType, session)?.toSymbol(session)?.fir?.let {
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val containingLookupTag = this.containingClassLookupTag()
|
|
||||||
val containingClass = containingLookupTag?.toSymbol(session)?.fir
|
|
||||||
|
|
||||||
if (isStatic && containingClass != null) {
|
|
||||||
containingUseSiteDeclarations.firstNotNullOfOrNull {
|
|
||||||
if (it !is FirClass) return@firstNotNullOfOrNull null
|
|
||||||
it.takeIf { it.isSubclassOf(containingLookupTag, session, isStrict = false, supertypeSupplier) }
|
|
||||||
}?.let { return it }
|
|
||||||
}
|
|
||||||
|
|
||||||
containingClass
|
|
||||||
}
|
|
||||||
is FirClassLikeDeclaration -> containingNonLocalClass(session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirClassLikeDeclaration.containingNonLocalClass(session: FirSession): FirClassLikeDeclaration? {
|
|
||||||
return when (this) {
|
|
||||||
is FirClass -> {
|
|
||||||
if (isLocal) return null
|
|
||||||
|
|
||||||
this.classId.outerClassId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it)?.fir }
|
|
||||||
}
|
|
||||||
// Currently, type aliases are only top-level
|
|
||||||
is FirTypeAlias -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSpecificDeclarationVisible(
|
private fun isSpecificDeclarationVisible(
|
||||||
declaration: FirMemberDeclaration,
|
declaration: FirMemberDeclaration,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
@@ -521,3 +470,65 @@ fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
|
|||||||
fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean {
|
fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean {
|
||||||
return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol
|
return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun FirMemberDeclaration.parentDeclarationSequence(
|
||||||
|
session: FirSession,
|
||||||
|
dispatchReceiver: FirExpression?,
|
||||||
|
containingDeclarations: List<FirDeclaration>,
|
||||||
|
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default,
|
||||||
|
): Sequence<FirClassLikeDeclaration>? {
|
||||||
|
val parentClass = containingNonLocalClass(
|
||||||
|
session,
|
||||||
|
dispatchReceiver,
|
||||||
|
containingDeclarations,
|
||||||
|
supertypeSupplier
|
||||||
|
) ?: return null
|
||||||
|
|
||||||
|
return generateSequence(parentClass) { it.containingNonLocalClass(session) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirMemberDeclaration.containingNonLocalClass(
|
||||||
|
session: FirSession,
|
||||||
|
dispatchReceiver: FirExpression?,
|
||||||
|
containingUseSiteDeclarations: List<FirDeclaration>,
|
||||||
|
supertypeSupplier: SupertypeSupplier
|
||||||
|
): FirClassLikeDeclaration? {
|
||||||
|
return when (this) {
|
||||||
|
is FirCallableDeclaration -> {
|
||||||
|
if (dispatchReceiver != null) {
|
||||||
|
val baseReceiverType = dispatchReceiverClassTypeOrNull()
|
||||||
|
if (baseReceiverType != null) {
|
||||||
|
dispatchReceiver.typeRef.coneType.findClassRepresentation(baseReceiverType, session)?.toSymbol(session)?.fir?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val containingLookupTag = this.containingClassLookupTag()
|
||||||
|
val containingClass = containingLookupTag?.toSymbol(session)?.fir
|
||||||
|
|
||||||
|
if (isStatic && containingClass != null) {
|
||||||
|
containingUseSiteDeclarations.firstNotNullOfOrNull {
|
||||||
|
if (it !is FirClass) return@firstNotNullOfOrNull null
|
||||||
|
it.takeIf { it.isSubclassOf(containingLookupTag, session, isStrict = false, supertypeSupplier) }
|
||||||
|
}?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
containingClass
|
||||||
|
}
|
||||||
|
is FirClassLikeDeclaration -> containingNonLocalClass(session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirClassLikeDeclaration.containingNonLocalClass(session: FirSession): FirClassLikeDeclaration? {
|
||||||
|
return when (this) {
|
||||||
|
is FirClass -> {
|
||||||
|
if (isLocal) return null
|
||||||
|
|
||||||
|
this.classId.outerClassId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it)?.fir }
|
||||||
|
}
|
||||||
|
// Currently, type aliases are only top-level
|
||||||
|
is FirTypeAlias -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
|
|||||||
import org.jetbrains.kotlin.fir.references.*
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedErrorReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedErrorReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
@@ -193,7 +190,7 @@ fun BodyResolveComponents.buildResolvedQualifierForClass(
|
|||||||
typeArgumentsForQualifier: List<FirTypeProjection> = emptyList(),
|
typeArgumentsForQualifier: List<FirTypeProjection> = emptyList(),
|
||||||
diagnostic: ConeDiagnostic? = null,
|
diagnostic: ConeDiagnostic? = null,
|
||||||
nonFatalDiagnostics: List<ConeDiagnostic> = emptyList(),
|
nonFatalDiagnostics: List<ConeDiagnostic> = emptyList(),
|
||||||
annotations: List<FirAnnotation> = emptyList()
|
annotations: List<FirAnnotation> = emptyList(),
|
||||||
): FirResolvedQualifier {
|
): FirResolvedQualifier {
|
||||||
val classId = regularClass.classId
|
val classId = regularClass.classId
|
||||||
|
|
||||||
@@ -370,7 +367,7 @@ private fun BodyResolveComponents.typeFromSymbol(symbol: FirBasedSymbol<*>, make
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(
|
fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(
|
||||||
qualifiedAccessExpression: FirQualifiedAccessExpression
|
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||||
): FirExpression {
|
): FirExpression {
|
||||||
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression)
|
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression)
|
||||||
?: return qualifiedAccessExpression
|
?: return qualifiedAccessExpression
|
||||||
@@ -379,7 +376,7 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun BodyResolveComponents.transformWhenSubjectExpressionUsingSmartcastInfo(
|
fun BodyResolveComponents.transformWhenSubjectExpressionUsingSmartcastInfo(
|
||||||
whenSubjectExpression: FirWhenSubjectExpression
|
whenSubjectExpression: FirWhenSubjectExpression,
|
||||||
): FirExpression {
|
): FirExpression {
|
||||||
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(whenSubjectExpression)
|
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(whenSubjectExpression)
|
||||||
?: return whenSubjectExpression
|
?: return whenSubjectExpression
|
||||||
@@ -388,7 +385,7 @@ fun BodyResolveComponents.transformWhenSubjectExpressionUsingSmartcastInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun BodyResolveComponents.transformDesugaredAssignmentValueUsingSmartcastInfo(
|
fun BodyResolveComponents.transformDesugaredAssignmentValueUsingSmartcastInfo(
|
||||||
expression: FirDesugaredAssignmentValueReferenceExpression
|
expression: FirDesugaredAssignmentValueReferenceExpression,
|
||||||
): FirExpression {
|
): FirExpression {
|
||||||
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(expression.expressionRef.value)
|
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(expression.expressionRef.value)
|
||||||
?: return expression
|
?: return expression
|
||||||
@@ -410,7 +407,7 @@ private fun FirSmartCastExpressionBuilder.applyResultTypeRef() {
|
|||||||
private fun <T : FirExpression> BodyResolveComponents.transformExpressionUsingSmartcastInfo(
|
private fun <T : FirExpression> BodyResolveComponents.transformExpressionUsingSmartcastInfo(
|
||||||
expression: T,
|
expression: T,
|
||||||
stability: PropertyStability,
|
stability: PropertyStability,
|
||||||
typesFromSmartCast: MutableList<ConeKotlinType>
|
typesFromSmartCast: MutableList<ConeKotlinType>,
|
||||||
): FirSmartCastExpression? {
|
): FirSmartCastExpression? {
|
||||||
val smartcastStability = stability.impliedSmartcastStability
|
val smartcastStability = stability.impliedSmartcastStability
|
||||||
?: if (dataFlowAnalyzer.isAccessToUnstableLocalVariable(expression)) {
|
?: if (dataFlowAnalyzer.isAccessToUnstableLocalVariable(expression)) {
|
||||||
@@ -477,7 +474,7 @@ private fun <T : FirExpression> BodyResolveComponents.transformExpressionUsingSm
|
|||||||
fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(
|
fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(
|
||||||
nullableReceiverExpression: FirExpression,
|
nullableReceiverExpression: FirExpression,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
file: FirFile
|
file: FirFile,
|
||||||
) {
|
) {
|
||||||
// If the receiver expression is smartcast to `null`, it would have `Nothing?` as its type, which may not have members called by user
|
// If the receiver expression is smartcast to `null`, it would have `Nothing?` as its type, which may not have members called by user
|
||||||
// code. Hence, we fallback to the type before intersecting with `Nothing?`.
|
// code. Hence, we fallback to the type before intersecting with `Nothing?`.
|
||||||
@@ -555,7 +552,7 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
// NB: with originScope given this function will try to find overridden declaration with allowed parameter names
|
// NB: with originScope given this function will try to find overridden declaration with allowed parameter names
|
||||||
// for intersection/substitution overrides
|
// for intersection/substitution overrides
|
||||||
originScope: FirTypeScope? = null
|
originScope: FirTypeScope? = null,
|
||||||
): ForbiddenNamedArgumentsTarget? {
|
): ForbiddenNamedArgumentsTarget? {
|
||||||
if (hasStableParameterNames) return null
|
if (hasStableParameterNames) return null
|
||||||
|
|
||||||
@@ -602,11 +599,36 @@ fun FirExpression?.isIntegerLiteralOrOperatorCall(): Boolean {
|
|||||||
|
|
||||||
fun createConeDiagnosticForCandidateWithError(
|
fun createConeDiagnosticForCandidateWithError(
|
||||||
applicability: CandidateApplicability,
|
applicability: CandidateApplicability,
|
||||||
candidate: Candidate
|
candidate: Candidate,
|
||||||
): ConeDiagnostic {
|
): ConeDiagnostic {
|
||||||
return when (applicability) {
|
return when (applicability) {
|
||||||
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate)
|
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate)
|
||||||
CandidateApplicability.K2_VISIBILITY_ERROR -> ConeVisibilityError(candidate.symbol)
|
CandidateApplicability.K2_VISIBILITY_ERROR -> {
|
||||||
|
val session = candidate.callInfo.session
|
||||||
|
val declaration = candidate.symbol.fir
|
||||||
|
if (declaration is FirMemberDeclaration &&
|
||||||
|
session.visibilityChecker.isVisible(declaration, candidate, skipCheckForContainingClassVisibility = true)
|
||||||
|
) {
|
||||||
|
// We can have declarations that are visible by themselves, but some containing declaration is invisible.
|
||||||
|
// We report the nearest invisible containing declaration, otherwise we'll get a confusing diagnostic like
|
||||||
|
// Cannot access 'foo', it is public in 'Bar'.
|
||||||
|
declaration
|
||||||
|
.parentDeclarationSequence(session, candidate.dispatchReceiver, candidate.callInfo.containingDeclarations)
|
||||||
|
?.firstOrNull {
|
||||||
|
!session.visibilityChecker.isVisible(
|
||||||
|
it,
|
||||||
|
session,
|
||||||
|
candidate.callInfo.containingFile,
|
||||||
|
candidate.callInfo.containingDeclarations,
|
||||||
|
dispatchReceiver = null,
|
||||||
|
skipCheckForContainingClassVisibility = true,
|
||||||
|
)
|
||||||
|
}?.let {
|
||||||
|
return ConeVisibilityError(it.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConeVisibilityError(candidate.symbol)
|
||||||
|
}
|
||||||
CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ConeInapplicableWrongReceiver(listOf(candidate))
|
CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ConeInapplicableWrongReceiver(listOf(candidate))
|
||||||
CandidateApplicability.K2_NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate)
|
CandidateApplicability.K2_NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate)
|
||||||
else -> ConeInapplicableCandidateError(applicability, candidate)
|
else -> ConeInapplicableCandidateError(applicability, candidate)
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
|||||||
fun FirVisibilityChecker.isVisible(
|
fun FirVisibilityChecker.isVisible(
|
||||||
declaration: FirMemberDeclaration,
|
declaration: FirMemberDeclaration,
|
||||||
callInfo: CallInfo,
|
callInfo: CallInfo,
|
||||||
dispatchReceiver: FirExpression?
|
dispatchReceiver: FirExpression?,
|
||||||
|
skipCheckForContainingClassVisibility: Boolean = false,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val staticQualifierForCallable = runIf(
|
val staticQualifierForCallable = runIf(
|
||||||
declaration is FirCallableDeclaration &&
|
declaration is FirCallableDeclaration &&
|
||||||
@@ -50,28 +51,30 @@ fun FirVisibilityChecker.isVisible(
|
|||||||
callInfo.containingDeclarations,
|
callInfo.containingDeclarations,
|
||||||
dispatchReceiver,
|
dispatchReceiver,
|
||||||
staticQualifierClassForCallable = staticQualifierForCallable,
|
staticQualifierClassForCallable = staticQualifierForCallable,
|
||||||
isCallToPropertySetter = callInfo.callSite is FirVariableAssignment
|
isCallToPropertySetter = callInfo.callSite is FirVariableAssignment,
|
||||||
|
skipCheckForContainingClassVisibility = skipCheckForContainingClassVisibility,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirVisibilityChecker.isVisible(
|
fun FirVisibilityChecker.isVisible(
|
||||||
declaration: FirMemberDeclaration,
|
declaration: FirMemberDeclaration,
|
||||||
candidate: Candidate
|
candidate: Candidate,
|
||||||
|
skipCheckForContainingClassVisibility: Boolean = false,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val callInfo = candidate.callInfo
|
val callInfo = candidate.callInfo
|
||||||
|
|
||||||
if (!isVisible(declaration, callInfo, candidate.dispatchReceiver)) {
|
if (!isVisible(declaration, callInfo, candidate.dispatchReceiver, skipCheckForContainingClassVisibility)) {
|
||||||
val dispatchReceiverWithoutSmartCastType =
|
val dispatchReceiverWithoutSmartCastType =
|
||||||
removeSmartCastTypeForAttemptToFitVisibility(candidate.dispatchReceiver, candidate.callInfo.session) ?: return false
|
removeSmartCastTypeForAttemptToFitVisibility(candidate.dispatchReceiver, candidate.callInfo.session) ?: return false
|
||||||
|
|
||||||
if (!isVisible(declaration, callInfo, dispatchReceiverWithoutSmartCastType)) return false
|
if (!isVisible(declaration, callInfo, dispatchReceiverWithoutSmartCastType, skipCheckForContainingClassVisibility)) return false
|
||||||
|
|
||||||
candidate.dispatchReceiver = dispatchReceiverWithoutSmartCastType
|
candidate.dispatchReceiver = dispatchReceiverWithoutSmartCastType
|
||||||
}
|
}
|
||||||
|
|
||||||
val backingField = declaration.getBackingFieldIfApplicable()
|
val backingField = declaration.getBackingFieldIfApplicable()
|
||||||
if (backingField != null) {
|
if (backingField != null) {
|
||||||
candidate.hasVisibleBackingField = isVisible(backingField, callInfo, candidate.dispatchReceiver)
|
candidate.hasVisibleBackingField = isVisible(backingField, callInfo, candidate.dispatchReceiver, skipCheckForContainingClassVisibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/b.kt:34:10: error: cannot access 'B': it is private in file
|
||||||
|
import a.B
|
||||||
|
^
|
||||||
|
/b.kt:35:10: error: cannot access 'B': it is private in file
|
||||||
|
import a.B.Companion.bar
|
||||||
|
^
|
||||||
|
/b.kt:37:12: error: cannot access 'Companion': it is private in 'C'
|
||||||
|
import a.C.Companion.baz
|
||||||
|
^
|
||||||
|
/b.kt:38:10: error: cannot access 'D': it is private in file
|
||||||
|
import a.D
|
||||||
|
^
|
||||||
|
/b.kt:39:10: error: cannot access 'D': it is private in file
|
||||||
|
import a.D.Companion.quux
|
||||||
|
^
|
||||||
|
/b.kt:39:12: error: cannot access 'Companion': it is private in 'D'
|
||||||
|
import a.D.Companion.quux
|
||||||
|
^
|
||||||
|
/b.kt:43:7: error: cannot access 'B': it is private in file
|
||||||
|
f(B)
|
||||||
|
^
|
||||||
|
/b.kt:44:7: error: cannot access 'Companion': it is private in 'C'
|
||||||
|
f(C)
|
||||||
|
^
|
||||||
|
/b.kt:45:7: error: cannot access 'Companion': it is private in 'D'
|
||||||
|
f(D)
|
||||||
|
^
|
||||||
|
/b.kt:48:5: error: cannot access 'B': it is private in file
|
||||||
|
B.bar()
|
||||||
|
^
|
||||||
|
/b.kt:48:7: error: cannot access 'B': it is private in file
|
||||||
|
B.bar()
|
||||||
|
^
|
||||||
|
/b.kt:49:7: error: cannot access 'Companion': it is private in 'C'
|
||||||
|
C.baz()
|
||||||
|
^
|
||||||
|
/b.kt:50:5: error: cannot access 'D': it is private in file
|
||||||
|
D.quux()
|
||||||
|
^
|
||||||
|
/b.kt:50:7: error: cannot access 'Companion': it is private in 'D'
|
||||||
|
D.quux()
|
||||||
|
^
|
||||||
|
/b.kt:53:9: error: cannot access 'Companion': it is private in 'C'
|
||||||
|
a.C.baz()
|
||||||
|
^
|
||||||
|
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/b.kt:(96,97): error: Cannot access 'class B : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(107,108): error: Cannot access 'class B : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(145,154): error: Cannot access 'companion object Companion : Any': it is private in 'a/C'
|
||||||
|
|
||||||
|
/b.kt:(168,169): error: Cannot access 'class D : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(179,180): error: Cannot access 'class D : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(181,190): error: Cannot access 'companion object Companion : Any': it is private in 'a/D'
|
||||||
|
|
||||||
|
/b.kt:(225,226): error: Cannot access 'class B : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(243,244): error: Cannot access 'class D : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(263,264): error: Cannot access 'class B : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(265,268): error: Cannot access 'class B : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(277,280): error: Cannot access 'companion object Companion : Any': it is private in 'a/C'
|
||||||
|
|
||||||
|
/b.kt:(287,288): error: Cannot access 'class D : Any': it is private in file
|
||||||
|
|
||||||
|
/b.kt:(289,293): error: Cannot access 'companion object Companion : Any': it is private in 'a/D'
|
||||||
|
|
||||||
|
/b.kt:(319,322): error: Cannot access 'companion object Companion : Any': it is private in 'a/C'
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// RENDER_DIAGNOSTICS_FULL_TEXT
|
||||||
//FILE:a.kt
|
//FILE:a.kt
|
||||||
package a
|
package a
|
||||||
|
|
||||||
@@ -29,9 +30,13 @@ private class D {
|
|||||||
package b
|
package b
|
||||||
|
|
||||||
import a.A
|
import a.A
|
||||||
|
import a.A.Companion.foo
|
||||||
import a.<!INVISIBLE_REFERENCE!>B<!>
|
import a.<!INVISIBLE_REFERENCE!>B<!>
|
||||||
|
import a.<!INVISIBLE_REFERENCE!>B<!>.Companion.bar
|
||||||
import a.C
|
import a.C
|
||||||
|
import a.C.<!INVISIBLE_REFERENCE!>Companion<!>.baz
|
||||||
import a.<!INVISIBLE_REFERENCE!>D<!>
|
import a.<!INVISIBLE_REFERENCE!>D<!>
|
||||||
|
import a.<!INVISIBLE_REFERENCE!>D<!>.<!INVISIBLE_REFERENCE!>Companion<!>.quux
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
f(A)
|
f(A)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// RENDER_DIAGNOSTICS_FULL_TEXT
|
||||||
//FILE:a.kt
|
//FILE:a.kt
|
||||||
package a
|
package a
|
||||||
|
|
||||||
@@ -29,9 +30,13 @@ private class D {
|
|||||||
package b
|
package b
|
||||||
|
|
||||||
import a.A
|
import a.A
|
||||||
|
import a.A.Companion.foo
|
||||||
import a.<!INVISIBLE_REFERENCE!>B<!>
|
import a.<!INVISIBLE_REFERENCE!>B<!>
|
||||||
|
import a.<!INVISIBLE_REFERENCE!>B<!>.Companion.bar
|
||||||
import a.C
|
import a.C
|
||||||
|
import a.C.<!INVISIBLE_REFERENCE!>Companion<!>.baz
|
||||||
import a.<!INVISIBLE_REFERENCE!>D<!>
|
import a.<!INVISIBLE_REFERENCE!>D<!>
|
||||||
|
import a.<!INVISIBLE_REFERENCE!>D<!>.<!INVISIBLE_REFERENCE!>Companion<!>.quux
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
f(A)
|
f(A)
|
||||||
|
|||||||
Reference in New Issue
Block a user