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.vfs.newvfs.impl.VfsRootAccess;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
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_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