From dd78faedde60e2499d41f6b2be244bd8125175d4 Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Fri, 26 Sep 2025 15:46:20 +0200 Subject: [PATCH] [java-decompiler] IDEA-379703 `extends @Nullable Object` is not shown in decompiler GitOrigin-RevId: c2b80cba6397b1924fe1d655e3b1dbd9f36c2fe0 --- plugins/java-decompiler/engine/BUILD.bazel | 1 + .../intellij.java.decompiler.engine.iml | 1 + .../java/decompiler/main/ClassWriter.java | 9 ++- .../java/decompiler/SingleClassesTest.java | 3 + .../pkg/TestAnnotationExtendObjectClass.class | Bin 0 -> 762 bytes ...tAnnotationExtendObjectStaticMethods.class | Bin 0 -> 977 bytes .../pkg/TestAnnotationExtendWildcard.class | Bin 0 -> 1070 bytes .../TestAnnotationExtendObjectClass.dec | 17 +++++ ...estAnnotationExtendObjectStaticMethods.dec | 25 +++++++ .../results/TestAnnotationExtendWildcard.dec | 68 ++++++++++++++++++ .../pkg/TestAnnotationExtendObjectClass.java | 9 +++ ...stAnnotationExtendObjectStaticMethods.java | 13 ++++ .../src/pkg/TestAnnotationExtendWildcard.java | 31 ++++++++ 13 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 plugins/java-decompiler/engine/testData/classes/pkg/TestAnnotationExtendObjectClass.class create mode 100644 plugins/java-decompiler/engine/testData/classes/pkg/TestAnnotationExtendObjectStaticMethods.class create mode 100644 plugins/java-decompiler/engine/testData/classes/pkg/TestAnnotationExtendWildcard.class create mode 100644 plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectClass.dec create mode 100644 plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectStaticMethods.dec create mode 100644 plugins/java-decompiler/engine/testData/results/TestAnnotationExtendWildcard.dec create mode 100644 plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectClass.java create mode 100644 plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectStaticMethods.java create mode 100644 plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendWildcard.java diff --git a/plugins/java-decompiler/engine/BUILD.bazel b/plugins/java-decompiler/engine/BUILD.bazel index 2399fcec49ca..f9d72d5cd3fa 100644 --- a/plugins/java-decompiler/engine/BUILD.bazel +++ b/plugins/java-decompiler/engine/BUILD.bazel @@ -25,6 +25,7 @@ jvm_library( "@lib//:junit4", "@lib//:assert_j", "@lib//:jetbrains-annotations", + "@lib//:hamcrest", ] ) ### auto-generated section `build intellij.java.decompiler.engine` end diff --git a/plugins/java-decompiler/engine/intellij.java.decompiler.engine.iml b/plugins/java-decompiler/engine/intellij.java.decompiler.engine.iml index 88c1aeb4a94d..9a68a32888d3 100644 --- a/plugins/java-decompiler/engine/intellij.java.decompiler.engine.iml +++ b/plugins/java-decompiler/engine/intellij.java.decompiler.engine.iml @@ -12,5 +12,6 @@ + \ No newline at end of file diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 26e0b3299c0f..5ff32101d59c 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -1475,10 +1475,13 @@ public class ClassWriter { TargetInfo.TypeParameterTarget.extract(typeAnnotations, i).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); buffer.append(parameters.get(i)); List parameterBounds = bounds.get(i); - if (parameterBounds.size() > 1 || !"java/lang/Object".equals(parameterBounds.get(0).getValue())) { + List firstTypeAnnotations = TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, 0); + if (parameterBounds.size() > 1 || + (parameterBounds.size() == 1 && !"java/lang/Object".equals(parameterBounds.getFirst().getValue()) || + !firstTypeAnnotations.isEmpty())) { buffer.append(" extends "); - TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, 0).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); - buffer.append(ExprProcessor.getCastTypeName(parameterBounds.get(0), Collections.emptyList())); + firstTypeAnnotations.forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); + buffer.append(ExprProcessor.getCastTypeName(parameterBounds.getFirst(), Collections.emptyList())); for (int j = 1; j < parameterBounds.size(); j++) { buffer.append(" & "); TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, j).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); diff --git a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java index c4b25e26e5a7..9531ee1e288a 100644 --- a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -264,4 +264,7 @@ public class SingleClassesTest extends SingleClassesTestBase { "typeAnnotations/A", "typeAnnotations/B", "typeAnnotations/C", "typeAnnotations/D", "typeAnnotations/E", "typeAnnotations/F", "typeAnnotations/Z", "typeAnnotations/P", "typeAnnotations/S", "typeAnnotations/T"); } + @Test public void testAnnotationExtendObjectStaticMethods() { doTest("pkg/TestAnnotationExtendObjectStaticMethods"); } + @Test public void testAnnotationExtendObjectClass() { doTest("pkg/TestAnnotationExtendObjectClass"); } + @Test public void testAnnotationExtendWildcard() { doTest("pkg/TestAnnotationExtendWildcard"); } } \ No newline at end of file diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestAnnotationExtendObjectClass.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestAnnotationExtendObjectClass.class new file mode 100644 index 0000000000000000000000000000000000000000..bdfeed33e80c4169760e58ca003bf66b7328d57f GIT binary patch literal 762 zcmb7COH0E*5dJo;_F;Xr^?eb+gAX)UF|{C~AjAhY^x|n-m$)U}lw?!t&+;UA@CW## z#MxRkML`{SM zklEg8=8$LD3nSka1K#Zg!uCY0Pm~HZ*D_RR11;43XX$CcfNm2_Jo z@^~vCPsI(}JZSPr8hhl->IX?h`|bq)a2S@yu^xM0c!!e!)jZGfT*td~>V%o?a;XS< z`_BDgrJ*CKd}pUgaUS{f)aoB$hC)O7it8kzMsI4~Q3~Rd9mh@kMzEJ@-zcyCyOg2W z2$QHS&ZQx8>z^4MnCCNW+$KuPuDDQr8B0Ss(eyJqYGrFkR!8VoM6Jg*|DJ1XUnN0c z=Hy@#Ia(U?Szu;uNEXOCAHaRSiDGEyfuMyTnMIH1&hYuZ% zjFu{JyJNz+4ygP_0ZbkHk@7jUKIr7wr$%UdK({E?EebN!M>0^{B%0b3eeWQbwVaV# zDAC{dJaCw@%IsX5nXNtXh?avI2QIu$3e3f=pKK$jjeYBU3J=AEs?NbG_`%UjU zc@9}dcIEv~upjhMLL*C}AfC|o+A@LcI(cP)1+x2jm^TI*_m_R=bSlb|NQ;+8^AuERp234LVgJa6b0@NadZSaq9f5kBguc3v!?Q^F$11gl#>7@y9h(mqR+;{Zj`}^B^ab+o zo>UR43#}(G4;ksoLL?Dfle*K<+cuuv{}MxU(5vT?M|f|wW@VMRlyP8 z2~=kl&58fbt;F#KCW_Yr+g~zc^-z5>=Q`D{Y2VJ&b?14<=a+pODBDfglhl`!v84V{ z7DcYpS0%m`sI=oO>8X#}&12_(bA07Giyf5sv$&@OUKB;zGIu^#!L`u*3Gss;9xAlX z?LzO;E{y`XE^}ALJ*@D=iFf(BxEWz(O342bs|*6xuui-azNE|vJ@MVysg%o8N^hKU z<1(g7ySV^ibuQrn2@e+_ROb?EBs?M^cgrnma|u;ECW9^A@N#Y-Pq+iN7GQ48W!7$B K3Ops(!}dQj9KA&V literal 0 HcmV?d00001 diff --git a/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectClass.dec b/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectClass.dec new file mode 100644 index 000000000000..d4ce5ddf01b9 --- /dev/null +++ b/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectClass.dec @@ -0,0 +1,17 @@ +package org.example; + +import org.jetbrains.annotations.Nullable; + +public class TestAnnotationExtendObjectClass { + public static void main(String[] args) { + }// 8 +} + +class 'org/example/TestAnnotationExtendObjectClass' { + method 'main ([Ljava/lang/String;)V' { + 0 6 + } +} + +Lines mapping: +8 <-> 7 diff --git a/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectStaticMethods.dec b/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectStaticMethods.dec new file mode 100644 index 000000000000..33449ea64e8f --- /dev/null +++ b/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendObjectStaticMethods.dec @@ -0,0 +1,25 @@ +package org.example; + +import org.jetbrains.annotations.Nullable; + +public class TestAnnotationExtendObjectStaticMethods { + public static void main(String[] args) { + }// 8 + + public static native Iterable concat(Iterable var0, Iterable var1); + + public static native Iterable concat2(Iterable var0, Iterable var1); + + public static native Iterable concat3(Iterable var0, Iterable var1); + + public static native Iterable concat4(Iterable var0, Iterable var1); +} + +class 'org/example/TestAnnotationExtendObjectStaticMethods' { + method 'main ([Ljava/lang/String;)V' { + 0 6 + } +} + +Lines mapping: +8 <-> 7 diff --git a/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendWildcard.dec b/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendWildcard.dec new file mode 100644 index 000000000000..dfd352f06a45 --- /dev/null +++ b/plugins/java-decompiler/engine/testData/results/TestAnnotationExtendWildcard.dec @@ -0,0 +1,68 @@ +package org.example; + +import java.util.List; +import org.jetbrains.annotations.Nullable; + +public class TestAnnotationExtendWildcard { + public static void main(String[] args) { + }// 10 + + List getA() { + return null;// 13 + } + + List getA5() { + return null;// 17 + } + + List getA3() { + return null;// 21 + } + + List getA2() { + return null;// 25 + } + + List getA4() { + return null;// 29 + } +} + +class 'org/example/TestAnnotationExtendWildcard' { + method 'main ([Ljava/lang/String;)V' { + 0 7 + } + + method 'getA ()Ljava/util/List;' { + 0 10 + 1 10 + } + + method 'getA5 ()Ljava/util/List;' { + 0 14 + 1 14 + } + + method 'getA3 ()Ljava/util/List;' { + 0 18 + 1 18 + } + + method 'getA2 ()Ljava/util/List;' { + 0 22 + 1 22 + } + + method 'getA4 ()Ljava/util/List;' { + 0 26 + 1 26 + } +} + +Lines mapping: +10 <-> 8 +13 <-> 11 +17 <-> 15 +21 <-> 19 +25 <-> 23 +29 <-> 27 diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectClass.java b/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectClass.java new file mode 100644 index 000000000000..e8aed5aac839 --- /dev/null +++ b/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectClass.java @@ -0,0 +1,9 @@ +package org.example; + +import org.jetbrains.annotations.Nullable; + +public class TestAnnotationExtendObjectClass { + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectStaticMethods.java b/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectStaticMethods.java new file mode 100644 index 000000000000..1f4f03533634 --- /dev/null +++ b/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendObjectStaticMethods.java @@ -0,0 +1,13 @@ +package org.example; + +import org.jetbrains.annotations.Nullable; + +public class TestAnnotationExtendObjectStaticMethods { + public static void main(String[] args) { + + } + public static native Iterable concat(Iterable a, Iterable b); + public static native Iterable concat2(Iterable a, Iterable b); + public static native Iterable concat3(Iterable a, Iterable b); + public static native Iterable concat4(Iterable a, Iterable b); +} \ No newline at end of file diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendWildcard.java b/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendWildcard.java new file mode 100644 index 000000000000..ed44f811f81e --- /dev/null +++ b/plugins/java-decompiler/engine/testData/src/pkg/TestAnnotationExtendWildcard.java @@ -0,0 +1,31 @@ +package org.example; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class TestAnnotationExtendWildcard { + public static void main(String[] args) { + + } + + List getA() { + return null; + } + + List getA5() { + return null; + } + + List getA3() { + return null; + } + + List getA2() { + return null; + } + + List getA4() { + return null; + } +} \ No newline at end of file