mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[navigation] IJPL-206689 "Jump to source" ignores symbols present in code
GitOrigin-RevId: e2d4509041af391c1f6b153b56deec54d71734ce
This commit is contained in:
committed by
intellij-monorepo-bot
parent
23edec04f2
commit
64cc996dff
@@ -7,6 +7,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.platform.backend.navigation.NavigationTarget;
|
||||
import com.intellij.platform.backend.presentation.TargetPresentation;
|
||||
import com.intellij.platform.backend.presentation.TargetPresentationBuilder;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.*;
|
||||
@@ -42,6 +43,10 @@ public interface SymbolNavigationService {
|
||||
@Contract("_ -> new")
|
||||
@NotNull NavigationTarget psiElementNavigationTarget(@NotNull PsiElement element);
|
||||
|
||||
@ApiStatus.Internal
|
||||
@ApiStatus.Experimental
|
||||
@NotNull Navigatable getNavigatable(@NotNull Project project, @NotNull NavigationTarget target);
|
||||
|
||||
/**
|
||||
* Please use {@link TargetPresentation#builder(String)}
|
||||
*/
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// 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.navigation.impl
|
||||
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.navigation.ItemPresentation
|
||||
import com.intellij.navigation.NavigationItem
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.components.serviceAsync
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.wm.IdeFocusManager
|
||||
import com.intellij.platform.backend.navigation.NavigationRequest
|
||||
import com.intellij.platform.backend.navigation.NavigationTarget
|
||||
import com.intellij.platform.ide.navigation.NavigationOptions
|
||||
import com.intellij.platform.ide.navigation.NavigationService
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
import javax.swing.Icon
|
||||
|
||||
internal class NavigationTargetNavigatable(
|
||||
private val project: Project,
|
||||
navigationTarget: NavigationTarget,
|
||||
) : NavigationItem, ItemPresentation {
|
||||
|
||||
private val targetPresentation = navigationTarget.computePresentation()
|
||||
private val navigationTargetPointer = navigationTarget.createPointer()
|
||||
private val navigationTarget: NavigationTarget?
|
||||
get() = navigationTargetPointer.dereference()
|
||||
|
||||
override fun navigationRequest(): NavigationRequest? = navigationTarget?.navigationRequest()
|
||||
|
||||
override fun navigate(requestFocus: Boolean) {
|
||||
val component = IdeFocusManager.getInstance(project).getFocusOwner()
|
||||
val dataContext = component?.let { DataManager.getInstance().getDataContext(it) }
|
||||
|
||||
runWithModalProgressBlocking(project, IdeBundle.message("progress.title.preparing.navigation")) {
|
||||
val request = readAction { navigationTarget?.navigationRequest() }
|
||||
request?.let {
|
||||
project.serviceAsync<NavigationService>().navigate(
|
||||
it, NavigationOptions.defaultOptions().requestFocus(requestFocus), dataContext
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun canNavigate(): Boolean = true
|
||||
|
||||
override fun canNavigateToSource(): Boolean = false
|
||||
|
||||
override fun getName(): String = targetPresentation.presentableText
|
||||
|
||||
override fun getPresentation(): ItemPresentation = this
|
||||
|
||||
override fun getPresentableText(): String = targetPresentation.presentableText
|
||||
|
||||
override fun getIcon(unused: Boolean): Icon? = targetPresentation.icon
|
||||
|
||||
override fun getLocationString(): String? {
|
||||
val container = targetPresentation.containerText
|
||||
val location = targetPresentation.locationText
|
||||
return if (container != null || location != null) {
|
||||
sequenceOf(container, location).joinToString(", ", "(", ")")
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"NavigationTargetNavigatable[$navigationTarget]"
|
||||
|
||||
}
|
||||
+4
@@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.ClassExtension
|
||||
import com.intellij.platform.backend.navigation.NavigationTarget
|
||||
import com.intellij.platform.backend.presentation.TargetPresentationBuilder
|
||||
import com.intellij.pom.Navigatable
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.SmartList
|
||||
@@ -50,4 +51,7 @@ class SymbolNavigationServiceImpl : SymbolNavigationService {
|
||||
override fun presentationBuilder(presentableText: @Nls String): TargetPresentationBuilder {
|
||||
return TargetPresentationBuilderImpl(presentableText = presentableText)
|
||||
}
|
||||
|
||||
override fun getNavigatable(project: Project, target: NavigationTarget): Navigatable =
|
||||
NavigationTargetNavigatable(project, target)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
package com.intellij.ide.impl.dataRules;
|
||||
|
||||
import com.intellij.ide.util.EditSourceUtil;
|
||||
import com.intellij.model.psi.PsiSymbolService;
|
||||
import com.intellij.navigation.SymbolNavigationService;
|
||||
import com.intellij.openapi.actionSystem.DataMap;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.pom.Navigatable;
|
||||
@@ -10,8 +12,7 @@ import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.openapi.actionSystem.CommonDataKeys.NAVIGATABLE;
|
||||
import static com.intellij.openapi.actionSystem.CommonDataKeys.PSI_ELEMENT;
|
||||
import static com.intellij.openapi.actionSystem.CommonDataKeys.*;
|
||||
import static com.intellij.openapi.actionSystem.PlatformCoreDataKeys.SELECTED_ITEM;
|
||||
|
||||
final class NavigatableRule {
|
||||
@@ -22,6 +23,22 @@ final class NavigatableRule {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
var symbols = dataProvider.get(SYMBOLS);
|
||||
var project = dataProvider.get(PROJECT);
|
||||
if (project != null && symbols != null && !symbols.isEmpty()
|
||||
// For PsiElement symbols use logic below
|
||||
&& (symbols.size() > 1 || PsiSymbolService.getInstance().extractElementFromSymbol(symbols.getFirst()) == null)
|
||||
) {
|
||||
var navigatables = symbols.stream()
|
||||
.flatMap(symbol -> SymbolNavigationService.getInstance().getNavigationTargets(project, symbol).stream())
|
||||
.map(target -> SymbolNavigationService.getInstance().getNavigatable(project, target))
|
||||
.toList();
|
||||
if (navigatables.size() == 1) {
|
||||
return navigatables.getFirst();
|
||||
}
|
||||
}
|
||||
|
||||
PsiElement element = dataProvider.get(PSI_ELEMENT);
|
||||
if (element instanceof Navigatable o) {
|
||||
return o;
|
||||
|
||||
+20
-1
@@ -1,15 +1,34 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.impl.dataRules;
|
||||
|
||||
import com.intellij.model.Symbol;
|
||||
import com.intellij.navigation.SymbolNavigationService;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataMap;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
final class NavigatableArrayRule {
|
||||
static Navigatable @Nullable [] getData(@NotNull DataMap dataProvider) {
|
||||
Navigatable element = dataProvider.get(CommonDataKeys.NAVIGATABLE);
|
||||
return element == null ? null : new Navigatable[]{element};
|
||||
if (element != null) {
|
||||
return new Navigatable[]{element};
|
||||
}
|
||||
List<Symbol> symbolList = dataProvider.get(CommonDataKeys.SYMBOLS);
|
||||
Project project = dataProvider.get(CommonDataKeys.PROJECT);
|
||||
if (symbolList != null && project != null) {
|
||||
var navigatables = symbolList.stream()
|
||||
.flatMap(symbol -> SymbolNavigationService.getInstance().getNavigationTargets(project, symbol).stream())
|
||||
.map(target -> SymbolNavigationService.getInstance().getNavigatable(project, target))
|
||||
.toArray(Navigatable[]::new);
|
||||
if (navigatables.length > 0) {
|
||||
return navigatables;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-5
@@ -540,8 +540,16 @@ fun CodeInsightTestFixture.checkGTDUOutcome(expectedOutcome: GotoDeclarationOrUs
|
||||
|
||||
fun CodeInsightTestFixture.checkGotoDeclaration(fromSignature: String?, declarationSignature: String, expectedFileName: String? = null) {
|
||||
checkGTDUOutcome(GotoDeclarationOrUsageHandler2.GTDUOutcome.GTD, fromSignature)
|
||||
checkEditorNavigation("GotoDeclaration", fromSignature, declarationSignature, expectedFileName)
|
||||
}
|
||||
|
||||
fun CodeInsightTestFixture.checkJumpToSource(fromSignature: String?, sourceSignature: String, expectedFileName: String? = null) {
|
||||
checkEditorNavigation("EditSource", fromSignature, sourceSignature, expectedFileName)
|
||||
}
|
||||
|
||||
private fun CodeInsightTestFixture.checkEditorNavigation(action: String, fromSignature: String?, targetSignature: String, expectedFileName: String?) {
|
||||
val actualSignature = fromSignature ?: editor.currentPositionSignature
|
||||
performEditorAction("GotoDeclaration")
|
||||
performEditorAction(action)
|
||||
val targetEditor = FileEditorManager.getInstance(project).selectedTextEditor?.topLevelEditor
|
||||
if (targetEditor == null) throw NullPointerException(actualSignature)
|
||||
val targetFile = PsiDocumentManager.getInstance(project).getPsiFile(targetEditor.document)!!
|
||||
@@ -551,12 +559,12 @@ fun CodeInsightTestFixture.checkGotoDeclaration(fromSignature: String?, declarat
|
||||
else {
|
||||
assertEquals(actualSignature, targetEditor, editor.topLevelEditor)
|
||||
}
|
||||
if (!declarationSignature.contains("<caret>") || targetFile.findOffsetBySignature(
|
||||
declarationSignature) != targetEditor.caretModel.offset) {
|
||||
if (!targetSignature.contains("<caret>") || targetFile.findOffsetBySignature(
|
||||
targetSignature) != targetEditor.caretModel.offset) {
|
||||
assertEquals("For go to from: $actualSignature",
|
||||
declarationSignature + if (!declarationSignature.contains("<caret>")) ""
|
||||
targetSignature + if (!targetSignature.contains("<caret>")) ""
|
||||
else (" [" + InjectedLanguageManager.getInstance(project).getTopLevelFile(file)
|
||||
.findOffsetBySignature(declarationSignature) + "]"),
|
||||
.findOffsetBySignature(targetSignature) + "]"),
|
||||
targetEditor.currentPositionSignature + "[${targetEditor.caretModel.offset}]")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user