mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] IDEA-355777 Support implicit imports
- Support implicitly imported modules GitOrigin-RevId: dbf10158847f652936c405a1ad20ce4dd04dbba7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8ce06c83bb
commit
eee416a4e8
@@ -0,0 +1,29 @@
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Represents a module that is implicitly imported.
|
||||
*
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public final class ImplicitlyImportedModule {
|
||||
public static final @NotNull ImplicitlyImportedModule @NotNull [] EMPTY_ARRAY = new ImplicitlyImportedModule[0];
|
||||
|
||||
private final @NotNull String myModuleName;
|
||||
|
||||
private ImplicitlyImportedModule(@NotNull String moduleName) {
|
||||
myModuleName = moduleName;
|
||||
}
|
||||
|
||||
public @NotNull String getModuleName() {
|
||||
return myModuleName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ImplicitlyImportedModule create(@NotNull String moduleName) {
|
||||
return new ImplicitlyImportedModule(moduleName);
|
||||
}
|
||||
}
|
||||
@@ -426,6 +426,12 @@ public interface PsiElementFactory extends PsiJavaParserFacade, JVMElementFactor
|
||||
*/
|
||||
@NotNull PsiImportStaticStatement createImportStaticStatementFromText(@NotNull String classFullyQualifiedName, @NotNull String memberName) throws IncorrectOperationException;
|
||||
|
||||
/**
|
||||
* Creates an {@code import static} statement for importing the specified member
|
||||
* from the specified class.
|
||||
*/
|
||||
@NotNull PsiImportModuleStatement createImportModuleStatementFromText(@NotNull String moduleName) throws IncorrectOperationException;
|
||||
|
||||
/**
|
||||
* Creates a parameter list from the specified parameter names and types.
|
||||
*
|
||||
|
||||
@@ -100,4 +100,12 @@ public interface PsiJavaFile extends PsiImportHolder, PsiClassOwner, AbstractBas
|
||||
default @NotNull ImplicitlyImportedStaticMember @NotNull [] getImplicitlyImportedStaticMembers() {
|
||||
return ImplicitlyImportedStaticMember.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the array of implicitly imported modules.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
default @NotNull ImplicitlyImportedModule @NotNull [] getImplicitlyImportedModules(){
|
||||
return ImplicitlyImportedModule.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
@@ -449,6 +449,17 @@ public final class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl impleme
|
||||
return (PsiImportStaticStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiImportModuleStatement createImportModuleStatementFromText(@NotNull String moduleName)
|
||||
throws IncorrectOperationException {
|
||||
PsiJavaFile aFile = createDummyJavaFile("import module " + moduleName + ";");
|
||||
PsiImportList importList = aFile.getImportList();
|
||||
if (importList == null) throw new IncorrectOperationException("Can't create module with name: " + moduleName);
|
||||
PsiImportModuleStatement[] statements = importList.getImportModuleStatements();
|
||||
if (statements.length != 1) throw new IncorrectOperationException("Created more than one module with name: " + moduleName);
|
||||
return (PsiImportModuleStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statements[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiParameterList createParameterList(String @NotNull [] names, PsiType @NotNull [] types) throws IncorrectOperationException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -45,6 +45,7 @@ import java.util.*;
|
||||
public final class PsiImplUtil {
|
||||
private static final Logger LOG = Logger.getInstance(PsiImplUtil.class);
|
||||
private static final String JAVA_IO_IO = "java.io.IO";
|
||||
private static final String JAVA_BASE = "java.base";
|
||||
|
||||
private PsiImplUtil() { }
|
||||
|
||||
@@ -871,4 +872,25 @@ public final class PsiImplUtil {
|
||||
|
||||
return staticImports.toArray(ImplicitlyImportedStaticMember.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the implicit static imports for the given file.
|
||||
*
|
||||
* @param file the file for which to retrieve implicit static imports
|
||||
* @return an array of static members representing the implicit static imports
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public static @NotNull ImplicitlyImportedModule @NotNull[] getImplicitlyImportedModules(@NotNull PsiFile file) {
|
||||
List<ImplicitlyImportedModule> modules = new ArrayList<>();
|
||||
|
||||
// import module java.base; 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) {
|
||||
modules.add(ImplicitlyImportedModule.create(JAVA_BASE));
|
||||
}
|
||||
}
|
||||
|
||||
return modules.toArray(ImplicitlyImportedModule.EMPTY_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,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 final CachedValue<List<PsiImportModuleStatement>> myCachedImplicitImportModuleStatements;
|
||||
private volatile String myPackageName;
|
||||
|
||||
protected PsiJavaFileBaseImpl(@NotNull IElementType elementType, @NotNull IElementType contentElementType, @NotNull FileViewProvider viewProvider) {
|
||||
@@ -69,6 +70,10 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
|
||||
List<PsiImportStaticStatement> statements = createImplicitImportStaticStatements();
|
||||
return Result.create(statements, this.getContainingFile());
|
||||
}, false);
|
||||
myCachedImplicitImportModuleStatements = cachedValuesManager.createCachedValue(() -> {
|
||||
List<PsiImportModuleStatement> statements = createImplicitImportModuleStatements();
|
||||
return Result.create(statements, this.getContainingFile());
|
||||
}, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -405,7 +410,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
|
||||
}
|
||||
|
||||
private boolean processModules(@NotNull ResolveState state, @NotNull PsiElement place, @NotNull PsiScopeProcessor processor) {
|
||||
for (PsiImportModuleStatement statement : getImportModuleStatements()) {
|
||||
for (PsiImportModuleStatement statement : ContainerUtil.append(getImplicitImportModuleStatements(), getImportModuleStatements())) {
|
||||
PsiElement resolved = statement.resolve();
|
||||
if (resolved != null) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, statement);
|
||||
@@ -572,6 +577,11 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
|
||||
return PsiImplUtil.getImplicitStaticImports(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ImplicitlyImportedModule @NotNull [] getImplicitlyImportedModules() {
|
||||
return PsiImplUtil.getImplicitlyImportedModules(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCaches() {
|
||||
super.clearCaches();
|
||||
@@ -589,6 +599,11 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
|
||||
return myCachedImplicitImportStaticStatements.getValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<PsiImportModuleStatement> getImplicitImportModuleStatements() {
|
||||
return myCachedImplicitImportModuleStatements.getValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<PsiImportStaticStatement> createImplicitImportStaticStatements() {
|
||||
PsiElementFactory factory = PsiElementFactory.getInstance(getProject());
|
||||
@@ -596,6 +611,12 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
|
||||
member -> factory.createImportStaticStatementFromText(member.getContainingClass(), member.getMemberName()));
|
||||
}
|
||||
|
||||
private List<PsiImportModuleStatement> createImplicitImportModuleStatements() {
|
||||
PsiElementFactory factory = PsiElementFactory.getInstance(getProject());
|
||||
return ContainerUtil.map(getImplicitlyImportedModules(),
|
||||
mod -> factory.createImportModuleStatementFromText(mod.getModuleName()));
|
||||
}
|
||||
|
||||
private static final Key<String> SHEBANG_SOURCE_LEVEL = Key.create("SHEBANG_SOURCE_LEVEL");
|
||||
|
||||
private @NotNull LanguageLevel getLanguageLevelInner() {
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
void main() {
|
||||
List<String> a = new ArrayList<>();
|
||||
}
|
||||
+21
@@ -2,10 +2,13 @@
|
||||
package com.intellij.java.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.NeedsIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NormalImplicitClassCompletionTest extends NormalCompletionTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -33,4 +36,22 @@ public class NormalImplicitClassCompletionTest extends NormalCompletionTestCase
|
||||
println(<caret>);
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.ForStandardLibrary
|
||||
public void testImplicitModuleImport() {
|
||||
myFixture.configureByText("a.java", """
|
||||
void main(){
|
||||
List<String> a = new ArrayLis<caret>
|
||||
}""");
|
||||
myFixture.complete(CompletionType.BASIC, 0);
|
||||
assertEquals(List.of("ArrayList", "CopyOnWriteArrayList"), myFixture.getLookupElementStrings());
|
||||
LookupElement[] elements = myFixture.getLookupElements();
|
||||
assertNotNull(elements);
|
||||
myFixture.getLookup().setCurrentItem(elements[0]);
|
||||
myFixture.type('\n');
|
||||
myFixture.checkResult("""
|
||||
void main(){
|
||||
List<String> a = new ArrayList<>(<caret>)
|
||||
}""");
|
||||
}
|
||||
}
|
||||
|
||||
+16
-3
@@ -4,9 +4,8 @@ package com.intellij.java.codeInsight.daemon
|
||||
import com.intellij.JavaTestUtil
|
||||
import com.intellij.pom.java.JavaFeature
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.psi.PsiCallExpression
|
||||
import com.intellij.psi.PsiExpressionStatement
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import com.intellij.testFramework.IdeaTestUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
|
||||
@@ -88,6 +87,20 @@ class ImplicitClassHighlightingTest : LightJavaCodeInsightFixtureTestCase() {
|
||||
})
|
||||
}
|
||||
|
||||
fun testImplicitModuleImport() {
|
||||
IdeaTestUtil.withLevel(module, JavaFeature.IMPLICIT_IMPORT_IN_IMPLICIT_CLASSES.minimumLevel, Runnable {
|
||||
val psiFile = myFixture.configureByFile(getTestName(false) + ".java")
|
||||
myFixture.checkHighlighting()
|
||||
val statement = (psiFile as PsiJavaFile).classes[0].methods[0].body!!.statements[0] as PsiDeclarationStatement
|
||||
val variable = (statement.declaredElements[0] as PsiVariable)
|
||||
val variableType = variable.type
|
||||
assertNotNull(variableType)
|
||||
val psiClass = PsiUtil.resolveClassInClassTypeOnly(variableType)
|
||||
assertNotNull(psiClass)
|
||||
assertEquals(CommonClassNames.JAVA_UTIL_LIST, psiClass!!.qualifiedName)
|
||||
})
|
||||
}
|
||||
|
||||
private fun doTest() {
|
||||
myFixture.configureByFile(getTestName(false) + ".java")
|
||||
myFixture.checkHighlighting()
|
||||
|
||||
Reference in New Issue
Block a user