[java-decompiler] IDEA-352102 support dumb mode in com.intellij.psi.impl.compiled.ClsModifierListImpl.setMirror

GitOrigin-RevId: 3d2e0562124a3fcc75c6f681a475dba59c15d69d
This commit is contained in:
Mikhail Pyltsin
2024-04-18 18:14:29 +02:00
committed by intellij-monorepo-bot
parent c4cdb539be
commit 795eecd6a7
5 changed files with 139 additions and 7 deletions

View File

@@ -1,6 +1,8 @@
// 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.psi.impl.compiled;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.cache.ModifierFlags;
@@ -12,6 +14,10 @@ import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
public class ClsModifierListImpl extends ClsRepositoryPsiElement<PsiModifierListStub> implements PsiModifierList {
public ClsModifierListImpl(PsiModifierListStub stub) {
@@ -136,17 +142,54 @@ public class ClsModifierListImpl extends ClsRepositoryPsiElement<PsiModifierList
setMirrorCheckingType(element, JavaElementType.MODIFIER_LIST);
PsiAnnotation[] annotations = getAnnotations();
PsiAnnotation[] mirrorAnnotations = SourceTreeToPsiMap.<PsiModifierList>treeToPsiNotNull(element).getAnnotations();
for (PsiAnnotation annotation : annotations) {
String qualifiedName = annotation.getQualifiedName();
// Annotations could be inconsistent, as in stubs all type annotations are attached to the types
// not to modifier list
if (qualifiedName != null) {
PsiAnnotation mirror = ContainerUtil.find(mirrorAnnotations, m -> qualifiedName.equals(m.getQualifiedName()));
// Annotations could be inconsistent, as in stubs all type annotations are attached to the types
// not to modifier list
Map<String, PsiAnnotation> annotationByShortName = getAnnotationByShortName(annotations);
Map<String, PsiAnnotation> mirrorAnnotationByShortName = getAnnotationByShortName(mirrorAnnotations);
if (!annotationByShortName.containsKey(null) &&
!mirrorAnnotationByShortName.containsKey(null) &&
annotationByShortName.size() == annotations.length &&
mirrorAnnotationByShortName.size() == mirrorAnnotations.length) {
//it is possible to work with short name without resolving
for (Map.Entry<String, PsiAnnotation> annotationEntry : annotationByShortName.entrySet()) {
String key = annotationEntry.getKey();
PsiAnnotation mirror = mirrorAnnotationByShortName.get(key);
if (mirror != null) {
PsiAnnotation annotation = annotationEntry.getValue();
setMirror(annotation, mirror);
}
}
return;
}
DumbService.getInstance(getProject()).runWithAlternativeResolveEnabled(() -> {
//necessary to use AlternativeResolver, because of getQualifiedName()
for (PsiAnnotation annotation : annotations) {
String qualifiedName = annotation.getQualifiedName();
if (qualifiedName != null) {
PsiAnnotation mirror = ContainerUtil.find(mirrorAnnotations, m -> qualifiedName.equals(m.getQualifiedName()));
if (mirror != null) {
setMirror(annotation, mirror);
}
}
}
});
}
@NotNull
private static Map<String, PsiAnnotation> getAnnotationByShortName(@NotNull PsiAnnotation @NotNull [] annotations) {
HashMap<String, PsiAnnotation> result = new HashMap<>();
for (@NotNull PsiAnnotation annotation : annotations) {
result.put(getAnnotationReferenceShortName(annotation), annotation);
}
return result;
}
private static @Nullable String getAnnotationReferenceShortName(@NotNull PsiAnnotation annotation) {
PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement == null) return null;
String name = referenceElement.getReferenceName();
if (name == null) return null;
return StringUtil.getShortName(name);
}
@Override

View File

@@ -0,0 +1,31 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package com.demo;
public class FieldWithSimilarAnnotation {
private static final long serialVersionUID = -1L;
@javax.validation.constraints.NotNull(groups = {com.demo.SupplierSubmit.class})
@io.swagger.v3.oas.annotations.media.Schema(description = "desc")
@com.demo.NotNull
private java.lang.@javax.validation.constraints.NotNull(groups = {com.demo.SupplierSubmit.class}) Long id;
protected FieldWithSimilarAnnotation(com.demo.FieldWithSimilarAnnotation.FieldWithSimilarAnnotationBuilder<?,?> b) { /* compiled code */ }
public static com.demo.FieldWithSimilarAnnotation.FieldWithSimilarAnnotationBuilder<?,?> builder() { /* compiled code */ }
public java.lang.Long getId() { /* compiled code */ }
public void setId(java.lang.Long id) { /* compiled code */ }
public java.lang.String toString() { /* compiled code */ }
public boolean equals(java.lang.Object o) { /* compiled code */ }
protected boolean canEqual(java.lang.Object other) { /* compiled code */ }
public int hashCode() { /* compiled code */ }
public FieldWithSimilarAnnotation() { /* compiled code */ }
}

View File

@@ -0,0 +1,24 @@
package com.demo;
//
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import javax.validation.constraints.NotNull;
@SuperBuilder
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class FieldWithSimilarAnnotation {
private static final long serialVersionUID = -1L;
@com.demo.NotNull
@NotNull(groups = {SupplierSubmit.class})
@Schema(description ="desc")
private Long id;
}

View File

@@ -16,7 +16,9 @@ import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.psi.impl.compiled.InnerClassSourceStrategy;
import com.intellij.psi.impl.compiled.StubBuildingVisitor;
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl;
import com.intellij.testFramework.DumbModeTestUtils;
import com.intellij.testFramework.LightIdeaTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.ClassReader;
import java.io.File;
@@ -62,6 +64,30 @@ public class ClsMirrorBuildingTest extends LightIdeaTestCase {
public void testInheritFromDollar$1() { doTest(); }
public void testSealed() { doTest(); }
public void testCompanyDO() { doTest(); }
public void testCompanyDOInDumbMode() {
testDumbMode("CompanyDO");
}
public void testFieldWithSimilarAnnotation() {
testDumbMode("FieldWithSimilarAnnotation");
}
private void testDumbMode(String testName) {
String testDir = getTestDataDir();
String clsPath = getClsPath(testName, testDir);
String txtPath = getTxtPath(testName, testDir);
VirtualFile file = (clsPath.contains("!/") ? StandardFileSystems.jar() : StandardFileSystems.local()).refreshAndFindFileByPath(clsPath);
assertNotNull(clsPath, file);
DumbModeTestUtils.runInDumbModeSynchronously(getProject(), () -> {
assertSameLinesWithFile(txtPath, ClsFileImpl.decompile(file).toString());
PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
if (psiFile instanceof PsiCompiledElement compiledElement) {
PsiElement mirror = compiledElement.getMirror();
assertNotNull(mirror);
}
});
}
public void testTextPsiMismatch() {
CommonCodeStyleSettings.IndentOptions options = CodeStyle.getSettings(getProject()).getIndentOptions(JavaFileType.INSTANCE);
@@ -187,7 +213,15 @@ public class ClsMirrorBuildingTest extends LightIdeaTestCase {
private static void doTest(String name) {
String testDir = getTestDataDir();
doTest(testDir + "pkg/" + name + ".class", testDir + name + ".txt");
doTest(getClsPath(name, testDir), getTxtPath(name, testDir));
}
private static @NotNull String getTxtPath(String name, String testDir) {
return testDir + name + ".txt";
}
private static @NotNull String getClsPath(String name, String testDir) {
return testDir + "pkg/" + name + ".class";
}
private static void doTest(String clsPath, String txtPath) {