mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[command-completion] IDEA-373902 Command completion. New actions: Safe Delete
GitOrigin-RevId: fe6389cad1553d577539b4800bed5bbaae1cd99f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
784c38c413
commit
786d15fc38
@@ -1494,6 +1494,7 @@
|
||||
<codeInsight.completion.command.provider language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaQuickDocumentationCompletionCommand" order="last"/>
|
||||
<codeInsight.completion.command.provider language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaGenerateConstructorCompletionCommandProvider" order="last"/>
|
||||
<codeInsight.completion.command.provider language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaSurroundWithCompletionCommandProvider" order="last"/>
|
||||
<codeInsight.completion.command.provider language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaSafeDeleteCompletionCommandProvider" order="last"/>
|
||||
|
||||
<weigher implementationClass="com.intellij.codeInsight.completion.LoggerWeigher" key="completion" id="logger"/>
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.completion.commands.impl
|
||||
|
||||
import com.intellij.codeInsight.completion.command.CompletionCommand
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractSafeDeleteCompletionCommandProvider
|
||||
import com.intellij.codeInsight.completion.command.commands.DirectInspectionFixCompletionCommand
|
||||
import com.intellij.codeInsight.completion.command.getCommandContext
|
||||
import com.intellij.codeInsight.completion.command.getTargetContext
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.elementType
|
||||
|
||||
public class JavaSafeDeleteCompletionCommandProvider : AbstractSafeDeleteCompletionCommandProvider() {
|
||||
override fun findElement(offset: Int, psiFile: PsiFile, editor: Editor?): PsiElement? {
|
||||
if (editor == null) return null
|
||||
var element = getCommandContext(offset, psiFile) ?: return null
|
||||
if (element is PsiWhiteSpace) element = PsiTreeUtil.skipWhitespacesBackward(element) ?: return null
|
||||
if (element is PsiIdentifier && (element.parent is PsiMember || element.parent is PsiVariable)) {
|
||||
return element
|
||||
}
|
||||
if (element.elementType == JavaTokenType.RBRACE) {
|
||||
val parentElement = element.parent
|
||||
if (parentElement is PsiMember) {
|
||||
val targetElement = (if (parentElement is PsiNameIdentifierOwner) parentElement.nameIdentifier
|
||||
else PsiTreeUtil.findChildOfType(parentElement, PsiIdentifier::class.java)) ?: return null
|
||||
return targetElement
|
||||
}
|
||||
val grandparentElement = element.parent?.parent
|
||||
if (grandparentElement is PsiMember) {
|
||||
val targetElement = (if (grandparentElement is PsiNameIdentifierOwner) grandparentElement.nameIdentifier
|
||||
else PsiTreeUtil.findChildOfType(grandparentElement, PsiIdentifier::class.java)) ?: return null
|
||||
return targetElement
|
||||
}
|
||||
}
|
||||
val targetContext = getTargetContext(offset, editor)
|
||||
if (targetContext?.isWritable != true) return null
|
||||
return element
|
||||
}
|
||||
|
||||
override fun skipForHighlightCommand(command: CompletionCommand): Boolean {
|
||||
return command is DirectInspectionFixCompletionCommand && command.inspectionId == "unused"
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInsight.completion.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.testFramework.NeedsIndex
|
||||
|
||||
@NeedsIndex.SmartMode(reason = "it requires highlighting")
|
||||
class JavaCommandsCompletionSafeDeleteTest : LightFixtureCompletionTestCase() {
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
Registry.get("ide.completion.command.enabled").setValue(false, getTestRootDisposable())
|
||||
Registry.get("ide.completion.command.force.enabled").setValue(true, getTestRootDisposable())
|
||||
}
|
||||
|
||||
fun testSafeDeleteClassEnd() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
}.<caret>
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
new A();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteClassIdentifier() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A.<caret> {
|
||||
int a;
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
new A();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteClassReference() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
new A.<caret>();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteMethodEnd() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
public void foo(){}.<caret>
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
new A().foo();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteMethodIdentifier() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
public void foo.<caret>(){}
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
new A().foo();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteMethodReference() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
public void foo(){}
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
new A().foo.<caret>();
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteVariable() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
public void foo(){}
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
A a.<caret> = new A().foo();
|
||||
System.out.println(a);
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testSafeDeleteVariableReference() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, """
|
||||
class A {
|
||||
int a;
|
||||
public void foo(){}
|
||||
}
|
||||
|
||||
class B {
|
||||
public B(){
|
||||
A a = new A().foo();
|
||||
System.out.println(a.<caret>);
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
}
|
||||
@@ -267,6 +267,14 @@ c:com.intellij.codeInsight.actions.VcsFacade
|
||||
- p:createCommand(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):com.intellij.codeInsight.completion.command.commands.ActionCompletionCommand
|
||||
- a:findRenameOffset(I,com.intellij.psi.PsiFile):java.lang.Integer
|
||||
- p:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
|
||||
*a:com.intellij.codeInsight.completion.command.commands.AbstractSafeDeleteCompletionCommandProvider
|
||||
- com.intellij.codeInsight.completion.command.commands.ActionCommandProvider
|
||||
- com.intellij.codeInsight.completion.command.commands.HighlightCommandSkipper
|
||||
- <init>():V
|
||||
- p:createCommand(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):com.intellij.codeInsight.completion.command.commands.ActionCompletionCommand
|
||||
- a:findElement(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):com.intellij.psi.PsiElement
|
||||
- p:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
|
||||
- a:skipForHighlightCommand(com.intellij.codeInsight.completion.command.CompletionCommand):Z
|
||||
*a:com.intellij.codeInsight.completion.command.commands.AbstractShowUsagesActionCompletionCommandProvider
|
||||
- com.intellij.codeInsight.completion.command.commands.ActionCommandProvider
|
||||
- <init>():V
|
||||
@@ -322,11 +330,23 @@ c:com.intellij.codeInsight.actions.VcsFacade
|
||||
- getPriority():java.lang.Integer
|
||||
- getSynonyms():java.util.List
|
||||
- f:setActionId(java.lang.String):V
|
||||
*f:com.intellij.codeInsight.completion.command.commands.DirectInspectionFixCompletionCommand
|
||||
- com.intellij.codeInsight.completion.command.CompletionCommand
|
||||
- <init>(java.lang.String,java.lang.String,java.lang.Integer,javax.swing.Icon,com.intellij.codeInsight.completion.command.HighlightInfoLookup,I,kotlin.jvm.functions.Function0):V
|
||||
- execute(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):V
|
||||
- getHighlightInfo():com.intellij.codeInsight.completion.command.HighlightInfoLookup
|
||||
- getIcon():javax.swing.Icon
|
||||
- f:getInspectionId():java.lang.String
|
||||
- getPresentableName():java.lang.String
|
||||
- getPreview():com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
|
||||
- getPriority():java.lang.Integer
|
||||
*:com.intellij.codeInsight.completion.command.commands.ErrorFixCommandProvider
|
||||
- com.intellij.openapi.project.PossiblyDumbAware
|
||||
- *sf:Companion:com.intellij.codeInsight.completion.command.commands.ErrorFixCommandProvider$Companion
|
||||
- a:getCommands(com.intellij.psi.PsiFile,java.util.List,I):java.util.List
|
||||
*f:com.intellij.codeInsight.completion.command.commands.ErrorFixCommandProvider$Companion
|
||||
*:com.intellij.codeInsight.completion.command.commands.HighlightCommandSkipper
|
||||
- a:skipForHighlightCommand(com.intellij.codeInsight.completion.command.CompletionCommand):Z
|
||||
*:com.intellij.codeInsight.completion.command.commands.IntentionCommandOffsetProvider
|
||||
- *sf:Companion:com.intellij.codeInsight.completion.command.commands.IntentionCommandOffsetProvider$Companion
|
||||
- findOffsets(com.intellij.psi.PsiFile,I):java.util.List
|
||||
|
||||
+7
-1
@@ -2,6 +2,8 @@
|
||||
package com.intellij.codeInsight.completion.command
|
||||
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.completion.command.commands.DirectIntentionCommandProvider
|
||||
import com.intellij.codeInsight.completion.command.commands.HighlightCommandSkipper
|
||||
import com.intellij.codeInsight.completion.command.configuration.ApplicationCommandCompletionService
|
||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
||||
import com.intellij.codeInsight.completion.ml.MLWeigherUtil
|
||||
@@ -237,7 +239,11 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
) {
|
||||
val element = copyFile.findElementAt(offset - 1) ?: return
|
||||
if (!ApplicationCommandCompletionService.getInstance().commandCompletionEnabled()) return
|
||||
for (provider in commandCompletionFactory.commandProviders(project, element.language)) {
|
||||
val commandProviders = commandCompletionFactory.commandProviders(project, element.language)
|
||||
val highlightCommandProvider = commandProviders.filterIsInstance<DirectIntentionCommandProvider>().firstOrNull()
|
||||
val highlightCommandSkippers = commandProviders.filter { it is HighlightCommandSkipper }.toSet()
|
||||
highlightCommandProvider?.setSkippers(highlightCommandSkippers)
|
||||
for (provider in commandProviders.filter { it !is HighlightCommandSkipper }) {
|
||||
try {
|
||||
if (isReadOnly && !provider.supportsReadOnly()) continue
|
||||
copyEditor.caretModel.moveToOffset(offset)
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.completion.command.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.CommandCompletionProviderContext
|
||||
import com.intellij.codeInsight.completion.command.CompletionCommand
|
||||
import com.intellij.codeInsight.completion.command.HighlightInfoLookup
|
||||
import com.intellij.idea.ActionsBundle
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.colors.EditorColors
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
abstract class AbstractSafeDeleteCompletionCommandProvider : HighlightCommandSkipper,
|
||||
ActionCommandProvider(actionId = "SafeDelete",
|
||||
presentableName = ActionsBundle.message("action.SafeDelete.text"),
|
||||
synonyms = listOf("delete", "safe delete"),
|
||||
icon = null,
|
||||
priority = -100,
|
||||
previewText = ActionsBundle.message("action.SafeDelete.description")) {
|
||||
|
||||
abstract fun findElement(offset: Int, psiFile: PsiFile, editor: Editor?): PsiElement?
|
||||
|
||||
abstract override fun skipForHighlightCommand(command: CompletionCommand): Boolean
|
||||
|
||||
override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
|
||||
val element = findElement(offset, psiFile, editor) ?: return false
|
||||
editor?.caretModel?.moveToOffset(element.textRange.endOffset)
|
||||
return super.isApplicable(element.textRange.endOffset, psiFile, editor)
|
||||
}
|
||||
|
||||
override fun createCommand(context: CommandCompletionProviderContext): ActionCompletionCommand? {
|
||||
val element = findElement(context.offset, context.psiFile, context.editor) ?: return null
|
||||
val startOffset = element.textRange.endOffset
|
||||
return object : ActionCompletionCommand(actionId = super.actionId,
|
||||
presentableActionName = super.presentableName,
|
||||
icon = super.icon,
|
||||
priority = super.priority,
|
||||
previewText = super.previewText,
|
||||
highlightInfo = HighlightInfoLookup(element.textRange, EditorColors.SEARCH_RESULT_ATTRIBUTES, 0),
|
||||
synonyms = super.synonyms) {
|
||||
override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
|
||||
editor?.caretModel?.moveToOffset(startOffset)
|
||||
super.execute(startOffset, psiFile, editor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -31,8 +31,8 @@ import kotlinx.coroutines.job
|
||||
import org.jetbrains.annotations.Nls
|
||||
import javax.swing.Icon
|
||||
|
||||
internal class DirectInspectionFixCompletionCommand(
|
||||
private val inspectionId: String,
|
||||
class DirectInspectionFixCompletionCommand(
|
||||
val inspectionId: String,
|
||||
override val presentableName: @Nls String,
|
||||
override val priority: Int?,
|
||||
override val icon: Icon?,
|
||||
|
||||
+28
-1
@@ -72,6 +72,11 @@ import java.util.function.Predicate
|
||||
* based on intentions, errors, and inspections within the given context.
|
||||
*/
|
||||
internal class DirectIntentionCommandProvider : CommandProvider {
|
||||
private var mySkipper: Set<CommandProvider> = emptySet()
|
||||
fun setSkippers(skippers: Set<CommandProvider>) {
|
||||
mySkipper = skippers
|
||||
}
|
||||
|
||||
override fun getCommands(context: CommandCompletionProviderContext): List<CompletionCommand> {
|
||||
if (!ApplicationCommandCompletionService.getInstance().commandCompletionEnabled()) return emptyList()
|
||||
val originalEditor = context.originalEditor
|
||||
@@ -136,10 +141,32 @@ internal class DirectIntentionCommandProvider : CommandProvider {
|
||||
|
||||
val intentions = asyncIntentions.await()
|
||||
result.addAll(intentions)
|
||||
result.addAll(processSkippers(result, context))
|
||||
return@runBlockingCancellable result
|
||||
}
|
||||
}
|
||||
|
||||
private fun processSkippers(fromHighlights: MutableList<CompletionCommand>, context: CommandCompletionProviderContext): Collection<CompletionCommand> {
|
||||
val result = mutableListOf<CompletionCommand>()
|
||||
if (mySkipper.isEmpty()) return emptyList()
|
||||
for (provider in mySkipper) {
|
||||
if (provider is HighlightCommandSkipper) {
|
||||
if (fromHighlights.any { provider.skipForHighlightCommand(it) }) continue
|
||||
try {
|
||||
context.editor.caretModel.moveToOffset(context.offset)
|
||||
result.addAll(provider.getCommands(context))
|
||||
}
|
||||
catch (e: Exception) {
|
||||
if (e is ControlFlowException || e is CancellationException) {
|
||||
throw e
|
||||
}
|
||||
thisLogger().error("Can't collect commands", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createCustomEditor(
|
||||
psiFile: PsiFile,
|
||||
editor: Editor,
|
||||
@@ -485,7 +512,7 @@ internal class DirectIntentionCommandProvider : CommandProvider {
|
||||
modCommandAction.getPresentation(ActionContext.from(editor, psiFile))
|
||||
?.rangesToHighlight()
|
||||
?.firstOrNull { highlightRange ->
|
||||
highlightRange.highlightingKind() == Presentation.HighlightingKind.APPLICABLE_TO_RANGE &&
|
||||
highlightRange.highlightingKind() == Presentation.HighlightingKind.APPLICABLE_TO_RANGE &&
|
||||
highlightRange.range.startOffset <= currentOffset
|
||||
}
|
||||
?.let {
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.completion.command.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.CompletionCommand
|
||||
|
||||
interface HighlightCommandSkipper {
|
||||
fun skipForHighlightCommand(command: CompletionCommand): Boolean
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.CompletionCommand
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractSafeDeleteCompletionCommandProvider
|
||||
import com.intellij.codeInsight.completion.command.commands.DirectInspectionFixCompletionCommand
|
||||
import com.intellij.codeInsight.completion.command.getCommandContext
|
||||
import com.intellij.codeInsight.completion.command.getTargetContext
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
|
||||
internal class KotlinSafeDeleteCompletionCommandProvider : AbstractSafeDeleteCompletionCommandProvider() {
|
||||
override fun findElement(
|
||||
offset: Int,
|
||||
psiFile: PsiFile,
|
||||
editor: Editor?
|
||||
): PsiElement? {
|
||||
var currentOffset = offset
|
||||
if (currentOffset == 0 || editor == null) return null
|
||||
var element = getCommandContext(offset, psiFile) ?: return null
|
||||
if (element is PsiWhiteSpace) {
|
||||
element = PsiTreeUtil.prevVisibleLeaf(element) ?: return null
|
||||
currentOffset = element.textRange.endOffset
|
||||
}
|
||||
|
||||
val method = element.parentOfType<KtFunction>()
|
||||
if (method != null &&
|
||||
(method.identifyingElement?.textRange?.endOffset == currentOffset ||
|
||||
method.bodyBlockExpression?.textRange?.endOffset == currentOffset)
|
||||
) return method.identifyingElement
|
||||
|
||||
val psiClass = element.parentOfType<KtClass>()
|
||||
if (psiClass != null && psiClass.getBody()?.rBrace != null && psiClass.getBody()?.rBrace?.textRange?.endOffset == currentOffset) {
|
||||
return psiClass.identifyingElement
|
||||
}
|
||||
|
||||
val nameIdentifierOwner = element.parentOfType<PsiNameIdentifierOwner>()
|
||||
if (nameIdentifierOwner != null && nameIdentifierOwner.nameIdentifier?.textRange?.endOffset == currentOffset) {
|
||||
return nameIdentifierOwner.nameIdentifier
|
||||
}
|
||||
|
||||
val targetContext = getTargetContext(offset, editor)
|
||||
if (targetContext?.isWritable != true) return null
|
||||
return element
|
||||
}
|
||||
|
||||
override fun skipForHighlightCommand(command: CompletionCommand): Boolean {
|
||||
return command is DirectInspectionFixCompletionCommand &&
|
||||
(command.inspectionId == "UnusedVariable" || command.inspectionId == "unused")
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.fir.completion.commands
|
||||
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
|
||||
class K2CommandCompletionSafeDeleteTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override val pluginMode = KotlinPluginMode.K2
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
Registry.get("ide.completion.command.enabled").setValue(false, getTestRootDisposable())
|
||||
Registry.get("ide.completion.command.force.enabled").setValue(true, getTestRootDisposable())
|
||||
}
|
||||
|
||||
fun testClassIdentifier() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A.<caret> {
|
||||
fun foo(a: String) {
|
||||
var b = a
|
||||
}
|
||||
}
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A()
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull() { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testClassEnd() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A {
|
||||
fun foo(a: String) {
|
||||
var b = a
|
||||
}
|
||||
}.<caret>
|
||||
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A()
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull() { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testClassReference() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A {
|
||||
fun foo(a: String) {
|
||||
var b = a
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A.<caret>()
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull() { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
|
||||
fun testMethodIdentifier() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A {
|
||||
fun foo.<caret>(a: String) {
|
||||
var b = a
|
||||
}
|
||||
}
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A().foo("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull() { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testMethodEnd() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A {
|
||||
fun foo(a: String) {
|
||||
var b = a
|
||||
} .<caret>
|
||||
}
|
||||
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A().foo("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull() { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
|
||||
fun testMethodReference() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
|
||||
class A {
|
||||
fun foo(a: String) {
|
||||
var b = a
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A().foo.<caret>("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull() { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
|
||||
fun testVariable() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
|
||||
class A {
|
||||
fun foo(a.<caret>: String) {
|
||||
var b = a
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A().foo("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
fun testVariableReference() {
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
|
||||
class A {
|
||||
fun foo(a: String) {
|
||||
var b = a.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class B{
|
||||
fun bar(){
|
||||
var c = A().foo("1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
assertNotNull(elements.firstOrNull { element -> element.lookupString.contains("Safe delete", ignoreCase = true) })
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
<codeInsight.completion.command.provider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinTypeInfoCompletionCommandProvider" order="last"/>
|
||||
<codeInsight.completion.command.provider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinQuickDocumentationCompletionCommandProvider" order="last"/>
|
||||
<codeInsight.completion.command.provider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinSurroundWithCompletionCommandProvider" order="last"/>
|
||||
<codeInsight.completion.command.provider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinSafeDeleteCompletionCommandProvider" order="last"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
|
||||
Reference in New Issue
Block a user