FIR IDE: implement KotlinExpressionTypeProvider for FIR
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.codeInsight
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.idea.frontend.api.analyseInModalWindow
|
||||
import org.jetbrains.kotlin.idea.frontend.api.types.render
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
class KotlinHighLevelExpressionTypeProvider : KotlinExpressionTypeProvider() {
|
||||
override fun KtExpression.shouldShowStatementType(): Boolean {
|
||||
return true /* TODO */
|
||||
}
|
||||
|
||||
override fun getInformationHint(element: KtExpression): String = analyseInModalWindow(element, "Getting expression type") {
|
||||
val rendered = element.getKtType().render()
|
||||
StringUtil.escapeXmlEntities(rendered)
|
||||
}
|
||||
|
||||
override fun getErrorHint(): String = "No expression found"
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.codeInsight
|
||||
|
||||
import com.intellij.lang.ExpressionTypeProvider
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.TextEditor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
abstract class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
||||
protected abstract fun KtExpression.shouldShowStatementType(): Boolean
|
||||
|
||||
override fun getExpressionsAt(elementAt: PsiElement): List<KtExpression> {
|
||||
val candidates = elementAt.parentsWithSelf.filterIsInstance<KtExpression>().filter { it.shouldShowType() }.toList()
|
||||
val fileEditor =
|
||||
elementAt.containingFile?.virtualFile?.let { FileEditorManager.getInstance(elementAt.project).getSelectedEditor(it) }
|
||||
val selectionTextRange = if (fileEditor is TextEditor) {
|
||||
EditorUtil.getSelectionInAnyMode(fileEditor.editor)
|
||||
} else {
|
||||
TextRange.EMPTY_RANGE
|
||||
}
|
||||
val anchor =
|
||||
candidates.firstOrNull { selectionTextRange.isEmpty || it.textRange.contains(selectionTextRange) } ?: return emptyList()
|
||||
return candidates.filter { it.textRange.startOffset == anchor.textRange.startOffset }
|
||||
}
|
||||
|
||||
private fun KtExpression.shouldShowType() = when (this) {
|
||||
is KtFunctionLiteral -> false
|
||||
is KtFunction -> !hasBlockBody() && !hasDeclaredReturnType()
|
||||
is KtProperty -> typeReference == null
|
||||
is KtPropertyAccessor -> false
|
||||
is KtDestructuringDeclarationEntry -> true
|
||||
is KtStatementExpression, is KtDestructuringDeclaration -> false
|
||||
is KtIfExpression, is KtWhenExpression, is KtTryExpression -> shouldShowStatementType()
|
||||
is KtLoopExpression -> false
|
||||
is KtConstantExpression -> false
|
||||
is KtThisExpression -> false
|
||||
else -> getQualifiedExpressionForSelector() == null && parent !is KtCallableReferenceExpression && !isFunctionCallee()
|
||||
}
|
||||
|
||||
private fun KtExpression.isFunctionCallee(): Boolean {
|
||||
val callExpression = parent as? KtCallExpression ?: return false
|
||||
if (callExpression.calleeExpression != this) return false
|
||||
return mainReference?.resolve() is KtFunction
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,9 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
|
||||
id="KotlinCompletionContributor"
|
||||
order="first"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.KotlinFirCompletionContributor"/>
|
||||
<codeInsight.typeInfo language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinHighLevelExpressionTypeProvider"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
<!-- scripts -->
|
||||
|
||||
@@ -614,7 +614,8 @@
|
||||
implementationClass="org.jetbrains.kotlin.idea.refactoring.pushDown.JavaToKotlinPushDownDelegate"/>
|
||||
|
||||
|
||||
<codeInsight.typeInfo language="kotlin" implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinExpressionTypeProvider"/>
|
||||
<codeInsight.typeInfo language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinExpressionTypeProviderDescriptorsImpl"/>
|
||||
|
||||
<testCreator language="kotlin" implementationClass="org.jetbrains.kotlin.idea.testIntegration.KotlinTestCreator"/>
|
||||
<testFinder implementation="org.jetbrains.kotlin.idea.testIntegration.KotlinTestFinder"/>
|
||||
|
||||
+2
-44
@@ -5,12 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight
|
||||
|
||||
import com.intellij.lang.ExpressionTypeProvider
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.TextEditor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
@@ -18,12 +12,9 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.RenderingFormat
|
||||
@@ -38,7 +29,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||
|
||||
class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
||||
class KotlinExpressionTypeProviderDescriptorsImpl : KotlinExpressionTypeProvider() {
|
||||
private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
|
||||
textFormat = RenderingFormat.HTML
|
||||
classifierNamePolicy = object : ClassifierNamePolicy {
|
||||
@@ -51,35 +42,7 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExpressionsAt(elementAt: PsiElement): List<KtExpression> {
|
||||
val candidates = elementAt.parentsWithSelf.filterIsInstance<KtExpression>().filter { it.shouldShowType() }.toList()
|
||||
val fileEditor =
|
||||
elementAt.containingFile?.virtualFile?.let { FileEditorManager.getInstance(elementAt.project).getSelectedEditor(it) }
|
||||
val selectionTextRange = if (fileEditor is TextEditor) {
|
||||
EditorUtil.getSelectionInAnyMode(fileEditor.editor)
|
||||
} else {
|
||||
TextRange.EMPTY_RANGE
|
||||
}
|
||||
val anchor =
|
||||
candidates.firstOrNull { selectionTextRange.isEmpty || it.textRange.contains(selectionTextRange) } ?: return emptyList()
|
||||
return candidates.filter { it.textRange.startOffset == anchor.textRange.startOffset }
|
||||
}
|
||||
|
||||
private fun KtExpression.shouldShowType() = when (this) {
|
||||
is KtFunctionLiteral -> false
|
||||
is KtFunction -> !hasBlockBody() && !hasDeclaredReturnType()
|
||||
is KtProperty -> typeReference == null
|
||||
is KtPropertyAccessor -> false
|
||||
is KtDestructuringDeclarationEntry -> true
|
||||
is KtStatementExpression, is KtDestructuringDeclaration -> false
|
||||
is KtIfExpression, is KtWhenExpression, is KtTryExpression -> shouldShowStatementType()
|
||||
is KtLoopExpression -> false
|
||||
is KtConstantExpression -> false
|
||||
is KtThisExpression -> false
|
||||
else -> getQualifiedExpressionForSelector() == null && parent !is KtCallableReferenceExpression && !isFunctionCallee()
|
||||
}
|
||||
|
||||
private fun KtExpression.shouldShowStatementType(): Boolean {
|
||||
override fun KtExpression.shouldShowStatementType(): Boolean {
|
||||
if (parent !is KtBlockExpression) return true
|
||||
if (parent.children.lastOrNull() == this) {
|
||||
return isUsedAsExpression(analyze(BodyResolveMode.PARTIAL_WITH_CFA))
|
||||
@@ -87,11 +50,6 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun KtExpression.isFunctionCallee(): Boolean {
|
||||
val callExpression = parent as? KtCallExpression ?: return false
|
||||
if (callExpression.calleeExpression != this) return false
|
||||
return mainReference?.resolve() is KtFunction
|
||||
}
|
||||
|
||||
override fun getInformationHint(element: KtExpression): String {
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
@@ -16,7 +16,7 @@ abstract class AbstractExpressionTypeTest : KotlinLightCodeInsightFixtureTestCas
|
||||
|
||||
protected fun doTest(path: String) {
|
||||
myFixture.configureByFile(fileName())
|
||||
val expressionTypeProvider = KotlinExpressionTypeProvider()
|
||||
val expressionTypeProvider = KotlinExpressionTypeProviderDescriptorsImpl()
|
||||
val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)!!
|
||||
val expressions = expressionTypeProvider.getExpressionsAt(elementAtCaret)
|
||||
val types = expressions.map { "${it.text.replace('\n', ' ')} -> ${expressionTypeProvider.getInformationHint(it)}" }
|
||||
|
||||
Reference in New Issue
Block a user