|
16 | 16 | import com.intellij.java.language.impl.psi.impl.source.PsiClassImpl; |
17 | 17 | import com.intellij.java.language.impl.psi.impl.source.PsiExtensibleClass; |
18 | 18 | import com.intellij.java.language.impl.psi.scope.processor.MethodsProcessor; |
| 19 | +import com.intellij.java.language.impl.psi.util.JavaPsiRecordUtil; |
19 | 20 | import com.intellij.java.language.psi.*; |
20 | 21 | import com.intellij.java.language.psi.util.PsiUtil; |
21 | 22 | import consulo.annotation.access.RequiredReadAction; |
|
36 | 37 | import org.jspecify.annotations.Nullable; |
37 | 38 |
|
38 | 39 | import java.util.*; |
| 40 | +import java.util.function.Predicate; |
| 41 | +import java.util.stream.Collectors; |
39 | 42 |
|
40 | 43 | import static consulo.util.lang.ObjectUtil.assertNotNull; |
41 | 44 | import static java.util.Arrays.asList; |
@@ -431,24 +434,100 @@ public void setMirror(TreeElement element) throws InvalidMirrorException { |
431 | 434 | setMirrorIfPresent(getDocComment(), mirror.getDocComment()); |
432 | 435 |
|
433 | 436 | PsiModifierList modifierList = getModifierList(); |
434 | | - if (modifierList != null) { |
| 437 | + if (modifierList != null && mirror.getModifierList() != null) { |
435 | 438 | setMirror(modifierList, mirror.getModifierList()); |
436 | 439 | } |
437 | | - setMirror(getNameIdentifier(), mirror.getNameIdentifier()); |
438 | | - setMirror(getTypeParameterList(), mirror.getTypeParameterList()); |
439 | | - setMirror(getExtendsList(), mirror.getExtendsList()); |
440 | | - setMirror(getImplementsList(), mirror.getImplementsList()); |
| 440 | + if (mirror.getNameIdentifier() != null) { |
| 441 | + setMirrorChecked(getNameIdentifier(), mirror.getNameIdentifier()); |
| 442 | + } |
| 443 | + if (mirror.getTypeParameterList() != null) { |
| 444 | + setMirrorChecked(getTypeParameterList(), mirror.getTypeParameterList()); |
| 445 | + } |
| 446 | + if (mirror.getExtendsList() != null) { |
| 447 | + setMirrorChecked(getExtendsList(), mirror.getExtendsList()); |
| 448 | + } |
| 449 | + if (mirror.getImplementsList() != null) { |
| 450 | + setMirrorChecked(getImplementsList(), mirror.getImplementsList()); |
| 451 | + } |
441 | 452 |
|
442 | 453 | if (mirror instanceof PsiExtensibleClass extMirror) { |
443 | | - setMirrors(getOwnFields(), extMirror.getOwnFields()); |
444 | | - setMirrors(getOwnMethods(), extMirror.getOwnMethods()); |
445 | | - setMirrors(getOwnInnerClasses(), extMirror.getOwnInnerClasses()); |
| 454 | + setMirrorsChecked(getOwnFields(), extMirror.getOwnFields()); |
| 455 | + setMethodMirrorsChecked(getOwnMethods(), extMirror.getOwnMethods()); |
| 456 | + //inner classes are sorted by decompiler by method lines, so it is necessary to resort |
| 457 | + setSortedMirrorsChecked(getOwnInnerClasses(), extMirror.getOwnInnerClasses(), Comparator.comparing(PsiClass::getName)); |
446 | 458 | } |
447 | 459 | else { |
448 | | - setMirrors(getOwnFields(), asList(mirror.getFields())); |
449 | | - setMirrors(getOwnMethods(), asList(mirror.getMethods())); |
450 | | - setMirrors(getOwnInnerClasses(), asList(mirror.getInnerClasses())); |
| 460 | + setMirrorsChecked(getOwnFields(), asList(mirror.getFields())); |
| 461 | + setMethodMirrorsChecked(getOwnMethods(), asList(mirror.getMethods())); |
| 462 | + //inner classes are sorted by decompiler by method lines, so it is necessary to resort |
| 463 | + setSortedMirrorsChecked(getOwnInnerClasses(), asList(mirror.getInnerClasses()), Comparator.comparing(PsiClass::getName)); |
| 464 | + } |
| 465 | + } |
| 466 | + |
| 467 | + private static <T extends PsiElement> void setMirrorChecked(T stub, T mirror) { |
| 468 | + setMirror(stub, mirror); |
| 469 | + } |
| 470 | + |
| 471 | + private static <T extends PsiElement> void setMirrorsChecked(List<T> stubs, List<T> mirrors) { |
| 472 | + if (stubs.size() == mirrors.size()) { |
| 473 | + setMirrors(stubs, mirrors); |
| 474 | + } |
| 475 | + } |
| 476 | + |
| 477 | + private static void setMethodMirrorsChecked(List<PsiMethod> stubs, List<PsiMethod> mirrors) { |
| 478 | + if (stubs.size() == mirrors.size()) { |
| 479 | + setMirrors(stubs, mirrors); |
| 480 | + } |
| 481 | + |
| 482 | + // If the count of stubs and mirrors doesn't match, |
| 483 | + // it's probably because the default constructor (present in stubs) isn't present in the decompiled code (mirrors), |
| 484 | + // because it was removed by Fernflower's "high readability" mode. |
| 485 | + |
| 486 | + // If after removing all constructors from both stubs and mirrors, the count is still different, then we cannot help. |
| 487 | + final long nonConstructorStubCount = stubs.stream().filter(method -> !method.isConstructor()).count(); |
| 488 | + final long nonConstructorMirrorCount = mirrors.stream().filter(method -> !method.isConstructor()).count(); |
| 489 | + if (nonConstructorStubCount != nonConstructorMirrorCount) { |
| 490 | + return; |
451 | 491 | } |
| 492 | + |
| 493 | + if (stubs.size() - 1 == mirrors.size()) { |
| 494 | + Predicate<PsiMethod> isSyntheticConstructor = (PsiMethod stubMethod) -> { |
| 495 | + final PsiClass containingClass = stubMethod.getContainingClass(); |
| 496 | + if (containingClass == null) { |
| 497 | + return false; |
| 498 | + } |
| 499 | + |
| 500 | + if (containingClass.isRecord()) { |
| 501 | + return JavaPsiRecordUtil.isCanonicalConstructor(stubMethod); |
| 502 | + } |
| 503 | + else { |
| 504 | + return isDefaultConstructor(stubMethod); |
| 505 | + } |
| 506 | + }; |
| 507 | + |
| 508 | + final List<PsiMethod> stubsWithoutSyntheticConstructor = stubs.stream() |
| 509 | + .filter(isSyntheticConstructor.negate()) |
| 510 | + .collect(Collectors.toList()); |
| 511 | + |
| 512 | + setMirrors(stubsWithoutSyntheticConstructor, mirrors); |
| 513 | + } |
| 514 | + } |
| 515 | + |
| 516 | + private static boolean isDefaultConstructor(PsiMethod stubMethod) { |
| 517 | + if (!stubMethod.isConstructor()) { |
| 518 | + return false; |
| 519 | + } |
| 520 | + if (!stubMethod.getParameterList().isEmpty()) { |
| 521 | + return false; |
| 522 | + } |
| 523 | + return true; |
| 524 | + } |
| 525 | + |
| 526 | + private static <T extends PsiElement> void setSortedMirrorsChecked(List<T> stub, |
| 527 | + List<T> mirror, |
| 528 | + Comparator<? super T> comparator) { |
| 529 | + setMirrorsChecked(stub.stream().sorted(comparator).collect(Collectors.toList()), |
| 530 | + mirror.stream().sorted(comparator).collect(Collectors.toList())); |
452 | 531 | } |
453 | 532 |
|
454 | 533 | @Override |
|
0 commit comments