diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyBrowser.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyBrowser.java
index c5a45b3a60ec..ad78a3f65017 100644
--- a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyBrowser.java
+++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyBrowser.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// 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.ide.hierarchy.call;
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
@@ -11,10 +11,7 @@ import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiField;
-import com.intellij.psi.PsiMember;
-import com.intellij.psi.PsiMethod;
+import com.intellij.psi.*;
import com.intellij.ui.PopupHandler;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -64,7 +61,7 @@ public class CallHierarchyBrowser extends CallHierarchyBrowserBase {
@Override
protected boolean isApplicableElement(@NotNull PsiElement e) {
- return e instanceof PsiMethod || e instanceof PsiField;
+ return e instanceof PsiMethod || e instanceof PsiField || e instanceof PsiClass aClass && aClass.isRecord();
}
@Override
diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java
index 56e0fc6c8dac..df053221be84 100644
--- a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java
+++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// 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.ide.hierarchy.call;
import com.intellij.codeInsight.highlighting.HighlightManager;
@@ -46,6 +46,9 @@ public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
*/
public PsiMember getEnclosingElement() {
PsiElement element = getPsiElement();
+ if (element instanceof PsiClass aClass && aClass.isRecord()) {
+ return JavaPsiRecordUtil.findCanonicalConstructor(aClass);
+ }
return element == null ? null : getEnclosingElement(element);
}
@@ -90,7 +93,7 @@ public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
}
if (enclosingElement instanceof PsiMethod || enclosingElement instanceof PsiField) {
- if (enclosingElement instanceof SyntheticElement) {
+ if (FileTypeUtils.isInServerPageFile(enclosingElement)) {
PsiFile file = enclosingElement.getContainingFile();
myHighlightedText.getEnding().addText(file != null ? file.getName() : JavaBundle.message("node.call.hierarchy.unknown.jsp"), mainTextAttributes);
}
diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/CalleeMethodsTreeStructure.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/CalleeMethodsTreeStructure.java
index 1cb6a5912d46..b351af3943b3 100644
--- a/java/java-impl/src/com/intellij/ide/hierarchy/call/CalleeMethodsTreeStructure.java
+++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/CalleeMethodsTreeStructure.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// 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.ide.hierarchy.call;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
@@ -30,7 +30,7 @@ public final class CalleeMethodsTreeStructure extends HierarchyTreeStructure {
@Override
protected Object @NotNull [] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
PsiMember enclosingElement = ((CallHierarchyNodeDescriptor)descriptor).getEnclosingElement();
- if (!(enclosingElement instanceof PsiMethod method)) {
+ if (!(enclosingElement instanceof PsiMethod method) || enclosingElement instanceof SyntheticElement) {
return ArrayUtilRt.EMPTY_OBJECT_ARRAY;
}
diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallHierarchyProvider.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallHierarchyProvider.java
index b8c952eb5125..25044d7b386c 100644
--- a/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallHierarchyProvider.java
+++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallHierarchyProvider.java
@@ -7,21 +7,17 @@ import com.intellij.ide.hierarchy.HierarchyProvider;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiField;
-import com.intellij.psi.PsiMember;
-import com.intellij.psi.PsiMethod;
+import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
-
public class JavaCallHierarchyProvider implements HierarchyProvider {
@Override
public PsiElement getTarget(@NotNull DataContext dataContext) {
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (project == null) return null;
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
- if (element instanceof PsiField) return element;
+ if (element instanceof PsiField || element instanceof PsiClass aClass && aClass.isRecord()) return element;
return PsiTreeUtil.getParentOfType(element, PsiMethod.class, false);
}
diff --git a/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructor/Action.java b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructor/Action.java
new file mode 100644
index 000000000000..9bcab8547b57
--- /dev/null
+++ b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructor/Action.java
@@ -0,0 +1,22 @@
+class Action {
+ public static void main(String[] args) {
+ var a = new Person("sdf", "sdf");
+ var b = new PersonB("sdf", "sdf");
+ }
+
+ public static class PersonB {
+
+ private final String name;
+ private final String address;
+
+ public PersonB(String name, String address) {
+ this.name = name;
+ this.address = address;
+ }
+ }
+}
+record Person(String name, String address) {
+ public Person(String name) {
+ this(name, "");
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructor/verification.xml b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructor/verification.xml
new file mode 100644
index 000000000000..d640718473f8
--- /dev/null
+++ b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructor/verification.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructorReverse/Action.java b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructorReverse/Action.java
new file mode 100644
index 000000000000..9bcab8547b57
--- /dev/null
+++ b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructorReverse/Action.java
@@ -0,0 +1,22 @@
+class Action {
+ public static void main(String[] args) {
+ var a = new Person("sdf", "sdf");
+ var b = new PersonB("sdf", "sdf");
+ }
+
+ public static class PersonB {
+
+ private final String name;
+ private final String address;
+
+ public PersonB(String name, String address) {
+ this.name = name;
+ this.address = address;
+ }
+ }
+}
+record Person(String name, String address) {
+ public Person(String name) {
+ this(name, "");
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructorReverse/verification.xml b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructorReverse/verification.xml
new file mode 100644
index 000000000000..548cf09bb048
--- /dev/null
+++ b/java/java-tests/testData/ide/hierarchy/call/RecordCanonicalConstructorReverse/verification.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java b/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java
index b18b8206c3a3..1dd905e8d3ba 100644
--- a/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java
@@ -27,7 +27,7 @@ import java.util.Arrays;
public class JavaCallHierarchyTest extends HierarchyViewTestBase {
@Override
protected @NotNull LanguageLevel getProjectLanguageLevel() {
- return LanguageLevel.JDK_1_8; // method refs are needed
+ return LanguageLevel.JDK_16; // records are needed
}
@NotNull
@@ -95,6 +95,20 @@ public class JavaCallHierarchyTest extends HierarchyViewTestBase {
doJavaCallerTypeHierarchyTest("A", "A", "A.java");
}
+ public void testRecordCanonicalConstructor() throws Exception {
+ doHierarchyTest(() -> {
+ PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass("Person", ProjectScope.getProjectScope(getProject()));
+ return new CallerMethodsTreeStructure(getProject(), aClass, HierarchyBrowserBaseEx.SCOPE_PROJECT);
+ }, JavaHierarchyUtil.getComparator(myProject), "Action.java");
+ }
+
+ public void testRecordCanonicalConstructorReverse() throws Exception {
+ doHierarchyTest(() -> {
+ PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass("Person", ProjectScope.getProjectScope(getProject()));
+ return new CalleeMethodsTreeStructure(getProject(), aClass, HierarchyBrowserBaseEx.SCOPE_PROJECT);
+ }, JavaHierarchyUtil.getComparator(myProject), "Action.java");
+ }
+
public void testMethodRef() throws Exception {
doJavaCalleeTypeHierarchyTest("A", "testMethod", "A.java");
}