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"
|
id="KotlinCompletionContributor"
|
||||||
order="first"
|
order="first"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.completion.KotlinFirCompletionContributor"/>
|
implementationClass="org.jetbrains.kotlin.idea.completion.KotlinFirCompletionContributor"/>
|
||||||
|
<codeInsight.typeInfo language="kotlin"
|
||||||
|
implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinHighLevelExpressionTypeProvider"/>
|
||||||
|
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<!-- scripts -->
|
<!-- scripts -->
|
||||||
|
|||||||
@@ -614,7 +614,8 @@
|
|||||||
implementationClass="org.jetbrains.kotlin.idea.refactoring.pushDown.JavaToKotlinPushDownDelegate"/>
|
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"/>
|
<testCreator language="kotlin" implementationClass="org.jetbrains.kotlin.idea.testIntegration.KotlinTestCreator"/>
|
||||||
<testFinder implementation="org.jetbrains.kotlin.idea.testIntegration.KotlinTestFinder"/>
|
<testFinder implementation="org.jetbrains.kotlin.idea.testIntegration.KotlinTestFinder"/>
|
||||||
|
|||||||
+2
-44
@@ -5,12 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.codeInsight
|
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.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
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.findModuleDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
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.idea.resolve.getDataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.parents
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
|
||||||
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.RenderingFormat
|
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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||||
|
|
||||||
class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
class KotlinExpressionTypeProviderDescriptorsImpl : KotlinExpressionTypeProvider() {
|
||||||
private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
|
private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
|
||||||
textFormat = RenderingFormat.HTML
|
textFormat = RenderingFormat.HTML
|
||||||
classifierNamePolicy = object : ClassifierNamePolicy {
|
classifierNamePolicy = object : ClassifierNamePolicy {
|
||||||
@@ -51,35 +42,7 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExpressionsAt(elementAt: PsiElement): List<KtExpression> {
|
override fun KtExpression.shouldShowStatementType(): Boolean {
|
||||||
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 {
|
|
||||||
if (parent !is KtBlockExpression) return true
|
if (parent !is KtBlockExpression) return true
|
||||||
if (parent.children.lastOrNull() == this) {
|
if (parent.children.lastOrNull() == this) {
|
||||||
return isUsedAsExpression(analyze(BodyResolveMode.PARTIAL_WITH_CFA))
|
return isUsedAsExpression(analyze(BodyResolveMode.PARTIAL_WITH_CFA))
|
||||||
@@ -87,11 +50,6 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
|||||||
return false
|
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 {
|
override fun getInformationHint(element: KtExpression): String {
|
||||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
@@ -16,7 +16,7 @@ abstract class AbstractExpressionTypeTest : KotlinLightCodeInsightFixtureTestCas
|
|||||||
|
|
||||||
protected fun doTest(path: String) {
|
protected fun doTest(path: String) {
|
||||||
myFixture.configureByFile(fileName())
|
myFixture.configureByFile(fileName())
|
||||||
val expressionTypeProvider = KotlinExpressionTypeProvider()
|
val expressionTypeProvider = KotlinExpressionTypeProviderDescriptorsImpl()
|
||||||
val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)!!
|
val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)!!
|
||||||
val expressions = expressionTypeProvider.getExpressionsAt(elementAtCaret)
|
val expressions = expressionTypeProvider.getExpressionsAt(elementAtCaret)
|
||||||
val types = expressions.map { "${it.text.replace('\n', ' ')} -> ${expressionTypeProvider.getInformationHint(it)}" }
|
val types = expressions.map { "${it.text.replace('\n', ' ')} -> ${expressionTypeProvider.getInformationHint(it)}" }
|
||||||
|
|||||||
Reference in New Issue
Block a user