Move/Change Package: Package name validation
#EA-70631 Fixed
This commit is contained in:
+1
-1
@@ -87,7 +87,7 @@ public abstract class JetSelfTargetingIntention<TElement : JetElement>(
|
|||||||
return !isIntentionBaseInspectionEnabled(project, target)
|
return !isIntentionBaseInspectionEnabled(project, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isIntentionBaseInspectionEnabled(project: Project, target: TElement): Boolean {
|
protected fun isIntentionBaseInspectionEnabled(project: Project, target: TElement): Boolean {
|
||||||
val inspection = findInspection(javaClass) ?: return false
|
val inspection = findInspection(javaClass) ?: return false
|
||||||
|
|
||||||
val key = HighlightDisplayKey.find(inspection.shortName)
|
val key = HighlightDisplayKey.find(inspection.shortName)
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
|||||||
import org.jetbrains.kotlin.idea.util.string.collapseSpaces
|
import org.jetbrains.kotlin.idea.util.string.collapseSpaces
|
||||||
import org.jetbrains.kotlin.j2k.ConverterSettings
|
import org.jetbrains.kotlin.j2k.ConverterSettings
|
||||||
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
|
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
|
||||||
|
import org.jetbrains.kotlin.name.FqNameBase
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
@@ -665,3 +666,5 @@ public fun invokeOnceOnCommandFinish(action: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun String.quoteIfNeeded(): String = if (KotlinNameSuggester.isIdentifier(this)) this else "`$this`"
|
public fun String.quoteIfNeeded(): String = if (KotlinNameSuggester.isIdentifier(this)) this else "`$this`"
|
||||||
|
|
||||||
|
public fun FqNameBase.hasIdentifiersOnly(): Boolean = pathSegments().all { KotlinNameSuggester.isIdentifier(it.asString()) }
|
||||||
+37
-11
@@ -16,22 +16,26 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.move.changePackage;
|
package org.jetbrains.kotlin.idea.refactoring.move.changePackage;
|
||||||
|
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
|
||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
import com.intellij.codeInsight.template.*
|
import com.intellij.codeInsight.template.*
|
||||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
|
||||||
import com.intellij.codeInsight.template.impl.TemplateState
|
import com.intellij.codeInsight.template.impl.TemplateState
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
import org.jetbrains.kotlin.idea.core.refactoring.hasIdentifiersOnly
|
||||||
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
|
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.psi.JetPackageDirective
|
import org.jetbrains.kotlin.psi.JetPackageDirective
|
||||||
|
|
||||||
public class ChangePackageIntention: JetSelfTargetingOffsetIndependentIntention<JetPackageDirective>(javaClass(), "Change package") {
|
public class ChangePackageIntention: JetSelfTargetingOffsetIndependentIntention<JetPackageDirective>(javaClass(), "Change package") {
|
||||||
|
companion object {
|
||||||
|
private val PACKAGE_NAME_VAR = "PACKAGE_NAME"
|
||||||
|
}
|
||||||
|
|
||||||
override fun isApplicableTo(element: JetPackageDirective) = element.getPackageNameExpression() != null
|
override fun isApplicableTo(element: JetPackageDirective) = element.getPackageNameExpression() != null
|
||||||
|
|
||||||
override fun applyTo(element: JetPackageDirective, editor: Editor) {
|
override fun applyTo(element: JetPackageDirective, editor: Editor) {
|
||||||
@@ -48,25 +52,47 @@ public class ChangePackageIntention: JetSelfTargetingOffsetIndependentIntention<
|
|||||||
val builder = TemplateBuilderImpl(file)
|
val builder = TemplateBuilderImpl(file)
|
||||||
builder.replaceElement(
|
builder.replaceElement(
|
||||||
nameExpression,
|
nameExpression,
|
||||||
|
PACKAGE_NAME_VAR,
|
||||||
object: Expression() {
|
object: Expression() {
|
||||||
override fun calculateQuickResult(context: ExpressionContext?) = TextResult(currentName)
|
override fun calculateQuickResult(context: ExpressionContext?) = TextResult(currentName)
|
||||||
override fun calculateResult(context: ExpressionContext?) = TextResult(currentName)
|
override fun calculateResult(context: ExpressionContext?) = TextResult(currentName)
|
||||||
override fun calculateLookupItems(context: ExpressionContext?) = arrayOf(LookupElementBuilder.create(currentName))
|
override fun calculateLookupItems(context: ExpressionContext?) = arrayOf(LookupElementBuilder.create(currentName))
|
||||||
}
|
},
|
||||||
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var enteredName: String? = null
|
||||||
|
var affectedRange: TextRange? = null
|
||||||
|
|
||||||
editor.getCaretModel().moveToOffset(0)
|
editor.getCaretModel().moveToOffset(0)
|
||||||
TemplateManager.getInstance(project).startTemplate(
|
TemplateManager.getInstance(project).startTemplate(
|
||||||
editor,
|
editor,
|
||||||
builder.buildInlineTemplate(),
|
builder.buildInlineTemplate(),
|
||||||
object: TemplateEditingAdapter() {
|
object: TemplateEditingAdapter() {
|
||||||
|
override fun beforeTemplateFinished(state: TemplateState?, template: Template?) {
|
||||||
|
if (state == null) return
|
||||||
|
enteredName = state.getVariableValue(PACKAGE_NAME_VAR)!!.text
|
||||||
|
affectedRange = state.getSegmentRange(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
||||||
if (!brokenOff) {
|
if (brokenOff || enteredName == null || affectedRange == null) return
|
||||||
// Restore original name and run refactoring
|
|
||||||
val packageDirective = file.getPackageDirective()!!
|
// Restore original name and run refactoring
|
||||||
val newFqName = packageDirective.getFqName()
|
|
||||||
packageDirective.setFqName(FqName(currentName))
|
val document = editor.document
|
||||||
KotlinChangePackageRefactoring(file).run(newFqName)
|
project.executeWriteCommand(text) {
|
||||||
|
document.replaceString(affectedRange!!.startOffset, affectedRange!!.endOffset, currentName)
|
||||||
}
|
}
|
||||||
|
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||||
|
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document)
|
||||||
|
|
||||||
|
if (!FqNameUnsafe(enteredName!!).hasIdentifiersOnly()) {
|
||||||
|
CodeInsightUtils.showErrorHint(project, editor, "$enteredName is not a valid package name", "Change package", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
KotlinChangePackageRefactoring(file).run(FqName(enteredName!!))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
+17
-5
@@ -17,11 +17,11 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.move.changePackage
|
package org.jetbrains.kotlin.idea.refactoring.move.changePackage
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
|
||||||
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
|
|
||||||
import org.jetbrains.kotlin.psi.JetPackageDirective
|
|
||||||
import org.jetbrains.kotlin.idea.core.getFqNameByDirectory
|
import org.jetbrains.kotlin.idea.core.getFqNameByDirectory
|
||||||
import org.jetbrains.kotlin.idea.core.packageMatchesDirectory
|
import org.jetbrains.kotlin.idea.core.packageMatchesDirectory
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.hasIdentifiersOnly
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
|
||||||
|
import org.jetbrains.kotlin.psi.JetPackageDirective
|
||||||
|
|
||||||
public class ChangePackageToMatchDirectoryIntention : JetSelfTargetingOffsetIndependentIntention<JetPackageDirective>(
|
public class ChangePackageToMatchDirectoryIntention : JetSelfTargetingOffsetIndependentIntention<JetPackageDirective>(
|
||||||
javaClass(), "", "Change file's package to match directory"
|
javaClass(), "", "Change file's package to match directory"
|
||||||
@@ -30,11 +30,23 @@ public class ChangePackageToMatchDirectoryIntention : JetSelfTargetingOffsetInde
|
|||||||
val file = element.getContainingJetFile()
|
val file = element.getContainingJetFile()
|
||||||
if (file.packageMatchesDirectory()) return false
|
if (file.packageMatchesDirectory()) return false
|
||||||
|
|
||||||
setText("Change file's package to '${file.getFqNameByDirectory().asString()}'")
|
val fqNameByDirectory = file.getFqNameByDirectory()
|
||||||
|
if (!fqNameByDirectory.hasIdentifiersOnly()) {
|
||||||
|
if (isIntentionBaseInspectionEnabled(file.project, element)) {
|
||||||
|
text = "File package doesn't match directory"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
text = "Change file's package to '${fqNameByDirectory.asString()}'"
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyTo(element: JetPackageDirective, editor: Editor) {
|
override fun applyTo(element: JetPackageDirective, editor: Editor) {
|
||||||
KotlinChangePackageRefactoring(element.getContainingJetFile()).run(element.getContainingFile().getFqNameByDirectory())
|
val file = element.getContainingJetFile()
|
||||||
|
val newFqName = file.getFqNameByDirectory()
|
||||||
|
if (!newFqName.hasIdentifiersOnly()) return
|
||||||
|
KotlinChangePackageRefactoring(file).run(newFqName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
@@ -24,8 +24,10 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectori
|
|||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import org.jetbrains.kotlin.idea.JetLanguage
|
import org.jetbrains.kotlin.idea.JetLanguage
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored
|
||||||
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.core.getPackage
|
import org.jetbrains.kotlin.idea.core.getPackage
|
||||||
import org.jetbrains.kotlin.idea.core.packageMatchesDirectory
|
import org.jetbrains.kotlin.idea.core.packageMatchesDirectory
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.hasIdentifiersOnly
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
import org.jetbrains.kotlin.idea.refactoring.move.*
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
@@ -57,6 +59,7 @@ public class MoveKotlinFileHandler : MoveFileHandler() {
|
|||||||
|
|
||||||
val newPackageName = FqNameUnsafe(newPackage.qualifiedName)
|
val newPackageName = FqNameUnsafe(newPackage.qualifiedName)
|
||||||
if (oldPackageName.asString() == newPackageName.asString()) return null
|
if (oldPackageName.asString() == newPackageName.asString()) return null
|
||||||
|
if (newPackageName != UNKNOWN_PACKAGE_FQ_NAME && !newPackageName.hasIdentifiersOnly()) return null
|
||||||
|
|
||||||
return PackageNameInfo(oldPackageName, newPackageName)
|
return PackageNameInfo(oldPackageName, newPackageName)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package p
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package q
|
||||||
|
|
||||||
|
import p.foo
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package p
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package q
|
||||||
|
|
||||||
|
import p.foo
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"mainFile": "p/main.kt",
|
||||||
|
"type": "MOVE_FILES",
|
||||||
|
"targetPackage": "p.123"
|
||||||
|
}
|
||||||
@@ -245,6 +245,12 @@ public class JetMoveTestGenerated extends AbstractJetMoveTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlin/moveFile/invalidTargetPackage/moveFileToInvalidPackage.test")
|
||||||
|
public void testKotlin_moveFile_invalidTargetPackage_MoveFileToInvalidPackage() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/invalidTargetPackage/moveFileToInvalidPackage.test");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kotlin/moveFile/moveFileToFile/moveFileToFile.test")
|
@TestMetadata("kotlin/moveFile/moveFileToFile/moveFileToFile.test")
|
||||||
public void testKotlin_moveFile_moveFileToFile_MoveFileToFile() throws Exception {
|
public void testKotlin_moveFile_moveFileToFile_MoveFileToFile() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/moveFileToFile/moveFileToFile.test");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/moveFileToFile/moveFileToFile.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user