diff --git a/java/java-analysis-impl/resources/messages/QuickFixBundle.properties b/java/java-analysis-impl/resources/messages/QuickFixBundle.properties
index e5ccf38f3e74..ee6b2daec928 100644
--- a/java/java-analysis-impl/resources/messages/QuickFixBundle.properties
+++ b/java/java-analysis-impl/resources/messages/QuickFixBundle.properties
@@ -134,6 +134,8 @@ create.write.only.property.from.usage.full.text=Create write-only property ''{0}
create.getter=Create Getter
# suppress inspection "UnusedProperty"
create.setter=Create Setter
+# suppress inspection "UnusedProperty"
+create.getter.setter=Create Getter/Setter
create.annotation.family=Add annotation to declaration
create.annotation.text=Annotate as @{0}
defer.final.assignment.with.temp.family=Defer final assignment with temp
diff --git a/java/java-impl/resources/META-INF/JavaPlugin.xml b/java/java-impl/resources/META-INF/JavaPlugin.xml
index 12ae1df835f7..c7efedf3e034 100644
--- a/java/java-impl/resources/META-INF/JavaPlugin.xml
+++ b/java/java-impl/resources/META-INF/JavaPlugin.xml
@@ -1505,6 +1505,12 @@
+
+
+
+
+
+
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt
index 055b20ae42e0..c31c910d6509 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt
@@ -1,9 +1,15 @@
// Copyright 2000-2024 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.api
+import com.intellij.codeInsight.TargetElementUtil
import com.intellij.modcommand.ModHighlight.HighlightInfo
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.actionSystem.DataContext
+import com.intellij.openapi.actionSystem.LangDataKeys
+import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.ApiStatus
@@ -41,4 +47,30 @@ abstract class OldCompletionCommand : CompletionCommand() {
override fun execute(offset: Int, psiFile: PsiFile) {
execute(offset, psiFile, null)
}
+
+
+ internal fun dataContext(
+ psiFile: PsiFile,
+ editor: Editor,
+ context: PsiElement?,
+ ): DataContext {
+ val dataContext = SimpleDataContext.builder()
+ .add(CommonDataKeys.PROJECT, psiFile.project)
+ .add(CommonDataKeys.EDITOR, editor)
+ .add(CommonDataKeys.PSI_ELEMENT, context)
+ .add(CommonDataKeys.PSI_FILE, psiFile)
+ .add(LangDataKeys.CONTEXT_LANGUAGES, arrayOf(psiFile.language))
+ .build()
+ return dataContext
+ }
+
+ internal fun getTargetContext(offset: Int, editor: Editor): PsiElement? {
+ try {
+ val util = TargetElementUtil.getInstance()
+ return util.findTargetElement(editor, util.getReferenceSearchFlags(), offset)
+ }
+ catch (e: IndexNotReadyException) {
+ return null;
+ }
+ }
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt
index 7b92a46b935a..36702ffb8864 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt
@@ -114,7 +114,8 @@ class CommandCompletionService(
if (highlightInfoContainer == null || actionContainers == null) return null
if (document.immutableCharSequence.hashCode() != highlightInfoContainer.hashcode) return null
if (highlightInfoContainer.offset != offset) return null
- val actionContainer = actionContainers.firstOrNull { it.hashcode == highlightInfoContainer.hashcode } ?: return null
+ val actionContainer = actionContainers.firstOrNull { it.hashcode == highlightInfoContainer.hashcode && it.offset == offset }
+ ?: return null
val allActions = mutableListOf()
allActions.addAll(actionContainer.highlighters.allActions)
val revertMap: MutableMap = mutableMapOf()
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt
index 521386a2ecb4..90426a7ff950 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt
@@ -1,16 +1,12 @@
// Copyright 2000-2024 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.TargetElementUtil
import com.intellij.codeInsight.completion.commands.api.OldCompletionCommand
import com.intellij.ide.DataManager
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ex.ActionUtil
-import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.psi.PsiComment
-import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.annotations.Nls
@@ -29,13 +25,7 @@ abstract class AbstractActionCompletionCommand(
val action = action ?: return false
if (editor == null) return false
val context = getTargetContext(offset, editor)
- val dataContext = SimpleDataContext.builder()
- .add(CommonDataKeys.PROJECT, psiFile.project)
- .add(CommonDataKeys.EDITOR, editor)
- .add(CommonDataKeys.PSI_ELEMENT, context)
- .add(CommonDataKeys.PSI_FILE, psiFile)
- .add(LangDataKeys.CONTEXT_LANGUAGES, arrayOf(psiFile.language))
- .build()
+ val dataContext = dataContext(psiFile, editor, context)
val presentation: Presentation = action.templatePresentation.clone()
val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.NONE, null)
@@ -44,16 +34,6 @@ abstract class AbstractActionCompletionCommand(
return event.presentation.isEnabled && event.presentation.isVisible
}
- private fun getTargetContext(offset: Int, editor: Editor): PsiElement? {
- try {
- val util = TargetElementUtil.getInstance()
- return util.findTargetElement(editor, util.getReferenceSearchFlags(), offset)
- }
- catch (e: IndexNotReadyException) {
- return null;
- }
- }
-
override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
val action = action ?: return
if (editor == null) return
@@ -61,7 +41,7 @@ abstract class AbstractActionCompletionCommand(
val presentation: Presentation = action.templatePresentation.clone()
val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.NONE, null)
if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
- ActionUtil.performActionDumbAwareWithCallbacks(action, event);
+ ActionUtil.performActionDumbAwareWithCallbacks(action, event)
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/BaseGenerateGetterSetterHandleCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/BaseGenerateGetterSetterHandleCompletionCommand.kt
new file mode 100644
index 000000000000..b1333a1ca052
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/BaseGenerateGetterSetterHandleCompletionCommand.kt
@@ -0,0 +1,53 @@
+// Copyright 2000-2024 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.commands.api.OldCompletionCommand
+import com.intellij.codeInsight.daemon.QuickFixBundle
+import com.intellij.codeInsight.intention.QuickFixFactory
+import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
+import com.intellij.modcommand.ActionContext
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiField
+import com.intellij.psi.PsiFile
+import com.intellij.psi.util.PsiTreeUtil
+import javax.swing.Icon
+
+
+class GenerateGetterSetterHandleCompletionCommand :
+ BaseGenerateGetterSetterHandleCompletionCommand(true, true, "Create Getter/Setter",
+ QuickFixBundle.message("create.getter.setter"))
+
+class GenerateSetterHandleCompletionCommand :
+ BaseGenerateGetterSetterHandleCompletionCommand(false, true, "Create Setter",
+ QuickFixBundle.message("create.setter"))
+
+class GenerateGetterHandleCompletionCommand :
+ BaseGenerateGetterSetterHandleCompletionCommand(true, false, "Create Getter",
+ QuickFixBundle.message("create.getter"))
+
+abstract class BaseGenerateGetterSetterHandleCompletionCommand(
+ val generateGetter: Boolean,
+ val generateSetter: Boolean,
+ override val name: String,
+ override val i18nName: String,
+) : OldCompletionCommand() {
+
+ override val icon: Icon? = null
+
+ override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ val element = getContext(offset, psiFile) ?: return false
+ val field = PsiTreeUtil.getParentOfType(element, PsiField::class.java) ?: return false
+ val action = QuickFixFactory.getInstance().createCreateGetterOrSetterFix(generateGetter, generateSetter, field)
+ val context = ActionContext.from(editor, psiFile).withElement(field)
+ return action.asModCommandAction()?.getPresentation(context) != null
+ }
+
+ override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
+ val element = getContext(offset, psiFile) ?: return
+ val field = PsiTreeUtil.getParentOfType(element, PsiField::class.java) ?: return
+ val action = QuickFixFactory.getInstance().createCreateGetterOrSetterFix(generateGetter, generateSetter, field)
+ if (editor == null) return
+ @Suppress("DialogTitleCapitalization")
+ ShowIntentionActionsHandler.chooseActionAndInvoke(psiFile, editor, action, action.text)
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt
index b07d09bfa04a..2d5b4ede2a33 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt
@@ -1,8 +1,8 @@
// Copyright 2000-2024 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.commands.api.CompletionCommand
import com.intellij.codeInsight.completion.commands.api.CommandProvider
+import com.intellij.codeInsight.completion.commands.api.CompletionCommand
import com.intellij.codeInsight.generation.actions.BaseGenerateAction
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
@@ -39,6 +39,7 @@ class GenerateCommandProvider : CommandProvider {
}
}
return generateActions.map { GenerateCompletionCommand(it) }
+ .filter { it.isApplicable(offset, psiFile, editor) }
}
override fun getId(): String {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt
index d07db5baeb70..9a1783eb513f 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt
@@ -2,6 +2,7 @@
package com.intellij.codeInsight.completion.commands.impl
import com.intellij.codeInsight.completion.commands.api.OldCompletionCommand
+import com.intellij.codeInsight.completion.commands.impl.AbstractActionCompletionCommand.Companion.isApplicableToProject
import com.intellij.codeInsight.generation.actions.BaseGenerateAction
import com.intellij.ide.DataManager
import com.intellij.java.JavaBundle
@@ -25,6 +26,9 @@ class GenerateCompletionCommand(private val action: BaseGenerateAction) : OldCom
get() = null
override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ if (!isApplicableToProject(offset, psiFile)) {
+ return false
+ }
val context = psiFile.findElementAt(offset) ?: return false
if (editor == null) return false
val dataContext = SimpleDataContext.builder()
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt
index 51e2c9f2bc49..fde97844dcff 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt
@@ -1,50 +1,30 @@
// Copyright 2000-2024 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.commands.api.CompletionCommand
-import com.intellij.icons.AllIcons
-import com.intellij.ide.util.EditSourceUtil
import com.intellij.idea.ActionsBundle
+import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiIdentifier
import com.intellij.psi.PsiJavaCodeReferenceElement
import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.annotations.Nls
-import javax.swing.Icon
-class GoToDeclarationCompletionCommand : CompletionCommand() {
- override val name: String
- get() = "Go to Declaration"
+class GoToDeclarationCompletionCommand : AbstractActionCompletionCommand("GotoDeclarationOnly",
+ "Go to Declaration",
+ ActionsBundle.message("action.GotoDeclarationOnly.text"),
+ null) {
+ override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ return super.isApplicable(offset, psiFile, editor) && hasToShow(offset, psiFile)
+ }
- override val i18nName: @Nls String
- get() = ActionsBundle.message("action.GotoDeclaration.text")
-
- override val icon: Icon
- get() = AllIcons.Ide.ExternalLinkArrowWhite // Use the appropriate icon
-
- override fun isApplicable(offset: Int, psiFile: PsiFile): Boolean {
+ private fun hasToShow(offset: Int, psiFile: PsiFile): Boolean {
val context = (getContext(offset, psiFile)) ?: return false
return canNavigateToDeclaration(context)
}
- override fun execute(offset: Int, psiFile: PsiFile) {
- val element = getContext(offset, psiFile) ?: return
- if (element !is PsiIdentifier) {
- return
- }
- val javaRef = PsiTreeUtil.getParentOfType(element, PsiJavaCodeReferenceElement::class.java)
-
- val psiElement = javaRef?.resolve()
- if (psiElement != null) {
- EditSourceUtil.navigateToPsiElement(psiElement)
- }
- }
-
-
private fun canNavigateToDeclaration(context: PsiElement): Boolean {
if (context !is PsiIdentifier) {
- return false;
+ return false
}
val javaRef = PsiTreeUtil.getParentOfType(context, PsiJavaCodeReferenceElement::class.java)
val psiElement = javaRef?.resolve()
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntroduceVariableCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntroduceVariableCommand.kt
new file mode 100644
index 000000000000..eaacc03608c5
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntroduceVariableCommand.kt
@@ -0,0 +1,50 @@
+// Copyright 2000-2024 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.commands.api.OldCompletionCommand
+import com.intellij.icons.AllIcons
+import com.intellij.lang.ContextAwareActionHandler
+import com.intellij.openapi.actionSystem.ActionPlaces
+import com.intellij.openapi.actionSystem.ActionUiKind
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.Presentation
+import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiFile
+import com.intellij.refactoring.JavaRefactoringActionHandlerFactory
+import com.intellij.refactoring.RefactoringBundle
+import com.intellij.refactoring.actions.IntroduceVariableAction
+import org.jetbrains.annotations.Nls
+import javax.swing.Icon
+
+class IntroduceVariableCommand : OldCompletionCommand() {
+ override val name: String
+ get() = "Introduce variable"
+
+ override val i18nName: @Nls String
+ get() = RefactoringBundle.message("introduce.variable.title")
+
+ override val icon: Icon
+ get() = AllIcons.Nodes.Variable
+
+ override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ if (editor == null) return false
+ val factory = JavaRefactoringActionHandlerFactory.getInstance()
+ val variableHandler = factory.createIntroduceVariableHandler()
+ if (variableHandler is ContextAwareActionHandler) {
+ return variableHandler.isAvailableForQuickList(editor, psiFile, dataContext(psiFile, editor, getTargetContext(offset, editor)))
+ }
+ return false
+ }
+
+ override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
+ val action = IntroduceVariableAction()
+ if (editor == null) return
+ val context = getTargetContext(offset, editor)
+ val dataContext = dataContext(psiFile, editor, context)
+ val presentation: Presentation = action.templatePresentation.clone()
+ val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.NONE, null)
+ action.update(event)
+ ActionUtil.performActionDumbAwareWithCallbacks(action, event)
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ShowUsagesActionCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ShowUsagesActionCompletionCommand.kt
new file mode 100644
index 000000000000..38e25d830b72
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ShowUsagesActionCompletionCommand.kt
@@ -0,0 +1,24 @@
+// Copyright 2000-2024 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.find.actions.ShowUsagesAction
+import com.intellij.idea.ActionsBundle
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.*
+import com.intellij.psi.util.PsiTreeUtil
+
+class ShowUsagesActionCompletionCommand : AbstractActionCompletionCommand(ShowUsagesAction.ID,
+ "Show usages",
+ ActionsBundle.message("action.ShowUsages.text"),
+ null) {
+ override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ return super.isApplicable(offset, psiFile, editor) && hasToShow(getContext(offset, psiFile))
+ }
+
+ private fun hasToShow(element: PsiElement?): Boolean {
+ if (element == null) return false
+ val namedIdentifierParent = PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner::class.java)
+ return namedIdentifierParent?.nameIdentifier == element &&
+ (namedIdentifierParent is PsiVariable || namedIdentifierParent is PsiMethod || namedIdentifierParent is PsiMember)
+ }
+}
\ No newline at end of file