diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/codeInsight/KotlinHighLevelExpressionTypeProvider.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/codeInsight/KotlinHighLevelExpressionTypeProvider.kt new file mode 100644 index 00000000000..ac767e4feea --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/codeInsight/KotlinHighLevelExpressionTypeProvider.kt @@ -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" +} diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt new file mode 100644 index 00000000000..974374915bb --- /dev/null +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt @@ -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() { + protected abstract fun KtExpression.shouldShowStatementType(): Boolean + + override fun getExpressionsAt(elementAt: PsiElement): List { + val candidates = elementAt.parentsWithSelf.filterIsInstance().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 + } +} \ No newline at end of file diff --git a/idea/resources-fir/META-INF/plugin.xml b/idea/resources-fir/META-INF/plugin.xml index df89ff0d1e6..e25d7ad2c15 100644 --- a/idea/resources-fir/META-INF/plugin.xml +++ b/idea/resources-fir/META-INF/plugin.xml @@ -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"/> + + diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index 43a768781dc..74ba5f2ca79 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -614,7 +614,8 @@ implementationClass="org.jetbrains.kotlin.idea.refactoring.pushDown.JavaToKotlinPushDownDelegate"/> - + diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProviderDescriptorsImpl.kt similarity index 68% rename from idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt rename to idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProviderDescriptorsImpl.kt index 93b90c8be13..4c9ac8cb1ac 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProviderDescriptorsImpl.kt @@ -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() { +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() { } } - override fun getExpressionsAt(elementAt: PsiElement): List { - val candidates = elementAt.parentsWithSelf.filterIsInstance().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() { 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) diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt index 6cf89b19459..847c293bc44 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt @@ -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)}" }