Create header implementation fix: check import directive, change / add it if needed
This commit is contained in:
+38
-5
@@ -30,13 +30,11 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
import org.jetbrains.kotlin.idea.core.*
|
||||||
import org.jetbrains.kotlin.idea.core.TemplateKind
|
|
||||||
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate
|
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
|
import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
@@ -66,6 +64,20 @@ sealed class CreateHeaderImplementationFix<out D : KtNamedDeclaration>(
|
|||||||
val generated = factory.generateIt(project, element) ?: return
|
val generated = factory.generateIt(project, element) ?: return
|
||||||
|
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
|
if (implFile.packageDirective?.fqName != file.packageDirective?.fqName &&
|
||||||
|
implFile.declarations.isEmpty()) {
|
||||||
|
val packageDirective = file.packageDirective
|
||||||
|
packageDirective?.let {
|
||||||
|
val oldPackageDirective = implFile.packageDirective
|
||||||
|
val newPackageDirective = factory.createPackageDirective(it.fqName)
|
||||||
|
if (oldPackageDirective != null) {
|
||||||
|
oldPackageDirective.replace(newPackageDirective)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
implFile.add(newPackageDirective)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
val implDeclaration = implFile.add(generated) as KtElement
|
val implDeclaration = implFile.add(generated) as KtElement
|
||||||
val reformatted = CodeStyleManager.getInstance(project).reformat(implDeclaration)
|
val reformatted = CodeStyleManager.getInstance(project).reformat(implDeclaration)
|
||||||
ShortenReferences.DEFAULT.process(reformatted as KtElement)
|
ShortenReferences.DEFAULT.process(reformatted as KtElement)
|
||||||
@@ -93,7 +105,28 @@ sealed class CreateHeaderImplementationFix<out D : KtNamedDeclaration>(
|
|||||||
implModule, headerPackage?.qualifiedName ?: "", null, false
|
implModule, headerPackage?.qualifiedName ?: "", null, false
|
||||||
) ?: return null
|
) ?: return null
|
||||||
return runWriteAction {
|
return runWriteAction {
|
||||||
getOrCreateKotlinFile("$name.kt", implDirectory)
|
val fileName = "$name.kt"
|
||||||
|
val existingFile = implDirectory.findFile(fileName)
|
||||||
|
val packageDirective = declaration.containingKtFile.packageDirective
|
||||||
|
val packageName =
|
||||||
|
if (packageDirective?.packageNameExpression == null) implDirectory.getPackage()?.qualifiedName
|
||||||
|
else packageDirective.fqName.asString()
|
||||||
|
if (existingFile is KtFile) {
|
||||||
|
val existingPackageDirective = existingFile.packageDirective
|
||||||
|
if (existingFile.declarations.isNotEmpty() &&
|
||||||
|
existingPackageDirective?.fqName != packageDirective?.fqName) {
|
||||||
|
val newName = KotlinNameSuggester.suggestNameByName(name) {
|
||||||
|
implDirectory.findFile("$it.kt") == null
|
||||||
|
} + ".kt"
|
||||||
|
createKotlinFile(newName, implDirectory, packageName)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existingFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createKotlinFile(fileName, implDirectory, packageName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create header class implementation for platform JVM" "true"
|
||||||
|
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||||
|
|
||||||
|
package test.inner
|
||||||
|
|
||||||
|
header class <caret>My
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create header class implementation for platform JVM" "true"
|
||||||
|
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||||
|
|
||||||
|
package test.inner
|
||||||
|
|
||||||
|
header class My
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test.inner
|
||||||
|
|
||||||
|
impl class My
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create header class implementation for platform JVM" "true"
|
||||||
|
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||||
|
|
||||||
|
package test.inner
|
||||||
|
|
||||||
|
header class <caret>My
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create header class implementation for platform JVM" "true"
|
||||||
|
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||||
|
|
||||||
|
package test.inner
|
||||||
|
|
||||||
|
header class My
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package incorrect
|
||||||
|
|
||||||
|
class Some
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package incorrect
|
||||||
|
|
||||||
|
class Some
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test.inner
|
||||||
|
|
||||||
|
impl class My
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create header class implementation for platform JVM" "true"
|
||||||
|
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||||
|
|
||||||
|
package test.inner
|
||||||
|
|
||||||
|
header class <caret>My
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create header class implementation for platform JVM" "true"
|
||||||
|
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||||
|
|
||||||
|
package test.inner
|
||||||
|
|
||||||
|
header class My
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package incorrect
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test.inner
|
||||||
|
|
||||||
|
impl class My
|
||||||
@@ -26,10 +26,12 @@ import junit.framework.ComparisonFailure
|
|||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
||||||
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||||
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
|
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
|
||||||
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils
|
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@@ -40,7 +42,8 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
|
|||||||
|
|
||||||
override fun getTestDataPath() = testPath
|
override fun getTestDataPath() = testPath
|
||||||
|
|
||||||
protected fun shouldBeAvailableAfterExecution() = false
|
protected fun shouldBeAvailableAfterExecution(file: KtFile) =
|
||||||
|
InTextDirectivesUtils.isDirectiveDefined(file.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION")
|
||||||
|
|
||||||
private fun getActionsTexts(availableActions: List<IntentionAction>) = availableActions.map { it.text }
|
private fun getActionsTexts(availableActions: List<IntentionAction>) = availableActions.map { it.text }
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
|
|||||||
DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile)
|
DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
doAction(text, actionShouldBeAvailable, actionFileName)
|
doAction(text, actionShouldBeAvailable, actionFileName, actionFile)
|
||||||
|
|
||||||
if (actionShouldBeAvailable) {
|
if (actionShouldBeAvailable) {
|
||||||
val testDirectory = File(testPath)
|
val testDirectory = File(testPath)
|
||||||
@@ -79,7 +82,9 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
|
|||||||
try {
|
try {
|
||||||
val editedFile = allFilesInProject.find {
|
val editedFile = allFilesInProject.find {
|
||||||
it.name.toLowerCase() == file.name.removeSuffix(".after").toLowerCase()
|
it.name.toLowerCase() == file.name.removeSuffix(".after").toLowerCase()
|
||||||
}!!
|
} ?: allFilesInProject.mapNotNull {
|
||||||
|
it.containingDirectory?.findFile(file.name.removeSuffix(".after"))
|
||||||
|
}.single()
|
||||||
setActiveEditor(editedFile.findExistingEditor() ?: createEditor(editedFile.virtualFile))
|
setActiveEditor(editedFile.findExistingEditor() ?: createEditor(editedFile.virtualFile))
|
||||||
checkResultByFile(file.relativeTo(testDirectory).path)
|
checkResultByFile(file.relativeTo(testDirectory).path)
|
||||||
}
|
}
|
||||||
@@ -105,7 +110,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
|
|||||||
|
|
||||||
// TODO: merge with AbstractQuickFixMultiFileTest
|
// TODO: merge with AbstractQuickFixMultiFileTest
|
||||||
|
|
||||||
fun doAction(text: String, actionShouldBeAvailable: Boolean, testFilePath: String) {
|
fun doAction(text: String, actionShouldBeAvailable: Boolean, testFilePath: String, actionFile: KtFile) {
|
||||||
val pattern = if (text.startsWith("/"))
|
val pattern = if (text.startsWith("/"))
|
||||||
Pattern.compile(text.substring(1, text.length - 1))
|
Pattern.compile(text.substring(1, text.length - 1))
|
||||||
else
|
else
|
||||||
@@ -140,7 +145,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
|
|||||||
UIUtil.dispatchAllInvocationEvents()
|
UIUtil.dispatchAllInvocationEvents()
|
||||||
|
|
||||||
|
|
||||||
if (!shouldBeAvailableAfterExecution()) {
|
if (!shouldBeAvailableAfterExecution(actionFile)) {
|
||||||
val afterAction = findActionByPattern(pattern, getAvailableActions())
|
val afterAction = findActionByPattern(pattern, getAvailableActions())
|
||||||
|
|
||||||
if (afterAction != null) {
|
if (afterAction != null) {
|
||||||
|
|||||||
@@ -65,6 +65,21 @@ class QuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() {
|
|||||||
doMultiPlatformTest()
|
doMultiPlatformTest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPackage() {
|
||||||
|
doMultiPlatformTest()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPackageIncorrect() {
|
||||||
|
doMultiPlatformTest()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPackageIncorrectEmpty() {
|
||||||
|
doMultiPlatformTest()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNested() {
|
fun testNested() {
|
||||||
doMultiPlatformTest()
|
doMultiPlatformTest()
|
||||||
|
|||||||
Reference in New Issue
Block a user