提交 7a19bc32 编写于 作者: I Igor Yakovlev

[FIR IDE] Add base implementation of find usages of overrides

上级 f05630fc
......@@ -5,11 +5,26 @@
package org.jetbrains.kotlin.idea.findUsages
import com.intellij.ide.IdeBundle
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.core.util.showYesNoCancelDialog
import org.jetbrains.kotlin.idea.frontend.api.analyseInModalWindow
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
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.markers.KtNamedSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithKind
import org.jetbrains.kotlin.idea.refactoring.CHECK_SUPER_METHODS_YES_NO_DIALOG
import org.jetbrains.kotlin.idea.refactoring.formatPsiClass
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
class KotlinFindUsagesSupportFirImpl : KotlinFindUsagesSupport {
override fun isCallReceiverRefersToCompanionObject(element: KtElement, companionObject: KtObjectDeclaration): Boolean {
......@@ -33,7 +48,65 @@ class KotlinFindUsagesSupportFirImpl : KotlinFindUsagesSupport {
}
override fun checkSuperMethods(declaration: KtDeclaration, ignore: Collection<PsiElement>?, actionString: String): List<PsiElement> {
return listOf(declaration)
if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return listOf(declaration)
data class AnalyzedModel(
val declaredClassRender: String,
val overriddenDeclarationsAndRenders: Map<PsiElement, String>
)
fun getClassDescription(overriddenElement: PsiElement, containingSymbol: KtSymbolWithKind?): String =
when (overriddenElement) {
is KtNamedFunction, is KtProperty, is KtParameter -> (containingSymbol as? KtNamedSymbol)?.name?.asString() ?: "Unknown" //TODO render symbols
is PsiMethod -> {
val psiClass = overriddenElement.containingClass ?: error("Invalid element: ${overriddenElement.text}")
formatPsiClass(psiClass, markAsJava = true, inCode = false)
}
else -> error("Unexpected element: ${overriddenElement.getElementTextWithContext()}")
}.let { " $it\n" }
val analyzeResult = analyseInModalWindow(declaration, KotlinBundle.message("find.usages.progress.text.declaration.superMethods")) {
(declaration.getSymbol() as? KtCallableSymbol)?.let { callableSymbol ->
((callableSymbol as? KtSymbolWithKind)?.getContainingSymbol() as? KtClassOrObjectSymbol)?.let { containingClass ->
val overriddenSymbols = callableSymbol.getOverriddenSymbols(containingClass)
val renderToPsi = overriddenSymbols.mapNotNull {
it.psi?.let { psi ->
psi to getClassDescription(psi, (it as? KtSymbolWithKind)?.getContainingSymbol())
}
}
val filteredDeclarations =
if (ignore != null) renderToPsi.filter { ignore.contains(it.first) } else renderToPsi
val renderedClass = containingClass.name.asString() //TODO render class
AnalyzedModel(renderedClass, filteredDeclarations.toMap())
}
}
} ?: return listOf(declaration)
if (analyzeResult.overriddenDeclarationsAndRenders.isEmpty()) return listOf(declaration)
val message = KotlinBundle.message(
"override.declaration.x.overrides.y.in.class.list",
analyzeResult.declaredClassRender,
"\n${analyzeResult.overriddenDeclarationsAndRenders.values.joinToString(separator = "")}",
actionString
)
val exitCode = showYesNoCancelDialog(
CHECK_SUPER_METHODS_YES_NO_DIALOG,
declaration.project, message, IdeBundle.message("title.warning"), Messages.getQuestionIcon(), Messages.YES
)
return when (exitCode) {
Messages.YES -> listOf(declaration) + analyzeResult.overriddenDeclarationsAndRenders.keys
Messages.NO -> listOf(declaration)
else -> emptyList()
}
}
override fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project): GlobalSearchScope {
......
......@@ -41,12 +41,14 @@ abstract class KtAnalysisSession(override val token: ValidityToken) : ValidityTo
protected abstract val symbolProvider: KtSymbolProvider
protected abstract val callResolver: KtCallResolver
protected abstract val completionCandidateChecker: KtCompletionCandidateChecker
protected abstract val symbolDeclarationOverridesProvider: KtSymbolDeclarationOverridesProvider
/// TODO: get rid of
@Deprecated("Used only in completion now, temporary")
abstract fun createContextDependentCopy(): KtAnalysisSession
fun KtCallableSymbol.getOverriddenSymbols(containingDeclaration: KtClassOrObjectSymbol): List<KtCallableSymbol> =
symbolDeclarationOverridesProvider.getOverriddenSymbols(this, containingDeclaration)
fun KtExpression.getSmartCasts(): Collection<KtType> = smartCastProvider.getSmartCastedToTypes(this)
......
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
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() {
/**
* Returns symbols that overridden by requested
*/
abstract fun <T : KtSymbol> getOverriddenSymbols(
callableSymbol: T,
containingDeclaration: KtClassOrObjectSymbol
): List<KtCallableSymbol>
//abstract fun getOverriddenSymbols(callableSymbol: KtCallableSymbol, containingDeclaration: KtClassOrObjectSymbol): List<KtCallableSymbol>
}
\ No newline at end of file
......@@ -42,7 +42,8 @@ private constructor(
override val symbolProvider: KtSymbolProvider =
KtFirSymbolProvider(this, firResolveState.firIdeLibrariesSession.firSymbolProvider, firResolveState, firSymbolBuilder, token)
override val completionCandidateChecker: KtCompletionCandidateChecker by threadLocal { KtFirCompletionCandidateChecker(this, token) }
override val symbolDeclarationOverridesProvider: KtSymbolDeclarationOverridesProvider
by threadLocal { KtFirSymbolDeclarationOverridesProvider(this, token) }
override fun createContextDependentCopy(): KtAnalysisSession {
check(!isContextSession) { "Cannot create context-dependent copy of KtAnalysis session from a context dependent one" }
......
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.frontend.api.fir.components
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.*
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
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
internal class KtFirSymbolDeclarationOverridesProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSymbolDeclarationOverridesProvider(), KtFirAnalysisSessionComponent {
private fun FirTypeScope.processCallableByName(declaration: FirDeclaration) = when (declaration) {
is FirSimpleFunction -> processFunctionsByName(declaration.name) { }
is FirProperty -> processPropertiesByName(declaration.name) { }
else -> error { " Invalid FIR symbol to process " }
}
private fun FirTypeScope.processOverriddenDeclarations(
declaration: FirDeclaration,
processor: (FirCallableDeclaration<*>) -> ProcessorAction
) = when (declaration) {
is FirSimpleFunction -> processOverriddenFunctions(declaration.symbol) { processor.invoke(it.fir) }
is FirProperty -> processOverriddenProperties(declaration.symbol) { processor.invoke(it.fir) }
else -> error { " Invalid FIR symbol to process " }
}
override fun <T : KtSymbol> getOverriddenSymbols(
callableSymbol: T,
containingDeclaration: KtClassOrObjectSymbol
): List<KtCallableSymbol> {
check(callableSymbol is KtFirSymbol<*>)
check(containingDeclaration is KtFirClassOrObjectSymbol)
return callableSymbol.firRef.withFir(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { firCallableElement ->
containingDeclaration.firRef.withFir(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { containingDeclaration ->
val firTypeScope = containingDeclaration.unsubstitutedScope(
containingDeclaration.session,
ScopeSession()
)
val overriddenElement = mutableSetOf<KtCallableSymbol>()
firTypeScope.processCallableByName(firCallableElement)
firTypeScope.processOverriddenDeclarations(firCallableElement) { overriddenDeclaration ->
val ktSymbol = analysisSession.firSymbolBuilder.buildCallableSymbol(overriddenDeclaration)
overriddenElement.add(ktSymbol)
ProcessorAction.NEXT
}
overriddenElement.toList()
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册