Create expect/actual: improve error hint message
#KT-33754 Fixed
This commit is contained in:
@@ -24,13 +24,10 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.makeActual
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
|
||||
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.TypeAccessibilityChecker
|
||||
import org.jetbrains.kotlin.idea.refactoring.getExpressionShortText
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.hasPrivateModifier
|
||||
import org.jetbrains.kotlin.idea.util.liftToExpected
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
@@ -118,16 +115,13 @@ class CreateExpectedClassFix(
|
||||
) : CreateExpectedFix<KtClassOrObject>(klass, outerExpectedClass, commonModule, block@{ project, checker, element ->
|
||||
val originalElements = element.collectDeclarations(withSelf = false).toList()
|
||||
val existingClasses = checker.findAndApplyExistingClasses(originalElements + klass)
|
||||
if (!checker.isCorrectAndHaveNonPrivateModifier(element)) {
|
||||
showUnknownTypesError(element)
|
||||
return@block null
|
||||
}
|
||||
if (!checker.isCorrectAndHaveNonPrivateModifier(element, true)) return@block null
|
||||
|
||||
val (members, declarationsWithNonExistentClasses) = originalElements.partition {
|
||||
checker.isCorrectAndHaveNonPrivateModifier(it)
|
||||
}
|
||||
|
||||
if (!showUnknownTypesDialog(project, declarationsWithNonExistentClasses)) return@block null
|
||||
if (!showUnknownTypeInDeclarationDialog(project, declarationsWithNonExistentClasses)) return@block null
|
||||
|
||||
val membersForSelection = members.filter {
|
||||
!it.isAlwaysActual() && if (it is KtParameter) it.hasValOrVar() else true
|
||||
@@ -144,15 +138,12 @@ class CreateExpectedClassFix(
|
||||
|
||||
val selectedClasses = checker.findAndApplyExistingClasses(selectedElements)
|
||||
val resultDeclarations = if (selectedClasses != existingClasses) {
|
||||
if (!checker.isCorrectAndHaveNonPrivateModifier(element)) {
|
||||
showUnknownTypesError(element)
|
||||
return@block null
|
||||
}
|
||||
if (!checker.isCorrectAndHaveNonPrivateModifier(element, true)) return@block null
|
||||
|
||||
val (resultDeclarations, withErrors) = selectedElements.partition {
|
||||
checker.isCorrectAndHaveNonPrivateModifier(it)
|
||||
}
|
||||
if (!showUnknownTypesDialog(project, withErrors)) return@block null
|
||||
if (!showUnknownTypeInDeclarationDialog(project, withErrors)) return@block null
|
||||
resultDeclarations
|
||||
} else
|
||||
selectedElements
|
||||
@@ -177,7 +168,10 @@ private fun TypeAccessibilityChecker.findAndApplyExistingClasses(elements: Colle
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnknownTypesDialog(project: Project, declarationsWithNonExistentClasses: Collection<KtNamedDeclaration>): Boolean {
|
||||
private fun showUnknownTypeInDeclarationDialog(
|
||||
project: Project,
|
||||
declarationsWithNonExistentClasses: Collection<KtNamedDeclaration>
|
||||
): Boolean {
|
||||
if (declarationsWithNonExistentClasses.isEmpty()) return true
|
||||
val message = escapeXml(
|
||||
declarationsWithNonExistentClasses.joinToString(
|
||||
@@ -195,17 +189,6 @@ private fun showUnknownTypesDialog(project: Project, declarationsWithNonExistent
|
||||
)
|
||||
}
|
||||
|
||||
private fun showUnknownTypesError(element: KtNamedDeclaration) {
|
||||
element.findExistingEditor()?.let { editor ->
|
||||
showErrorHint(
|
||||
element.project,
|
||||
editor,
|
||||
"You cannot create the expect declaration from:\n${escapeXml(getExpressionShortText(element))}",
|
||||
"Unknown types"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtDeclaration.canAddActualModifier() = when (this) {
|
||||
is KtEnumEntry, is KtClassInitializer -> false
|
||||
is KtParameter -> hasValOrVar()
|
||||
@@ -300,10 +283,7 @@ class CreateExpectedCallableMemberFix(
|
||||
targetExpectedClass: KtClassOrObject?,
|
||||
commonModule: Module
|
||||
) : CreateExpectedFix<KtNamedDeclaration>(declaration, targetExpectedClass, commonModule, block@{ project, checker, element ->
|
||||
if (!checker.isCorrectAndHaveNonPrivateModifier(element)) {
|
||||
showUnknownTypesError(element)
|
||||
return@block null
|
||||
}
|
||||
if (!checker.isCorrectAndHaveNonPrivateModifier(element, true)) return@block null
|
||||
val descriptor = element.toDescriptor() as? CallableMemberDescriptor
|
||||
checker.existingTypeNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty()
|
||||
descriptor?.let {
|
||||
@@ -317,6 +297,3 @@ class CreateExpectedCallableMemberFix(
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
private fun TypeAccessibilityChecker.isCorrectAndHaveNonPrivateModifier(declaration: KtNamedDeclaration): Boolean =
|
||||
!declaration.hasPrivateModifier() && checkAccessibility(declaration)
|
||||
@@ -24,14 +24,13 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObj
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
||||
import org.jetbrains.kotlin.idea.quickfix.TypeAccessibilityChecker
|
||||
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.idea.util.hasInlineModifier
|
||||
import org.jetbrains.kotlin.idea.util.isEffectivelyActual
|
||||
import org.jetbrains.kotlin.idea.util.mustHaveValOrVar
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -379,3 +378,35 @@ class KotlinTypeInaccessibleException(fqNames: Collection<FqName?>) : Exception(
|
||||
|
||||
fun KtNamedDeclaration.isAlwaysActual(): Boolean = safeAs<KtParameter>()?.parent?.parent?.safeAs<KtPrimaryConstructor>()
|
||||
?.mustHaveValOrVar() ?: false
|
||||
|
||||
|
||||
fun TypeAccessibilityChecker.isCorrectAndHaveNonPrivateModifier(declaration: KtNamedDeclaration, showErrorHint: Boolean = false): Boolean {
|
||||
if (declaration.hasPrivateModifier()) {
|
||||
if (showErrorHint) showInaccessibleDeclarationError(declaration, "The declaration has a private modifier")
|
||||
return false
|
||||
}
|
||||
|
||||
if (!showErrorHint) return checkAccessibility(declaration)
|
||||
|
||||
val types = incorrectTypes(declaration).ifEmpty { return true }
|
||||
showInaccessibleDeclarationError(
|
||||
declaration,
|
||||
"Some types are not accessible from ${targetModule.name}:\n" + TypeAccessibilityChecker.typesToString(
|
||||
types
|
||||
)
|
||||
)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun showInaccessibleDeclarationError(element: KtNamedDeclaration, message: String) {
|
||||
element.findExistingEditor()?.let { editor ->
|
||||
showErrorHint(element.project, editor, message, "Inaccessible declaration")
|
||||
}
|
||||
}
|
||||
|
||||
fun TypeAccessibilityChecker.Companion.typesToString(types: Collection<FqName?>, separator: CharSequence = "\n"): String {
|
||||
return types.toSet().joinToString(separator = separator) {
|
||||
it?.shortName()?.asString() ?: "Unknown type"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected class in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,class A
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some,A
|
||||
// DISABLE-ERRORS
|
||||
|
||||
interface Some
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: Some){...}
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
class Some
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<T>) = TODO()
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
interface Some
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<Some>){...}
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
class Some
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<T>){...}
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
interface Some
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<T>){...}
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
interface Some
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected property in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,actual val foo: Some = TODO()
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
interface Some
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected property in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,actual val <T>Some<T>.foo: Some<T> get() = TODO()
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some
|
||||
// DISABLE-ERRORS
|
||||
|
||||
class Some<T>
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected property in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,actual val <T: A> Some<T>.foo: Some<T> get() = TODO()
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,A
|
||||
// DISABLE-ERRORS
|
||||
interface A
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module testModule_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo() = ""
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,SomeString
|
||||
// DISABLE-ERRORS
|
||||
|
||||
typealias SomeString = String
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module proj_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun createList() = ArrayList()
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from proj_Common:,ArrayList
|
||||
// DISABLE-ERRORS
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Create expected function in common module proj_Common" "true"
|
||||
// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun createList() = ArrayList()
|
||||
// SHOULD_FAIL_WITH: Some types are not accessible from proj_Common:,ArrayList
|
||||
// DISABLE-ERRORS
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
Reference in New Issue
Block a user