IJ-CR-138822 [java-highlighting] IDEA-355777 Support JEP 477: implicit imports

- cache implicit static references
- extract ImplicitlyImportedStaticMember into a separate file

GitOrigin-RevId: 105a69ce72b4722f0d32d1d858c426e96b73f9c5
This commit is contained in:
Mikhail Pyltsin
2024-07-05 13:02:41 +02:00
committed by intellij-monorepo-bot
parent dc2f88d484
commit ecff6e161b
6 changed files with 75 additions and 53 deletions

View File

@@ -465,13 +465,13 @@ public final class ImportUtils {
public static class ImplicitImportChecker {
@NotNull
private final Map<String, PsiJavaFile.StaticMember> myStaticImportStatements = new HashMap<>();
private final Map<String, ImplicitlyImportedStaticMember> myStaticImportStatements = new HashMap<>();
@NotNull
private final Set<String> packages = new HashSet<>();
private ImplicitImportChecker(@NotNull PsiJavaFile file) {
for (PsiJavaFile.StaticMember imp : file.getImplicitlyImportedStaticMembers()) {
for (ImplicitlyImportedStaticMember imp : file.getImplicitlyImportedStaticMembers()) {
myStaticImportStatements.put(imp.getContainingClass(), imp);
}
packages.addAll(Arrays.asList(file.getImplicitlyImportedPackages()));
@@ -480,7 +480,7 @@ public final class ImportUtils {
public boolean isImplicitlyImported(@NotNull Import name) {
String packageOrClassName = getPackageOrClassName(name.name);
if (!name.isStatic && packages.contains(packageOrClassName)) return true;
PsiJavaFile.StaticMember base = myStaticImportStatements.get(packageOrClassName);
ImplicitlyImportedStaticMember base = myStaticImportStatements.get(packageOrClassName);
if (base != null) {
if (!name.isStatic) return false;
if (base.isOnDemand()) {
@@ -500,7 +500,7 @@ public final class ImportUtils {
}
@ApiStatus.Internal
public record Import(String name, boolean isStatic) {}
public record Import(@NotNull String name, boolean isStatic) {}
private static boolean memberReferenced(PsiMember member, PsiElement context) {
final MemberReferenceVisitor visitor = new MemberReferenceVisitor(member);

View File

@@ -100,7 +100,7 @@ public final class ImplicitToExplicitClassBackwardMigrationInspection extends Ab
if (!(containingFile instanceof PsiJavaFile psiJavaFile)) {
return;
}
PsiJavaFile.@NotNull StaticMember[] imports = PsiImplUtil.getImplicitStaticImports(psiJavaFile);
@NotNull ImplicitlyImportedStaticMember[] imports = PsiImplUtil.getImplicitStaticImports(psiJavaFile);
PsiElement replaced = implicitClass.replace(newClass);
PsiJavaFile newPsiJavaFile = PsiTreeUtil.getParentOfType(replaced, PsiJavaFile.class);
if (newPsiJavaFile == null) {
@@ -111,7 +111,7 @@ public final class ImplicitToExplicitClassBackwardMigrationInspection extends Ab
return;
}
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (PsiJavaFile.@NotNull StaticMember importMember : imports) {
for (@NotNull ImplicitlyImportedStaticMember importMember : imports) {
PsiClass psiClass = psiFacade.findClass(importMember.getContainingClass(), implicitClass.getResolveScope());
if (psiClass == null) {
continue;

View File

@@ -0,0 +1,41 @@
// 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;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Class representing a static member represented implicitly imported static members.
* if memberName is `*`, it is on demand import
*/
@ApiStatus.Experimental
public final class ImplicitlyImportedStaticMember {
public static final @NotNull ImplicitlyImportedStaticMember @NotNull [] EMPTY_ARRAY = new ImplicitlyImportedStaticMember[0];
private final @NotNull String myContainingClass;
private final @NotNull String myMemberName;
private ImplicitlyImportedStaticMember(@NotNull String containingClass, @NotNull String memberName) {
myContainingClass = containingClass;
myMemberName = memberName;
}
@NotNull
public String getContainingClass() {
return myContainingClass;
}
@NotNull
public String getMemberName() {
return myMemberName;
}
public boolean isOnDemand() {
return "*".equals(myMemberName);
}
@NotNull
public static ImplicitlyImportedStaticMember create(@NotNull String containingClass, @NotNull String memberName) {
return new ImplicitlyImportedStaticMember(containingClass, memberName);
}
}

View File

@@ -68,7 +68,10 @@ public interface PsiJavaFile extends PsiImportHolder, PsiClassOwner, AbstractBas
* implicitly imported packages (for example, java.lang).
*
* @return the array of implicitly imported package reference elements.
* @deprecated Use {@link PsiJavaFile#getImplicitlyImportedPackages()} instead
*/
@Deprecated
@ApiStatus.ScheduledForRemoval
PsiJavaCodeReferenceElement @NotNull [] getImplicitlyImportedPackageReferences();
/**
@@ -94,43 +97,7 @@ public interface PsiJavaFile extends PsiImportHolder, PsiClassOwner, AbstractBas
* @return the array of implicitly imported static members.
*/
@ApiStatus.Experimental
default @NotNull StaticMember @NotNull [] getImplicitlyImportedStaticMembers() {
return StaticMember.EMPTY_ARRAY;
}
/**
* Class representing a static member represented implicitly imported static members.
* if memberName is `*`, it is on demand import
*/
@ApiStatus.Experimental
class StaticMember {
public static final @NotNull StaticMember @NotNull [] EMPTY_ARRAY = new StaticMember[0];
private final @NotNull String myContainingClass;
private final @NotNull String myMemberName;
private StaticMember(@NotNull String containingClass, @NotNull String memberName) {
myContainingClass = containingClass;
myMemberName = memberName;
}
@NotNull
public String getContainingClass() {
return myContainingClass;
}
@NotNull
public String getMemberName() {
return myMemberName;
}
public boolean isOnDemand() {
return "*".equals(myMemberName);
}
@NotNull
public static StaticMember create(@NotNull String containingClass, @NotNull String memberName) {
return new StaticMember(containingClass, memberName);
}
default @NotNull ImplicitlyImportedStaticMember @NotNull [] getImplicitlyImportedStaticMembers() {
return ImplicitlyImportedStaticMember.EMPTY_ARRAY;
}
}

View File

@@ -854,21 +854,21 @@ public final class PsiImplUtil {
* @return an array of static members representing the implicit static imports
*/
@ApiStatus.Experimental
public static @NotNull PsiJavaFile.StaticMember @NotNull[] getImplicitStaticImports(@NotNull PsiFile file) {
List<PsiJavaFile.StaticMember> staticImports = new ArrayList<>();
public static @NotNull ImplicitlyImportedStaticMember @NotNull[] getImplicitStaticImports(@NotNull PsiFile file) {
List<ImplicitlyImportedStaticMember> staticImports = new ArrayList<>();
// java.lang.StringTemplate.STR
if (PsiUtil.isAvailable(JavaFeature.STRING_TEMPLATES, file)) {
staticImports.add(PsiJavaFile.StaticMember.create(CommonClassNames.JAVA_LANG_STRING_TEMPLATE, "STR"));
staticImports.add(ImplicitlyImportedStaticMember.create(CommonClassNames.JAVA_LANG_STRING_TEMPLATE, "STR"));
}
// java.io.IO.* for implicit classes
if (PsiUtil.isAvailable(JavaFeature.IMPLICIT_IMPORT_IN_IMPLICIT_CLASSES, file) && file instanceof PsiJavaFile) {
PsiClass[] classes = ((PsiJavaFile)file).getClasses();
if (classes.length == 1 && classes[0] instanceof PsiImplicitClass) {
staticImports.add(PsiJavaFile.StaticMember.create(JAVA_IO_IO, "*"));
staticImports.add(ImplicitlyImportedStaticMember.create(JAVA_IO_IO, "*"));
}
}
return staticImports.toArray(PsiJavaFile.StaticMember.EMPTY_ARRAY);
return staticImports.toArray(ImplicitlyImportedStaticMember.EMPTY_ARRAY);
}
}

View File

@@ -50,6 +50,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
private final CachedValue<MostlySingularMultiMap<String, ResultWithContext>> myResolveCache;
private final CachedValue<Map<String, Iterable<ResultWithContext>>> myCachedDeclarations;
private final CachedValue<List<PsiImportStaticStatement>> myCachedImplicitImportStaticStatements;
private volatile String myPackageName;
protected PsiJavaFileBaseImpl(@NotNull IElementType elementType, @NotNull IElementType contentElementType, @NotNull FileViewProvider viewProvider) {
@@ -64,6 +65,13 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
}
return Result.create(declarations, PsiModificationTracker.MODIFICATION_COUNT);
}, false);
myCachedImplicitImportStaticStatements = cachedValuesManager.createCachedValue(() -> {
List<PsiImportStaticStatement> statements = createImplicitImportStaticStatements();
if (!this.isPhysical()) {
return Result.create(statements, this.getContainingFile(), PsiModificationTracker.MODIFICATION_COUNT);
}
return Result.create(statements, PsiModificationTracker.MODIFICATION_COUNT);
}, false);
}
@Override
@@ -333,7 +341,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
}
}
}
for (PsiImportStaticStatement staticImport : ContainerUtil.append(getImplicitlyImportedStaticStatements(), getImportStaticStatements())) {
for (PsiImportStaticStatement staticImport : ContainerUtil.append(getImplicitImportStaticStatements(), getImportStaticStatements())) {
String name = staticImport.getReferenceName();
if (name != null) {
staticImports.putValue(name, staticImport);
@@ -425,7 +433,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
}
private boolean processOnDemandStaticImports(@NotNull ResolveState state, @NotNull StaticImportFilteringProcessor processor) {
for (PsiImportStaticStatement importStaticStatement : ContainerUtil.append(getImplicitlyImportedStaticStatements(), getImportStaticStatements())) {
for (PsiImportStaticStatement importStaticStatement : ContainerUtil.append(getImplicitImportStaticStatements(), getImportStaticStatements())) {
if (!importStaticStatement.isOnDemand()) continue;
PsiClass targetElement = importStaticStatement.resolveTargetClass();
if (targetElement != null) {
@@ -524,7 +532,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
}
@Override
public @NotNull StaticMember @NotNull [] getImplicitlyImportedStaticMembers() {
public @NotNull ImplicitlyImportedStaticMember @NotNull [] getImplicitlyImportedStaticMembers() {
return PsiImplUtil.getImplicitStaticImports(this);
}
@@ -540,7 +548,13 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
clearCaches();
}
private List<PsiImportStaticStatement> getImplicitlyImportedStaticStatements() {
@NotNull
private List<PsiImportStaticStatement> getImplicitImportStaticStatements() {
return myCachedImplicitImportStaticStatements.getValue();
}
@NotNull
private List<PsiImportStaticStatement> createImplicitImportStaticStatements() {
PsiElementFactory factory = PsiElementFactory.getInstance(getProject());
return ContainerUtil.map(getImplicitlyImportedStaticMembers(),
member -> factory.createImportStaticStatementFromText(member.getContainingClass(), member.getMemberName()));