[java, complete, import-module] Complete the name of the current module for Module Import Declarations IDEA-355531

GitOrigin-RevId: c3eb0b36ebb8b221d6484ee4fd26927c19571464
This commit is contained in:
Aleksey Dobrynin
2024-07-25 17:15:53 +02:00
committed by intellij-monorepo-bot
parent a75d78bf10
commit 013eb83aa8
3 changed files with 101 additions and 13 deletions

View File

@@ -551,7 +551,7 @@ public final class JavaCompletionContributor extends CompletionContributor imple
}
if (!smart && parent instanceof PsiJavaModuleReferenceElement) {
addModuleReferences(parent, parameters.getOriginalFile(), result);
addModuleReferences(parent, position, parameters.getOriginalFile(), result);
}
if (JavaPatternCompletionUtil.insideDeconstructionList(parameters.getPosition())) {
@@ -1384,7 +1384,7 @@ public final class JavaCompletionContributor extends CompletionContributor imple
return added[0];
}
private static void addModuleReferences(PsiElement moduleRef, PsiFile originalFile, CompletionResultSet result) {
private static void addModuleReferences(PsiElement moduleRef, PsiElement position, PsiFile originalFile, CompletionResultSet result) {
PsiElement statement = moduleRef.getParent();
boolean withAutoModules;
if ((withAutoModules = statement instanceof PsiRequiresStatement || statement instanceof PsiImportModuleStatement) || statement instanceof PsiPackageAccessibilityStatement) {
@@ -1392,11 +1392,24 @@ public final class JavaCompletionContributor extends CompletionContributor imple
if (parent != null) {
Project project = moduleRef.getProject();
Set<String> filter = new HashSet<>();
if (parent instanceof PsiJavaModule psiJavaModule) {
filter.add(psiJavaModule.getName());
} else {
PsiJavaModule psiJavaModule = JavaModuleGraphHelper.getInstance().findDescriptorByElement(originalFile);
if (psiJavaModule != null) filter.add(psiJavaModule.getName());
Function<PsiJavaModule, String> getModuleName = psiJavaModule -> {
if (psiJavaModule == null) return null;
return psiJavaModule.getName();
};
String currentJavaModuleName = getModuleName.apply(PsiTreeUtil.getParentOfType(statement, PsiJavaModule.class));
if (currentJavaModuleName == null) currentJavaModuleName = getModuleName.apply(JavaModuleGraphHelper.getInstance().findDescriptorByElement(originalFile));
if (currentJavaModuleName == null) currentJavaModuleName = findModuleName(originalFile, position);
if (currentJavaModuleName != null) {
// "importing a module declaration" can declare its own module.
if (statement instanceof PsiImportModuleStatement) {
LookupElement lookup = TailTypeDecorator.withTail(LookupElementBuilder.create(currentJavaModuleName)
.withIcon(AllIcons.Nodes.JavaModule),
TailTypes.semicolonType());
result.addElement(lookup);
}
filter.add(currentJavaModuleName);
}
JavaModuleNameIndex index = JavaModuleNameIndex.getInstance();
@@ -1443,6 +1456,43 @@ public final class JavaCompletionContributor extends CompletionContributor imple
}
}
/**
* Searching for a module name in a broken PsiFile when import module declaration typing before the module description.
* <pre>{@code
* import module current.<caret>
* module current.module.name {
* }
* }</pre>
*
* @param originalFile The module-info.java file
* @param position the position within the file
* @return The module name if found, otherwise null.
*/
private static @Nullable String findModuleName(@NotNull PsiFile originalFile, @NotNull PsiElement position) {
if (!PsiJavaModule.MODULE_INFO_FILE.equals(originalFile.getName())) return null;
if(!(position.getNode() instanceof PsiIdentifier intellijIdeaRulezzz)) return null;
StringBuilder name = new StringBuilder();
PsiElement cursor = intellijIdeaRulezzz;
PsiElement prev = null;
while ((cursor = cursor.getNextSibling()) != null) {
if (cursor instanceof PsiErrorElement) {
name.setLength(0);
}
else if (cursor instanceof PsiIdentifier && prev instanceof PsiIdentifier) {
name.setLength(0);
name.append(cursor.getText());
}
else if (!(cursor instanceof PsiWhiteSpace)){
name.append(cursor.getText());
}
prev = cursor;
}
String result = name.toString();
if (result.trim().isEmpty()) return null;
return result;
}
private static void addAutoModuleReference(String name, PsiElement parent, Set<? super String> filter, CompletionResultSet result) {
if (PsiNameHelper.isValidModuleName(name, parent) && filter.add(name)) {
LookupElement lookup = LookupElementBuilder.create(name).withIcon(AllIcons.FileTypes.Archive);

View File

@@ -154,23 +154,59 @@ class ModuleCompletionTest : LightJava9ModulesCodeInsightFixtureTestCase() {
""")
@NeedsIndex.Full
fun testModuleImportDeclarationsBare() =
fun testModuleImportDeclarationsBare() {
addFile("module-info.java", "module current.module.name { }")
fileVariants("Test.java", """
import module <caret>
class Test { }
""".trimIndent(),
"M2", "java.base", "java.non.root", "java.se", "java.xml.bind", "java.xml.ws",
"lib.multi.release", "lib.named", "lib.auto", "lib.claimed", "all.fours", "lib.with.module.info")
"lib.multi.release", "lib.named", "lib.auto", "lib.claimed", "all.fours", "lib.with.module.info", "current.module.name")
}
@NeedsIndex.Full
fun testModuleImportDeclarationsIgnoreCurrentModule() {
fun testModuleImportDeclarationsUseOwnModule() {
addFile("module-info.java", "module current.module.name { }")
fileVariants("Test.java", """
import module current<caret>
class Test { }
fileComplete("Test.java", """
import module current.<caret>
public class Test { }
""".trimIndent(), """
import module current.module.name;
public class Test { }
""".trimIndent())
}
@NeedsIndex.Full
fun testModuleImportDeclarationsUseOwnModule2() = complete("""
import module current.<caret>
module current.module.name { }
""".trimIndent(), """
import module current.module.name;
module current.module.name { }
""".trimIndent())
@NeedsIndex.Full
fun testModuleImportDeclarationsUseOwnModule3() = complete("""
import module curr<caret>
module current
.module .name { }
""".trimIndent(), """
import module current.module.name;
module current
.module .name { }
""".trimIndent())
@NeedsIndex.Full
fun testModuleImportDeclarationsUseOwnModule4() = complete("""
import module curr<caret>
import module java.base;
module current.module.name { }
""".trimIndent(), """
import module current.module.name;
import module java.base;
module current.module.name { }
""".trimIndent())
//<editor-fold desc="Helpers.">
private fun complete(text: String, expected: String) = fileComplete("module-info.java", text, expected)
private fun fileComplete(fileName: String, text: String, expected: String) {

View File

@@ -63,8 +63,10 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
fun testModuleImportDeclarationUnresolvedModule() {
IdeaTestUtil.withLevel(module, LanguageLevel.JDK_23_PREVIEW) {
addFile("moodule-info.java", "module current.module.name {}");
highlight("Test.java", """
import module M2;
import module current.module.name;
import module <error descr="Module is not in dependencies: M3">M3</error>;
import module <error descr="Module not found: M4">M4</error>;