diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/replAnalysis.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/replAnalysis.kt index 0c7535e82ad..da3ff81dc79 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/replAnalysis.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/replAnalysis.kt @@ -19,7 +19,8 @@ data class SourceCodeCompletionVariant( val text: String, val displayText: String, val tail: String, - val icon: String + val icon: String, + val deprecationLevel: DeprecationLevel? = null, ) interface ReplAnalyzerResultKeys diff --git a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt index 068cc891eaf..14d4e92447a 100644 --- a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt +++ b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt @@ -127,6 +127,39 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() { } } + @Test + fun testDeprecatedCompletion() = test { + run { + doCompile + code = """ + @Deprecated("deprecated") + class Clazz1 + + @Deprecated("deprecated", level=DeprecationLevel.ERROR) + class Clazz2 + """.trimIndent() + } + run { + doComplete + code = """ + @Deprecated("deprecated1", level=DeprecationLevel.WA) + class Clazz3 + + @Deprecated("deprecated1", level=kotlin.annotation.AnnotationRetention.SOURCE) + class Clazz4 + + Claz + """.trimIndent() + cursor = code.length + expect { + addCompletion("Clazz3", "Clazz3", " (Line_2_simplescript)", "class", DeprecationLevel.WARNING) + addCompletion("Clazz4", "Clazz4", " (Line_2_simplescript)", "class", DeprecationLevel.WARNING) + addCompletion("Clazz1", "Clazz1", " (Line_1_simplescript)", "class", DeprecationLevel.WARNING) + addCompletion("Clazz2", "Clazz2", " (Line_1_simplescript)", "class", DeprecationLevel.ERROR) + } + } + } + @Test fun testExtensionMethods() = test { run { diff --git a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/test_util/testConfiguration.kt b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/test_util/testConfiguration.kt index 0a702307e9f..a272faa93af 100644 --- a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/test_util/testConfiguration.kt +++ b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/test_util/testConfiguration.kt @@ -72,8 +72,8 @@ class TestConf { class Expected(private val run: Run) { val completions = ExpectedList(run::doComplete) - fun addCompletion(text: String, displayText: String, tail: String, icon: String) { - completions.add(SourceCodeCompletionVariant(text, displayText, tail, icon)) + fun addCompletion(text: String, displayText: String, tail: String, icon: String, deprecationLevel: DeprecationLevel? = null) { + completions.add(SourceCodeCompletionVariant(text, displayText, tail, icon, deprecationLevel)) } val errors = ExpectedList(run::doErrorCheck) diff --git a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt index 10e5df292b2..96d16c606e4 100644 --- a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt +++ b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt @@ -17,6 +17,8 @@ import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -27,16 +29,20 @@ import org.jetbrains.kotlin.renderer.ClassifierNamePolicy import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.MemberScope.Companion.ALL_NAME_FILTER import org.jetbrains.kotlin.scripting.ide_services.compiler.completion import org.jetbrains.kotlin.scripting.ide_services.compiler.filterOutShadowedDescriptors import org.jetbrains.kotlin.scripting.ide_services.compiler.nameFilter +import org.jetbrains.kotlin.scripting.resolve.classId import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.asFlexibleType import org.jetbrains.kotlin.types.isFlexible import java.io.File +import java.lang.IllegalArgumentException +import java.util.* import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.SourceCodeCompletionVariant @@ -252,14 +258,23 @@ private class KJvmReplCompleter( .let { if (isSortNeeded) it.sortedBy { descTriple -> descTriple.third } else it } - .forEach { - val descriptor = it.first - val (rawName, presentableText, tailText, completionText) = it.second + .forEach { resultTriple -> + val descriptor = resultTriple.first + val (rawName, presentableText, tailText, completionText) = resultTriple.second if (nameFilter(rawName, prefix)) { val fullName: String = formatName( presentableText ) + val deprecationLevel = descriptor.annotations + .findAnnotation(FqName("kotlin.Deprecated")) + ?.let { annotationDescriptor -> + val valuePair = annotationDescriptor.argumentValue("level")?.value as? Pair<*, *> + val valueClass = (valuePair?.first as? ClassId)?.takeIf { DeprecationLevel::class.classId == it } + val valueName = (valuePair?.second as? Name)?.identifier + if (valueClass == null || valueName == null) return@let DeprecationLevel.WARNING + DeprecationLevel.valueOf(valueName) + } yield( SourceCodeCompletionVariant( completionText, @@ -267,7 +282,8 @@ private class KJvmReplCompleter( tailText, getIconFromDescriptor( descriptor - ) + ), + deprecationLevel, ) ) }