diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt index 5d59a9e9b6a..35b929837bd 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt @@ -58,6 +58,9 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali fun KtCallableSymbol.getOverriddenSymbols(containingDeclaration: KtClassOrObjectSymbol): List = symbolDeclarationOverridesProvider.getOverriddenSymbols(this, containingDeclaration) + fun KtCallableSymbol.getIntersectionOverriddenSymbols(): Collection = + symbolDeclarationOverridesProvider.getIntersectionOverriddenSymbols(this) + fun KtExpression.getSmartCasts(): Collection = smartCastProvider.getSmartCastedToTypes(this) fun KtExpression.getImplicitReceiverSmartCasts(): Collection = diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationOverridesProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationOverridesProvider.kt index 17b38c1d3ba..caec1ed846c 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationOverridesProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationOverridesProvider.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.frontend.api.components import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol -import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol abstract class KtSymbolDeclarationOverridesProvider : KtAnalysisSessionComponent() { @@ -19,5 +18,9 @@ abstract class KtSymbolDeclarationOverridesProvider : KtAnalysisSessionComponent containingDeclaration: KtClassOrObjectSymbol ): List - //abstract fun getOverriddenSymbols(callableSymbol: KtCallableSymbol, containingDeclaration: KtClassOrObjectSymbol): List + /** + * If [symbol] origin is [org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolOrigin.INTERSECTION_OVERRIDE] + * Then returns the symbols which [symbol] overrides, otherwise empty collection + */ + abstract fun getIntersectionOverriddenSymbols(symbol: KtCallableSymbol): Collection } \ No newline at end of file diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbol.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbol.kt index 92ba2ee3567..59d9570da19 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbol.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbol.kt @@ -42,5 +42,17 @@ enum class KtSymbolOrigin { */ JAVA, - SAM_CONSTRUCTOR + SAM_CONSTRUCTOR, + + /** + * Consider the following code: + * ``` + * interface A { fun x() } + * interface B { fun x() } + * + * interface C : A, B + * ``` + * The intersection of functions A.foo & B.foo will create a function C.foo which will be marked with [INTERSECTION_OVERRIDE] + */ + INTERSECTION_OVERRIDE, } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt index d5d1d4f26fe..ad88f8c500c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt @@ -26,6 +26,7 @@ internal class KtFirSymbolContainingDeclarationProvider( KtSymbolOrigin.SOURCE, KtSymbolOrigin.SOURCE_MEMBER_GENERATED -> getContainingDeclarationForKotlinInSourceSymbol(symbol) KtSymbolOrigin.LIBRARY, KtSymbolOrigin.JAVA -> getContainingDeclarationForLibrarySymbol(symbol) + KtSymbolOrigin.INTERSECTION_OVERRIDE -> TODO() KtSymbolOrigin.SAM_CONSTRUCTOR -> TODO() } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolDeclarationOverridesProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolDeclarationOverridesProvider.kt index 10924fc58a2..7dce5343342 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolDeclarationOverridesProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSymbolDeclarationOverridesProvider.kt @@ -5,9 +5,15 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components +import org.jetbrains.kotlin.fir.FirSymbolOwner import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.scopes.* +import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverridePropertySymbol +import org.jetbrains.kotlin.fir.unwrapFakeOverrides import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.components.KtSymbolDeclarationOverridesProvider import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession @@ -63,4 +69,24 @@ internal class KtFirSymbolDeclarationOverridesProvider( } } } + + override fun getIntersectionOverriddenSymbols(symbol: KtCallableSymbol): Collection { + require(symbol is KtFirSymbol<*>) + if (symbol.origin != KtSymbolOrigin.INTERSECTION_OVERRIDE) return emptyList() + return symbol.firRef.withFir { fir -> + val firSymbol = (fir as? FirSymbolOwner<*>)?.symbol ?: return@withFir emptyList() + firSymbol.getIntersectionOverriddenSymbols().map { analysisSession.firSymbolBuilder.buildCallableSymbol(it.fir) } + } + } + + private fun AbstractFirBasedSymbol<*>.getIntersectionOverriddenSymbols(): Collection> { + require(this is FirCallableSymbol<*>) { + "Required FirCallableSymbol but ${this::class} found" + } + return when (this) { + is FirIntersectionOverrideFunctionSymbol -> intersections + is FirIntersectionOverridePropertySymbol -> intersections + else -> listOf(this) + } + } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt index b3fe3ba915e..9e7a32125ac 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt @@ -35,6 +35,7 @@ private tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (orig FirDeclarationOrigin.Java -> KtSymbolOrigin.JAVA FirDeclarationOrigin.SamConstructor -> KtSymbolOrigin.SAM_CONSTRUCTOR FirDeclarationOrigin.Enhancement -> KtSymbolOrigin.JAVA + FirDeclarationOrigin.IntersectionOverride -> KtSymbolOrigin.INTERSECTION_OVERRIDE else -> { val overridden = (this as? FirCallableDeclaration<*>)?.originalIfFakeOverride() ?: throw InvalidFirDeclarationOriginForSymbol(this) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReference.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReference.kt index c3295cff669..524d9e10693 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReference.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReference.kt @@ -10,14 +10,32 @@ import org.jetbrains.kotlin.idea.fir.findReferencePsi import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.KtSymbolBasedReference import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolOrigin interface KtFirReference : KtReference, KtSymbolBasedReference { - fun getResolvedToPsi(analysisSession: KtAnalysisSession): Collection = - analysisSession.resolveToSymbols().mapNotNull { symbol -> - (symbol as? KtFirSymbol<*>)?.firRef?.withFir { it.findReferencePsi() } - ?: symbol.psi + fun getResolvedToPsi(analysisSession: KtAnalysisSession): Collection = with(analysisSession) { + resolveToSymbols().flatMap { symbol -> + when (symbol) { + is KtFirSymbol<*> -> getPsiDeclarations(symbol) + else -> listOfNotNull(symbol.psi) + } } + } + + private fun KtAnalysisSession.getPsiDeclarations(symbol: KtFirSymbol<*>): Collection { + val intersectionOverriddenSymbolsOrSingle = when { + symbol.origin == KtSymbolOrigin.INTERSECTION_OVERRIDE && symbol is KtCallableSymbol -> symbol.getIntersectionOverriddenSymbols() + else -> listOf(symbol) + } + return intersectionOverriddenSymbolsOrSingle.mapNotNull { it.findPsiForReferenceResolve() } + } + + private fun KtSymbol.findPsiForReferenceResolve(): PsiElement? { + require(this is KtFirSymbol<*>) + return firRef.withFir { it.findReferencePsi() } + } override val resolver get() = KtFirReferenceResolver } \ No newline at end of file diff --git a/idea/idea-frontend-fir/testData/memberScopeByFqName/Int.txt b/idea/idea-frontend-fir/testData/memberScopeByFqName/Int.txt index 47aea143c5f..6b3e1e82925 100644 --- a/idea/idea-frontend-fir/testData/memberScopeByFqName/Int.txt +++ b/idea/idea-frontend-fir/testData/memberScopeByFqName/Int.txt @@ -1233,7 +1233,7 @@ KtFirFunctionSymbol: isSuspend: false modality: OPEN name: equals - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -1254,7 +1254,7 @@ KtFirFunctionSymbol: isSuspend: false modality: OPEN name: hashCode - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -1275,7 +1275,7 @@ KtFirFunctionSymbol: isSuspend: false modality: OPEN name: toString - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] diff --git a/idea/idea-frontend-fir/testData/memberScopeByFqName/MutableList.txt b/idea/idea-frontend-fir/testData/memberScopeByFqName/MutableList.txt index e94116ba572..f1ee3b5e269 100644 --- a/idea/idea-frontend-fir/testData/memberScopeByFqName/MutableList.txt +++ b/idea/idea-frontend-fir/testData/memberScopeByFqName/MutableList.txt @@ -288,7 +288,7 @@ KtFirFunctionSymbol: isSuspend: false modality: ABSTRACT name: contains - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -309,7 +309,7 @@ KtFirFunctionSymbol: isSuspend: false modality: ABSTRACT name: containsAll - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -372,7 +372,7 @@ KtFirFunctionSymbol: isSuspend: false modality: ABSTRACT name: isEmpty - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -393,7 +393,7 @@ KtFirFunctionSymbol: isSuspend: false modality: ABSTRACT name: iterator - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -439,7 +439,7 @@ KtFirKotlinPropertySymbol: isVal: true modality: ABSTRACT name: size - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null setter: null symbolKind: MEMBER @@ -459,7 +459,7 @@ KtFirFunctionSymbol: isSuspend: false modality: OPEN name: equals - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -480,7 +480,7 @@ KtFirFunctionSymbol: isSuspend: false modality: OPEN name: hashCode - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] @@ -501,7 +501,7 @@ KtFirFunctionSymbol: isSuspend: false modality: OPEN name: toString - origin: LIBRARY + origin: INTERSECTION_OVERRIDE receiverType: null symbolKind: MEMBER typeParameters: [] diff --git a/idea/testData/resolve/references/SeveralOverrides.kt b/idea/testData/resolve/references/SeveralOverrides.kt index 5d05223b0ed..5f05393ad8f 100644 --- a/idea/testData/resolve/references/SeveralOverrides.kt +++ b/idea/testData/resolve/references/SeveralOverrides.kt @@ -1,5 +1,3 @@ -// IGNORE_FIR - interface A { fun foo() } diff --git a/idea/testData/resolve/references/delegatedPropertyAccessors/inSource/getMultipleDeclarations.kt b/idea/testData/resolve/references/delegatedPropertyAccessors/inSource/getMultipleDeclarations.kt index 83d54224766..8c0fe7a2657 100644 --- a/idea/testData/resolve/references/delegatedPropertyAccessors/inSource/getMultipleDeclarations.kt +++ b/idea/testData/resolve/references/delegatedPropertyAccessors/inSource/getMultipleDeclarations.kt @@ -1,5 +1,3 @@ -// IGNORE_FIR - var x : Int by Baz() interface Foo {