Skip to content

Commit c4acc5f

Browse files
Hardes1intellij-monorepo-bot
authored andcommitted
[Java] IDEA-379305 Improve Java annotation folding
GitOrigin-RevId: bdd65e50cbd04868cce091546385fb4cd1c3efc1
1 parent a523332 commit c4acc5f

File tree

3 files changed

+144
-25
lines changed

3 files changed

+144
-25
lines changed

java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,9 @@ private static boolean isSimplePropertyAccessor(@NotNull PsiMethod method) {
113113
}
114114

115115
private static @NotNull TextRange annotationRange(@NotNull PsiAnnotation annotation) {
116-
PsiElement element = annotation;
117-
int startOffset = element.getTextRange().getStartOffset();
118-
PsiElement last = element;
119-
while (element instanceof PsiAnnotation) {
120-
last = element;
121-
element = PsiTreeUtil.skipWhitespacesAndCommentsForward(element);
122-
}
123-
124-
return new TextRange(startOffset, last.getTextRange().getEndOffset());
116+
TextRange parameterListRange = annotation.getParameterList().getTextRange();
117+
int startOffset = parameterListRange.getStartOffset();
118+
return new TextRange(startOffset, parameterListRange.getEndOffset());
125119
}
126120

127121
public static boolean hasErrorElementsNearby(@NotNull PsiFile file, int startOffset, int endOffset) {
@@ -162,20 +156,19 @@ private static void addAnnotationsToFold(@NotNull List<? super FoldingDescriptor
162156
@NotNull Document document) {
163157
if (modifierList == null) return;
164158
PsiElement[] children = modifierList.getChildren();
165-
for (int i = 0; i < children.length; i++) {
159+
for (int i = 0; i < children.length;) {
166160
PsiElement child = children[i];
167161
if (child instanceof PsiAnnotation) {
168162
PsiAnnotation annotation = (PsiAnnotation)child;
169-
addToFold(list, annotation, document, false, "@{...}", annotationRange(annotation), JavaCodeFoldingSettings.getInstance().isCollapseAnnotations());
170-
int j;
171-
for (j = i + 1; j < children.length; j++) {
172-
PsiElement nextChild = children[j];
173-
if (nextChild instanceof PsiModifier) break;
174-
}
175-
176-
//noinspection AssignmentToForLoopParameter
177-
i = j;
163+
addToFold(list, annotation, document, false, "(...)", annotationRange(annotation), JavaCodeFoldingSettings.getInstance().isCollapseAnnotations());
164+
annotation.acceptChildren(new NestedAnnotationsVisitor(list, document));
165+
}
166+
int j;
167+
for (j = i + 1; j < children.length; j++) {
168+
PsiElement nextChild = children[j];
169+
if (nextChild instanceof PsiModifier || nextChild instanceof PsiAnnotation) break;
178170
}
171+
i = j;
179172
}
180173
}
181174

@@ -756,4 +749,19 @@ protected boolean isCustomFoldingRoot(@NotNull ASTNode node) {
756749
}
757750
return nodeType == JavaElementType.CODE_BLOCK;
758751
}
752+
753+
private static class NestedAnnotationsVisitor extends JavaRecursiveElementWalkingVisitor {
754+
@NotNull private final List<? super FoldingDescriptor> myList;
755+
@NotNull private final Document myDocument;
756+
757+
private NestedAnnotationsVisitor(@NotNull List<? super FoldingDescriptor> list, @NotNull Document document) {
758+
myList = list;
759+
myDocument = document;
760+
}
761+
762+
@Override
763+
public void visitAnnotation(@NotNull PsiAnnotation annotation) {
764+
addToFold(myList, annotation, myDocument, false, "(...)", annotationRange(annotation), JavaCodeFoldingSettings.getInstance().isCollapseAnnotations());
765+
}
766+
}
759767
}

java/java-tests/testSrc/com/intellij/java/codeInsight/folding/JavaFolding8Test.java

Lines changed: 116 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.jetbrains.annotations.NotNull;
1111
import org.junit.Assume;
1212

13+
import java.util.Collections;
1314
import java.util.List;
1415

1516
public class JavaFolding8Test extends JavaFoldingTestCase {
@@ -106,21 +107,103 @@ void test(boolean b) {
106107
.toList());
107108
}
108109

109-
public void test_parameter_annotations() {
110+
public void testParameterAnnotations() {
111+
myFixture.addClass("""
112+
@interface Anno {
113+
String value();
114+
}
115+
""");
110116
configure("""
111117
class Some {
112118
void m(@Anno("hello " +
113119
"world") int a,
114120
@Anno("goodbye " +
115121
"world") int b) {}
116122
}
123+
""");
124+
assertEquals(List.of("FoldRegion -(29:66), placeholder='(...)'",
125+
"FoldRegion -(90:129), placeholder='(...)'"),
126+
ContainerUtil.map(myFixture.getEditor().getFoldingModel().getAllFoldRegions(), FoldRegion::toString));
127+
}
128+
129+
public void testSingleLineAnnotationIsNotCollapsed() {
130+
myFixture.addClass("""
131+
@interface Anno {
132+
String value();
133+
}
134+
""");
135+
configure("""
136+
class Some {
137+
@Anno("hello world")
138+
void m() {}
139+
}
140+
""");
141+
assertEquals(Collections.emptyList(),
142+
ContainerUtil.map(myFixture.getEditor().getFoldingModel().getAllFoldRegions(), FoldRegion::toString));
143+
144+
}
145+
146+
public void testAnnotationsFoldedIndependently() {
147+
myFixture.addClass("""
148+
@interface Anno {
149+
String value();
150+
}
151+
""");
152+
myFixture.addClass("""
153+
@interface Anno1 {
154+
String value();
155+
}
156+
""");
157+
configure("""
158+
class Some {
159+
@Anno(
160+
"hello world"
161+
)
162+
@Anno1(
163+
"Another hello world!"
164+
)
165+
void m() {}
166+
}
167+
""");
168+
assertEquals(List.of("FoldRegion -(22:47), placeholder='(...)'", "FoldRegion -(58:92), placeholder='(...)'"),
169+
ContainerUtil.map(myFixture.getEditor().getFoldingModel().getAllFoldRegions(), FoldRegion::toString));
170+
171+
}
172+
173+
public void testAnnotationsFoldingInDifferentPlaces(){
174+
myFixture.addClass("""
175+
@interface Anno {
176+
String value();
177+
}
178+
""");
117179

118-
@interface Anno {\s
180+
myFixture.addClass("""
181+
@interface Anno1 {
119182
String value();
120183
}
184+
""");
185+
configure("""
186+
public @Anno(
187+
"1"
188+
)
189+
class X {
190+
@Anno(
191+
"2"
192+
)
193+
private final @Anno1(
194+
"3"
195+
) String x = "";
196+
197+
@Anno(
198+
"4"
199+
) public @Anno1(
200+
"5"
201+
)
202+
String m() { return null; }
203+
}
121204
""");
122-
assertEquals(List.of("FoldRegion -(11:141), placeholder='{...}'", "FoldRegion -(24:66), placeholder='@{...}'",
123-
"FoldRegion -(85:129), placeholder='@{...}'", "FoldRegion -(159:183), placeholder='{...}'"),
205+
assertEquals(List.of("FoldRegion -(12:27), placeholder='(...)'", "FoldRegion -(47:70), placeholder='(...)'", "FoldRegion -(95:118), placeholder='(...)'",
206+
"FoldRegion -(144:167), placeholder='(...)'", "FoldRegion -(181:204), placeholder='(...)'", "FoldRegion -(220:236), placeholder='{...}'"),
124207
ContainerUtil.map(myFixture.getEditor().getFoldingModel().getAllFoldRegions(), FoldRegion::toString));
125208
}
126209

@@ -137,4 +220,33 @@ public void testCommentBeforePackageInfo() {
137220
"FoldRegion -(28:53), placeholder='/** A cool package */'"),
138221
ContainerUtil.map(myFixture.getEditor().getFoldingModel().getAllFoldRegions(), FoldRegion::toString));
139222
}
223+
224+
public void testNestedAnnotationWithMultiline() {
225+
myFixture.addClass("""
226+
@interface Anno {
227+
NestedAnno[] value();
228+
}
229+
""");
230+
myFixture.addClass("""
231+
@interface NestedAnno {
232+
String[] value();
233+
}
234+
""");
235+
configure("""
236+
class A {
237+
@Anno({
238+
@NestedAnno({"a",
239+
"b"}),
240+
@NestedAnno({"c",
241+
"d",
242+
"e"}),
243+
@NestedAnno({})
244+
})
245+
void f() {}
246+
}
247+
""");
248+
assertEquals(List.of("FoldRegion -(17:146), placeholder='(...)'", "FoldRegion -(33:60), placeholder='(...)'",
249+
"FoldRegion -(75:122), placeholder='(...)'"),
250+
ContainerUtil.map(myFixture.getEditor().getFoldingModel().getAllFoldRegions(), FoldRegion::toString));
251+
}
140252
}

java/java-tests/testSrc/com/intellij/java/codeInsight/folding/JavaFolding9Test.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ class JavaFolding9Test : JavaFoldingTestCase() {
3434
configure(text)
3535

3636
val regions = myFixture.editor.foldingModel.allFoldRegions
37-
assertThat(regions).hasSize(4)
37+
assertThat(regions).hasSize(3)
3838

3939
assertThat(regions.map { it.startOffset to it.endOffset }).containsExactly(
4040
range(text, "/**", "*/"),
41-
range(text, "@D", ")"),
4241
range(text, "@S", ")"),
4342
range(text, "{", "}"))
4443

0 commit comments

Comments
 (0)