mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] module reference completion
This commit is contained in:
@@ -18,7 +18,12 @@ package com.intellij.codeInsight.completion;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.completion.JavaKeywordCompletion.OverrideableSpace;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -36,24 +41,44 @@ class JavaModuleCompletion {
|
||||
PsiElement context = position.getParent();
|
||||
if (context instanceof PsiErrorElement) context = context.getParent();
|
||||
|
||||
addFileHeaderKeywords(position, context, result);
|
||||
|
||||
addModuleStatementKeywords(position, context, result);
|
||||
if (context instanceof PsiJavaFile) {
|
||||
addFileHeaderKeywords(position, result);
|
||||
}
|
||||
else if (context instanceof PsiJavaModule) {
|
||||
addModuleStatementKeywords(position, result);
|
||||
}
|
||||
else if (context instanceof PsiJavaModuleReferenceElement) {
|
||||
addModuleReferences(position, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addFileHeaderKeywords(PsiElement position, PsiElement context, Consumer<LookupElement> result) {
|
||||
if (context instanceof PsiJavaFile && PsiTreeUtil.prevVisibleLeaf(position) == null) {
|
||||
private static void addFileHeaderKeywords(PsiElement position, Consumer<LookupElement> result) {
|
||||
if (PsiTreeUtil.prevVisibleLeaf(position) == null) {
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.MODULE), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
}
|
||||
}
|
||||
|
||||
private static void addModuleStatementKeywords(PsiElement position, PsiElement context, Consumer<LookupElement> result) {
|
||||
if (context instanceof PsiJavaModule) {
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.REQUIRES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.EXPORTS), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.USES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.PROVIDES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
private static void addModuleStatementKeywords(PsiElement position, Consumer<LookupElement> result) {
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.REQUIRES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.EXPORTS), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.USES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.PROVIDES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
}
|
||||
|
||||
private static void addModuleReferences(PsiElement position, Consumer<LookupElement> result) {
|
||||
PsiJavaModule host = PsiTreeUtil.getParentOfType(position, PsiJavaModule.class);
|
||||
if (host != null) {
|
||||
String hostName = host.getModuleName();
|
||||
Project project = position.getProject();
|
||||
JavaModuleNameIndex index = JavaModuleNameIndex.getInstance();
|
||||
GlobalSearchScope scope = ProjectScope.getAllScope(project);
|
||||
index.processAllKeys(project, name -> {
|
||||
if (!name.equals(hostName) && index.get(name, project, scope).size() == 1) {
|
||||
result.consume(new OverrideableSpace(LookupElementBuilder.create(name), TailType.SEMICOLON));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,18 @@
|
||||
package com.intellij.codeInsight.completion
|
||||
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.MultiModuleJava9ProjectDescriptor
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
|
||||
class ModuleCompletionTest : LightFixtureCompletionTestCase() {
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = JAVA_9
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = MultiModuleJava9ProjectDescriptor
|
||||
|
||||
fun testFileHeader() = complete("<caret>", "module <caret>")
|
||||
fun testStatements1() = variants("module M { <caret> }", "requires", "exports", "uses", "provides")
|
||||
fun testStatements2() = complete("module M { requires X; ex<caret> }", "module M { requires X; exports <caret> }")
|
||||
fun testModuleRef() = complete("module M { requires M<caret> }", "module M { requires M2;<caret> }")
|
||||
|
||||
//<editor-fold desc="Helpers.">
|
||||
private fun complete(text: String, expected: String) {
|
||||
myFixture.configureByText("module-info.java", text)
|
||||
myFixture.completeBasic()
|
||||
@@ -36,4 +39,5 @@ class ModuleCompletionTest : LightFixtureCompletionTestCase() {
|
||||
val result = myFixture.completeBasic()?.map { it.lookupString }
|
||||
assertThat(result).containsExactlyInAnyOrder(*variants)
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -16,24 +16,16 @@
|
||||
package com.intellij.codeInsight.daemon
|
||||
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import com.intellij.testFramework.IdeaTestUtil
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
|
||||
import com.intellij.testFramework.MultiModuleJava9ProjectDescriptor
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
|
||||
|
||||
class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() {
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = DESCRIPTOR
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = MultiModuleJava9ProjectDescriptor
|
||||
|
||||
fun testWrongFileName() {
|
||||
myFixture.configureByText("M.java", """/* ... */ <error descr="Module declaration should be in a file named 'module-info.java'">module M</error> { }""")
|
||||
@@ -67,27 +59,6 @@ class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() {
|
||||
}
|
||||
|
||||
//<editor-fold desc="Helpers.">
|
||||
companion object {
|
||||
private val DESCRIPTOR = object : DefaultLightProjectDescriptor() {
|
||||
override fun getSdk() = IdeaTestUtil.getMockJdk18()
|
||||
|
||||
override fun setUpProject(project: Project, handler: SetupHandler) {
|
||||
super.setUpProject(project, handler)
|
||||
runWriteAction {
|
||||
val m2 = createModule(project, FileUtil.join(FileUtil.getTempDirectory(), "light_idea_test_case_m2.iml"))
|
||||
val src2 = createSourceRoot(m2, "src2")
|
||||
createContentEntry(m2, src2)
|
||||
|
||||
VfsUtil.saveText(src2.createChildData(this, "module-info.java"), "module M2 { requires M1; }")
|
||||
}
|
||||
}
|
||||
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
model.getModuleExtension(LanguageLevelModuleExtension::class.java).languageLevel = LanguageLevel.JDK_1_9
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun additionalFile(text: String) = myFixture.configureFromExistingVirtualFile(runWriteAction {
|
||||
val file = LightPlatformTestCase.getSourceRoot().createChildDirectory(this, "pkg").createChildData(this, "module-info.java")
|
||||
VfsUtil.saveText(file, text)
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.testFramework
|
||||
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
|
||||
|
||||
object MultiModuleJava9ProjectDescriptor : DefaultLightProjectDescriptor() {
|
||||
override fun getSdk(): Sdk = IdeaTestUtil.getMockJdk18()
|
||||
|
||||
override fun setUpProject(project: Project, handler: SetupHandler) {
|
||||
super.setUpProject(project, handler)
|
||||
runWriteAction {
|
||||
val m2 = createModule(project, FileUtil.join(FileUtil.getTempDirectory(), "light_idea_test_case_m2.iml"))
|
||||
val src2 = createSourceRoot(m2, "src2")
|
||||
createContentEntry(m2, src2)
|
||||
|
||||
VfsUtil.saveText(src2.createChildData(this, "module-info.java"), "module M2 { requires M1; }")
|
||||
}
|
||||
}
|
||||
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
model.getModuleExtension(LanguageLevelModuleExtension::class.java).languageLevel = LanguageLevel.JDK_1_9
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user