From 6e1f17ce06217f84df39a01e92111a1faf1630e7 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Fri, 1 Apr 2011 20:52:57 +0400 Subject: [PATCH] GotoDeclarationHandler now can return multiple targets --- .../actions/GotoBreakContinueHandler.java | 2 +- .../navigation/CtrlMouseHandler.java | 18 +++++- .../actions/GotoDeclarationAction.java | 55 +++++++++++++------ .../actions/GotoDeclarationHandler.java | 2 +- .../actions/GotoDeclarationHandlerBase.java | 34 ++++++++++++ .../find/actions/FindUsagesAction.java | 2 +- .../I18nMessageGotoDeclarationHandler.java | 6 +- 7 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandlerBase.java diff --git a/java/java-impl/src/com/intellij/codeInsight/navigation/actions/GotoBreakContinueHandler.java b/java/java-impl/src/com/intellij/codeInsight/navigation/actions/GotoBreakContinueHandler.java index 3a97cf0d3d4e..9dc5b4f89f7e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/navigation/actions/GotoBreakContinueHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/navigation/actions/GotoBreakContinueHandler.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; /** * @author yole */ -public class GotoBreakContinueHandler implements GotoDeclarationHandler { +public class GotoBreakContinueHandler extends GotoDeclarationHandlerBase { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.navigation.actions.GotoBreakContinueHandler"); @Nullable diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java index c61716b16ac4..96a573615423 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java @@ -353,6 +353,23 @@ public class CtrlMouseHandler extends AbstractProjectComponent { } } else if (browseMode == BrowseMode.Declaration) { + final PsiElement[] targetElements = GotoDeclarationAction.findTargetElementsNoVS(myProject, editor, offset); + final PsiElement elementAtPointer = file.findElementAt(offset); + + if (targetElements != null) { + if (targetElements.length == 0) { + return null; + } + else if (targetElements.length == 1) { + if (elementAtPointer != null && targetElements[0].isPhysical()) { + return new InfoSingle(elementAtPointer, targetElements[0]); + } + } + else { + return elementAtPointer != null ? new InfoMultiple(elementAtPointer) : null; + } + } + PsiReference ref = TargetElementUtilBase.findReference(editor, offset); if (ref != null) { PsiElement resolvedElement = resolve(ref); @@ -360,7 +377,6 @@ public class CtrlMouseHandler extends AbstractProjectComponent { return new InfoSingle(ref, resolvedElement); } } - targetElement = GotoDeclarationAction.findTargetElementNoVS(myProject, editor, offset); } else if (browseMode == BrowseMode.Implementation) { final PsiElement element = TargetElementUtilBase.getInstance().findTargetElement(editor, ImplementationSearcher.getFlags(), offset); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java index e931cdcb7f90..380470b5e337 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java @@ -76,13 +76,16 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code try { int offset = editor.getCaretModel().getOffset(); - PsiElement element = findTargetElement(project, editor, offset); + PsiElement[] elements = findAllTargetElements(project, editor, offset); FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration"); - if (element == null) { - chooseAmbiguousTarget(editor, offset); + + if (elements.length != 1) { + chooseAmbiguousTarget(editor, offset, elements); return; } + final PsiElement element = elements[0]; + PsiElement navElement = element.getNavigationElement(); navElement = TargetElementUtilBase.getInstance().getGotoDeclarationTarget(element, navElement); @@ -104,7 +107,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code } } - private static void chooseAmbiguousTarget(final Editor editor, int offset) { + private static void chooseAmbiguousTarget(final Editor editor, int offset, PsiElement[] elements) { PsiElementProcessor navigateProcessor = new PsiElementProcessor() { public boolean execute(final PsiElement element) { Navigatable navigatable = EditSourceUtil.getDescriptor(element); @@ -114,28 +117,37 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return true; } }; - boolean found = chooseAmbiguousTarget(editor, offset, navigateProcessor, CodeInsightBundle.message("declaration.navigation.title")); + boolean found = + chooseAmbiguousTarget(editor, offset, navigateProcessor, CodeInsightBundle.message("declaration.navigation.title"), elements); if (!found) { HintManager.getInstance().showErrorHint(editor, "Cannot find declaration to go to"); } } // returns true if processor is run or is going to be run after showing popup - public static boolean chooseAmbiguousTarget(final Editor editor, int offset, PsiElementProcessor processor, String titlePattern) { + public static boolean chooseAmbiguousTarget(final Editor editor, + int offset, + PsiElementProcessor processor, + String titlePattern, + PsiElement[] elements) { if (TargetElementUtilBase.inVirtualSpace(editor, offset)) { return false; } final PsiReference reference = TargetElementUtilBase.findReference(editor, offset); - final Collection candidates = suggestCandidates(reference); - if (candidates.size() == 1) { - PsiElement element = candidates.iterator().next(); + + if (elements == null) { + final Collection candidates = suggestCandidates(reference); + elements = PsiUtilBase.toPsiElementArray(candidates); + } + + if (elements.length == 1) { + PsiElement element = elements[0]; LOG.assertTrue(element != null); processor.execute(element); return true; } - if (candidates.size() > 1) { - PsiElement[] elements = PsiUtilBase.toPsiElementArray(candidates); + if (elements.length > 1) { final TextRange range = reference.getRangeInElement(); final String refText = range.substring(reference.getElement().getText()); String title = MessageFormat.format(titlePattern, refText); @@ -158,15 +170,22 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code @Nullable public static PsiElement findTargetElement(Project project, Editor editor, int offset) { + final PsiElement[] targets = findAllTargetElements(project, editor, offset); + return targets.length == 1 ? targets[0] : null; + } + + @NotNull + public static PsiElement[] findAllTargetElements(Project project, Editor editor, int offset) { if (TargetElementUtilBase.inVirtualSpace(editor, offset)) { - return null; + return PsiElement.EMPTY_ARRAY; } - return findTargetElementNoVS(project, editor, offset); + final PsiElement[] targets = findTargetElementsNoVS(project, editor, offset); + return targets != null ? targets : PsiElement.EMPTY_ARRAY; } @Nullable - public static PsiElement findTargetElementNoVS(Project project, Editor editor, int offset) { + public static PsiElement[] findTargetElementsNoVS(Project project, Editor editor, int offset) { PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); if (file == null) { return null; @@ -174,7 +193,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code PsiElement elementAt = file.findElementAt(offset); for (GotoDeclarationHandler handler : Extensions.getExtensions(GotoDeclarationHandler.EP_NAME)) { - PsiElement result = handler.getGotoDeclarationTarget(elementAt); + PsiElement[] result = handler.getGotoDeclarationTargets(elementAt); if (result != null) { return result; } @@ -182,12 +201,14 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code int flags = TargetElementUtilBase.getInstance().getAllAccepted() & ~TargetElementUtilBase.ELEMENT_NAME_ACCEPTED; PsiElement element = TargetElementUtilBase.getInstance().findTargetElement(editor, flags, offset); - if (element != null) return element; + if (element != null) { + return new PsiElement[] {element}; + } // if no references found in injected fragment, try outer document if (editor instanceof EditorWindow) { EditorWindow window = (EditorWindow)editor; - return findTargetElementNoVS(project, window.getDelegate(), window.getDocument().injectedToHost(offset)); + return findTargetElementsNoVS(project, window.getDelegate(), window.getDocument().injectedToHost(offset)); } return null; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandler.java index db959f68f75c..677372e17942 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandler.java @@ -27,5 +27,5 @@ public interface GotoDeclarationHandler { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.gotoDeclarationHandler"); @Nullable - PsiElement getGotoDeclarationTarget(PsiElement sourceElement); + PsiElement[] getGotoDeclarationTargets(PsiElement sourceElement); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandlerBase.java new file mode 100644 index 000000000000..9459af1f0810 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationHandlerBase.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.navigation.actions; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +/** + * @author Eugene.Kudelevsky + */ +public abstract class GotoDeclarationHandlerBase implements GotoDeclarationHandler { + @Nullable + @Override + public PsiElement[] getGotoDeclarationTargets(PsiElement sourceElement) { + final PsiElement target = getGotoDeclarationTarget(sourceElement); + return target != null ? new PsiElement[] {target} : null; + } + + @Nullable + public abstract PsiElement getGotoDeclarationTarget(PsiElement sourceElement); +} diff --git a/platform/lang-impl/src/com/intellij/find/actions/FindUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/FindUsagesAction.java index 98141c15e0e9..9f0d98d66937 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/FindUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/FindUsagesAction.java @@ -74,7 +74,7 @@ public class FindUsagesAction extends AnAction { } else { int offset = editor.getCaretModel().getOffset(); - boolean chosen = GotoDeclarationAction.chooseAmbiguousTarget(editor, offset, processor, FindBundle.message("find.usages.ambiguous.title")); + boolean chosen = GotoDeclarationAction.chooseAmbiguousTarget(editor, offset, processor, FindBundle.message("find.usages.ambiguous.title"), null); if (!chosen) { HintManager.getInstance().showErrorHint(editor, FindBundle.message("find.no.usages.at.cursor.error")); } diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java index efe0c987a6bd..72ba48886414 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java @@ -16,10 +16,10 @@ package com.intellij.codeInspection.i18n.folding; import com.intellij.codeInsight.folding.impl.EditorFoldingInfo; -import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler; +import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandlerBase; +import com.intellij.lang.ASTNode; import com.intellij.lang.folding.CompositeFoldingBuilder; import com.intellij.lang.folding.FoldingBuilder; -import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.FoldRegion; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable; /** * @author Konstantin Bulenkov */ -public class I18nMessageGotoDeclarationHandler implements GotoDeclarationHandler { +public class I18nMessageGotoDeclarationHandler extends GotoDeclarationHandlerBase { private static final Key KEY = CompositeFoldingBuilder.FOLDING_BUILDER; public PsiElement getGotoDeclarationTarget(PsiElement element) {