Quick fix for module is absent in module-info requirements (KT-20108)
#KT-20108 Fixed
This commit is contained in:
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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 org.jetbrains.kotlin.idea.test
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.testFramework.EditorTestUtil
|
||||||
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
|
import com.intellij.testFramework.VfsTestUtil
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinMultiModuleJava9ProjectDescriptor.ModuleDescriptor
|
||||||
|
|
||||||
|
abstract class KotlinLightJava9ModulesCodeInsightFixtureTestCase : KotlinLightCodeInsightFixtureTestCase() {
|
||||||
|
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinMultiModuleJava9ProjectDescriptor
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
KotlinMultiModuleJava9ProjectDescriptor.cleanupSourceRoots()
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun addFile(path: String, text: String, module: ModuleDescriptor = ModuleDescriptor.MAIN): VirtualFile =
|
||||||
|
VfsTestUtil.createFile(module.root(), path, text)
|
||||||
|
|
||||||
|
protected fun addKotlinFile(path: String, @Language("kotlin") text: String, module: ModuleDescriptor = ModuleDescriptor.MAIN): VirtualFile =
|
||||||
|
addFile(path, text.toTestData(), module)
|
||||||
|
|
||||||
|
protected fun addJavaFile(path: String, @Language("java") text: String, module: ModuleDescriptor = ModuleDescriptor.MAIN): VirtualFile =
|
||||||
|
addFile(path, text.toTestData(), module)
|
||||||
|
|
||||||
|
protected fun moduleInfo(@Language("JAVA") text: String, module: ModuleDescriptor = ModuleDescriptor.MAIN) =
|
||||||
|
addFile("module-info.java", text.toTestData(), module)
|
||||||
|
|
||||||
|
protected fun checkModuleInfo(@Language("JAVA") text: String) =
|
||||||
|
myFixture.checkResult("module-info.java", text.toTestData(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val IDENTIFIER_CARET = "CARET"
|
||||||
|
private const val COMMENT_CARET_CHAR = "/*|*/"
|
||||||
|
private const val COMMENT_CARET = "/*CARET*/"
|
||||||
|
private val ADDITIONAL_CARET_MARKERS = arrayOf(IDENTIFIER_CARET, COMMENT_CARET_CHAR, COMMENT_CARET)
|
||||||
|
|
||||||
|
private fun String.toTestData(): String =
|
||||||
|
ADDITIONAL_CARET_MARKERS.fold(trimIndent()) { result, marker -> result.replace(marker, EditorTestUtil.CARET_TAG, ignoreCase = true) }
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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 org.jetbrains.kotlin.idea.test
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.runWriteAction
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.module.ModuleManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
|
import com.intellij.openapi.roots.*
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.vfs.ex.temp.TempFileSystem
|
||||||
|
import com.intellij.pom.java.LanguageLevel
|
||||||
|
import com.intellij.testFramework.LightPlatformTestCase
|
||||||
|
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
|
||||||
|
import org.jetbrains.jps.model.java.JavaSourceRootType
|
||||||
|
import org.jetbrains.kotlin.test.TestJdkKind
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependencies: 'main' -> 'm2', 'main' -> 'm4', 'main' -> 'm5', 'main' -> 'm6' => 'm7'
|
||||||
|
*/
|
||||||
|
object KotlinMultiModuleJava9ProjectDescriptor : DefaultLightProjectDescriptor() {
|
||||||
|
enum class ModuleDescriptor(internal val moduleName: String, internal val rootName: String) {
|
||||||
|
// Dependent for: none, Depends on: M2, M4, M5, M6
|
||||||
|
MAIN(TEST_MODULE_NAME, "/not_used/"),
|
||||||
|
|
||||||
|
// Dependent for: MAIN, Depends on: none
|
||||||
|
M2("${TEST_MODULE_NAME}_m2", "src_m2"),
|
||||||
|
|
||||||
|
// Dependent for: none, Depends on: none
|
||||||
|
M3("${TEST_MODULE_NAME}_m3", "src_m3"),
|
||||||
|
|
||||||
|
// Dependent for: MAIN, Depends on: none
|
||||||
|
M4("${TEST_MODULE_NAME}_m4", "src_m4"),
|
||||||
|
|
||||||
|
// Dependent for: MAIN, Depends on: none
|
||||||
|
M5("${TEST_MODULE_NAME}_m5", "src_m5"),
|
||||||
|
|
||||||
|
// Dependent for: MAIN, Depends on: M7
|
||||||
|
M6("${TEST_MODULE_NAME}_m6", "src_m6"),
|
||||||
|
|
||||||
|
// Dependent for: M6, Depends on: none
|
||||||
|
M7("${TEST_MODULE_NAME}_m7", "src_m7");
|
||||||
|
|
||||||
|
fun root(): VirtualFile =
|
||||||
|
if (this == MAIN) LightPlatformTestCase.getSourceRoot() else TempFileSystem.getInstance().findFileByPath("/$rootName")!!
|
||||||
|
|
||||||
|
fun testRoot(): VirtualFile? =
|
||||||
|
if (this == MAIN) TempFileSystem.getInstance().findFileByPath("/test_src")!! else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSdk(): Sdk = PluginTestCaseBase.jdk(TestJdkKind.FULL_JDK_9)
|
||||||
|
|
||||||
|
override fun setUpProject(project: Project, handler: SetupHandler) {
|
||||||
|
super.setUpProject(project, handler)
|
||||||
|
|
||||||
|
runWriteAction {
|
||||||
|
val main = ModuleManager.getInstance(project).findModuleByName(TEST_MODULE_NAME)!!
|
||||||
|
|
||||||
|
val m2 = makeModule(project, ModuleDescriptor.M2)
|
||||||
|
ModuleRootModificationUtil.addDependency(main, m2)
|
||||||
|
|
||||||
|
makeModule(project, ModuleDescriptor.M3)
|
||||||
|
|
||||||
|
val m4 = makeModule(project, ModuleDescriptor.M4)
|
||||||
|
ModuleRootModificationUtil.addDependency(main, m4)
|
||||||
|
|
||||||
|
val m5 = makeModule(project, ModuleDescriptor.M5)
|
||||||
|
ModuleRootModificationUtil.addDependency(main, m5)
|
||||||
|
|
||||||
|
val m6 = makeModule(project, ModuleDescriptor.M6)
|
||||||
|
ModuleRootModificationUtil.addDependency(main, m6)
|
||||||
|
|
||||||
|
val m7 = makeModule(project, ModuleDescriptor.M7)
|
||||||
|
ModuleRootModificationUtil.addDependency(m6, m7, DependencyScope.COMPILE, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeModule(project: Project, descriptor: ModuleDescriptor): Module {
|
||||||
|
val path = FileUtil.join(FileUtil.getTempDirectory(), "${descriptor.moduleName}.iml")
|
||||||
|
val module = createModule(project, path)
|
||||||
|
val sourceRoot = createSourceRoot(module, descriptor.rootName)
|
||||||
|
createContentEntry(module, sourceRoot)
|
||||||
|
return module
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||||
|
model.getModuleExtension(LanguageLevelModuleExtension::class.java).languageLevel = LanguageLevel.JDK_1_9
|
||||||
|
if (module.name == TEST_MODULE_NAME) {
|
||||||
|
val testRoot = createSourceRoot(module, "test_src")
|
||||||
|
registerSourceRoot(module.project, testRoot)
|
||||||
|
model.addContentEntry(testRoot).addSourceFolder(testRoot, JavaSourceRootType.TEST_SOURCE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cleanupSourceRoots() = runWriteAction {
|
||||||
|
ModuleDescriptor.values().asSequence()
|
||||||
|
.filter { it != ModuleDescriptor.MAIN }
|
||||||
|
.flatMap { it.root().children.asSequence() }
|
||||||
|
.plus(ModuleDescriptor.MAIN.testRoot()!!.children.asSequence())
|
||||||
|
.forEach { it.delete(this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.projectRoots.Sdk;
|
|||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.TestOnly;
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
import org.jetbrains.kotlin.test.TestJdkKind;
|
import org.jetbrains.kotlin.test.TestJdkKind;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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 org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil
|
||||||
|
import com.intellij.codeInsight.daemon.impl.quickfix.AddRequiredModuleFix
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||||
|
|
||||||
|
class KotlinAddRequiredModuleFix {
|
||||||
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
|
val expression = diagnostic.psiElement as? KtExpression ?: return null
|
||||||
|
val javaModule = JavaModuleGraphUtil.findDescriptorByElement(expression) ?: return null
|
||||||
|
|
||||||
|
val dependDiagnostic = DiagnosticFactory.cast(diagnostic, ErrorsJvm.JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE)
|
||||||
|
val moduleName = dependDiagnostic.a
|
||||||
|
|
||||||
|
return AddRequiredModuleFix(javaModule, moduleName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -519,5 +519,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
|||||||
|
|
||||||
ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION.registerFactory(ReplaceWithArrayCallInAnnotationFix)
|
ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION.registerFactory(ReplaceWithArrayCallInAnnotationFix)
|
||||||
ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.registerFactory(SurroundWithArrayOfWithSpreadOperatorInFunctionFix)
|
ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.registerFactory(SurroundWithArrayOfWithSpreadOperatorInFunctionFix)
|
||||||
|
|
||||||
|
JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE.registerFactory(KotlinAddRequiredModuleFix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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 org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinLightJava9ModulesCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinMultiModuleJava9ProjectDescriptor.ModuleDescriptor.*
|
||||||
|
|
||||||
|
|
||||||
|
class KotlinAddRequiredModuleTest : KotlinLightJava9ModulesCodeInsightFixtureTestCase() {
|
||||||
|
private val messageM2 = QuickFixBundle.message("module.info.add.requires.name", "M_TWO")!!
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
moduleInfo("module M_TWO { exports pkgA; }", M2)
|
||||||
|
addJavaFile("pkgA/A.java", "package pkgA; public class A {}", M2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAddRequiresToModuleInfo() {
|
||||||
|
moduleInfo("module MAIN {}", MAIN)
|
||||||
|
val editedFile = addKotlinFile(
|
||||||
|
"pkgB/B.kt",
|
||||||
|
"""
|
||||||
|
package pkgB
|
||||||
|
import pkgA.A
|
||||||
|
class B(a: /*|*/A)
|
||||||
|
""",
|
||||||
|
MAIN)
|
||||||
|
myFixture.configureFromExistingVirtualFile(editedFile)
|
||||||
|
|
||||||
|
findActionAndExecute(messageM2)
|
||||||
|
assertNoErrors()
|
||||||
|
|
||||||
|
checkModuleInfo(
|
||||||
|
"""
|
||||||
|
module MAIN {
|
||||||
|
requires M_TWO;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testNoIdeaModuleDependency() {
|
||||||
|
moduleInfo("module M_THREE {}", M3)
|
||||||
|
val editedFile = addKotlinFile(
|
||||||
|
"pkgB/B.kt",
|
||||||
|
"""
|
||||||
|
package pkgB
|
||||||
|
import pkgA.A
|
||||||
|
class B(a: /*|*/A)
|
||||||
|
""",
|
||||||
|
M3)
|
||||||
|
myFixture.configureFromExistingVirtualFile(editedFile)
|
||||||
|
|
||||||
|
val actions = myFixture.filterAvailableIntentions(messageM2)
|
||||||
|
assertEmpty(actions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAddRequiresToInfoForJavaModule() {
|
||||||
|
moduleInfo("module MAIN {}", MAIN)
|
||||||
|
val editedFile = addKotlinFile(
|
||||||
|
"test.kt",
|
||||||
|
"""
|
||||||
|
fun test() {
|
||||||
|
java.util.logging./*|*/FileHandler() // <-- error; "add 'requires java.logging'" quick fix expected
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
MAIN)
|
||||||
|
myFixture.configureFromExistingVirtualFile(editedFile)
|
||||||
|
|
||||||
|
findActionAndExecute(QuickFixBundle.message("module.info.add.requires.name", "java.logging")!!)
|
||||||
|
|
||||||
|
assertNoErrors()
|
||||||
|
checkModuleInfo(
|
||||||
|
"""
|
||||||
|
module MAIN {
|
||||||
|
requires java.logging;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertNoErrors() {
|
||||||
|
myFixture.checkHighlighting(false, false, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findActionAndExecute(message: String) {
|
||||||
|
val action = myFixture.findSingleIntention(message)
|
||||||
|
assertNotNull(action)
|
||||||
|
myFixture.launchAction(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user