ExpectActualUtils: drop missedDeclarations parameter from generateClassOrObject function
This commit is contained in:
@@ -21,25 +21,24 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
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.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||||
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.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class AddActualFix(
|
class AddActualFix(
|
||||||
actualClassOrObject: KtClassOrObject,
|
actualClassOrObject: KtClassOrObject,
|
||||||
expectedClassOrObject: KtClassOrObject,
|
|
||||||
missedDeclarations: List<KtDeclaration>
|
missedDeclarations: List<KtDeclaration>
|
||||||
) : KotlinQuickFixAction<KtClassOrObject>(actualClassOrObject) {
|
) : KotlinQuickFixAction<KtClassOrObject>(actualClassOrObject) {
|
||||||
|
|
||||||
private val expectedClassPointer = expectedClassOrObject.createSmartPointer()
|
|
||||||
|
|
||||||
private val missedDeclarationPointers = missedDeclarations.map { it.createSmartPointer() }
|
private val missedDeclarationPointers = missedDeclarations.map { it.createSmartPointer() }
|
||||||
|
|
||||||
override fun getFamilyName() = text
|
override fun getFamilyName() = text
|
||||||
@@ -48,45 +47,43 @@ class AddActualFix(
|
|||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
val element = element ?: return
|
val element = element ?: return
|
||||||
val expectedClass = expectedClassPointer.element ?: return
|
|
||||||
val missedDeclarations = missedDeclarationPointers.mapNotNull { it.element }
|
|
||||||
if (missedDeclarations.isEmpty()) return
|
|
||||||
val factory = KtPsiFactory(element)
|
val factory = KtPsiFactory(element)
|
||||||
val pureActualClass = factory.generateClassOrObject(
|
|
||||||
project, false, expectedClass,
|
val codeStyleManager = CodeStyleManager.getInstance(project)
|
||||||
missedDeclarations = missedDeclarations
|
|
||||||
)
|
|
||||||
|
|
||||||
fun PsiElement.clean() {
|
fun PsiElement.clean() {
|
||||||
val reformatted = CodeStyleManager.getInstance(project).reformat(this)
|
ShortenReferences.DEFAULT.process(codeStyleManager.reformat(this) as KtElement)
|
||||||
ShortenReferences.DEFAULT.process(reformatted as KtElement)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (declaration in pureActualClass.declarations) {
|
for (missedDeclaration in missedDeclarationPointers.mapNotNull { it.element }) {
|
||||||
element.addDeclaration(declaration).clean()
|
val actualDeclaration = when (missedDeclaration) {
|
||||||
}
|
is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, listOf(element))
|
||||||
val primaryConstructor = pureActualClass.primaryConstructor
|
is KtFunction -> missedDeclaration.toDescriptor()?.safeAs<FunctionDescriptor>()?.let {
|
||||||
if (element.primaryConstructor == null && primaryConstructor != null) {
|
generateFunction(project, false, missedDeclaration, it, element)
|
||||||
element.addAfter(primaryConstructor, element.nameIdentifier).clean()
|
}
|
||||||
|
is KtProperty -> missedDeclaration.toDescriptor()?.safeAs<PropertyDescriptor>()?.let {
|
||||||
|
generateProperty(project, false, missedDeclaration, it, element)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
} ?: continue
|
||||||
|
|
||||||
|
if (actualDeclaration is KtPrimaryConstructor) {
|
||||||
|
if (element.primaryConstructor == null)
|
||||||
|
element.addAfter(actualDeclaration, element.nameIdentifier).clean()
|
||||||
|
} else {
|
||||||
|
element.addDeclaration(actualDeclaration).clean()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
val incompatibleMap = DiagnosticFactory.cast(diagnostic, Errors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS).b
|
val missedDeclarations = DiagnosticFactory.cast(diagnostic, Errors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS).b.mapNotNull {
|
||||||
|
|
||||||
val expectedClassDescriptor = incompatibleMap.firstOrNull()?.first?.containingDeclaration as? ClassDescriptor
|
|
||||||
?: return null
|
|
||||||
val expectedClassOrObject = DescriptorToSourceUtils.descriptorToDeclaration(expectedClassDescriptor) as? KtClassOrObject
|
|
||||||
?: return null
|
|
||||||
|
|
||||||
val missedDeclarations = incompatibleMap.mapNotNull {
|
|
||||||
DescriptorToSourceUtils.descriptorToDeclaration(it.first) as? KtDeclaration
|
DescriptorToSourceUtils.descriptorToDeclaration(it.first) as? KtDeclaration
|
||||||
}
|
}.ifEmpty { return null }
|
||||||
if (missedDeclarations.isEmpty()) return null
|
|
||||||
|
|
||||||
return (diagnostic.psiElement as? KtClassOrObject)?.let {
|
return (diagnostic.psiElement as? KtClassOrObject)?.let {
|
||||||
AddActualFix(it, expectedClassOrObject, missedDeclarations)
|
AddActualFix(it, missedDeclarations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,26 +109,8 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
project: Project,
|
project: Project,
|
||||||
generateExpectClass: Boolean,
|
generateExpectClass: Boolean,
|
||||||
originalClass: KtClassOrObject,
|
originalClass: KtClassOrObject,
|
||||||
outerClasses: List<KtClassOrObject> = emptyList(),
|
outerClasses: List<KtClassOrObject> = emptyList()
|
||||||
// If null, all class declarations are missed (so none from them exists)
|
|
||||||
missedDeclarations: List<KtDeclaration>? = null
|
|
||||||
): KtClassOrObject {
|
): KtClassOrObject {
|
||||||
fun areCompatible(first: KtFunction, second: KtFunction) =
|
|
||||||
first.valueParameters.size == second.valueParameters.size &&
|
|
||||||
first.valueParameters.zip(second.valueParameters).all { (firstParam, secondParam) ->
|
|
||||||
firstParam.name == secondParam.name && firstParam.typeReference?.text == secondParam.typeReference?.text
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KtDeclaration.exists() =
|
|
||||||
missedDeclarations != null && missedDeclarations.none {
|
|
||||||
name == it.name && when (this) {
|
|
||||||
is KtConstructor<*> -> it is KtConstructor<*> && areCompatible(this, it)
|
|
||||||
is KtNamedFunction -> it is KtNamedFunction && areCompatible(this, it)
|
|
||||||
is KtProperty -> it is KtProperty || it is KtParameter && it.hasValOrVar()
|
|
||||||
else -> this.javaClass == it.javaClass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val generatedClass = createClassHeaderCopyByText(originalClass)
|
val generatedClass = createClassHeaderCopyByText(originalClass)
|
||||||
val context = originalClass.analyzeWithContent()
|
val context = originalClass.analyzeWithContent()
|
||||||
|
|
||||||
@@ -169,7 +151,8 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
generatedClass.addModifier(KtTokens.ACTUAL_KEYWORD)
|
generatedClass.addModifier(KtTokens.ACTUAL_KEYWORD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
declLoop@ for (originalDeclaration in originalClass.declarations.filter { !it.exists() }) {
|
|
||||||
|
declLoop@ for (originalDeclaration in originalClass.declarations) {
|
||||||
val descriptor = originalDeclaration.toDescriptor() ?: continue
|
val descriptor = originalDeclaration.toDescriptor() ?: continue
|
||||||
if (generateExpectClass && !originalDeclaration.isEffectivelyActual(false)) continue
|
if (generateExpectClass && !originalDeclaration.isEffectivelyActual(false)) continue
|
||||||
val generatedDeclaration: KtDeclaration = when (originalDeclaration) {
|
val generatedDeclaration: KtDeclaration = when (originalDeclaration) {
|
||||||
@@ -206,7 +189,6 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
generatedClass is KtClass
|
generatedClass is KtClass
|
||||||
&& originalPrimaryConstructor != null
|
&& originalPrimaryConstructor != null
|
||||||
&& (!generateExpectClass || originalPrimaryConstructor.hasActualModifier())
|
&& (!generateExpectClass || originalPrimaryConstructor.hasActualModifier())
|
||||||
&& !originalPrimaryConstructor.exists()
|
|
||||||
) {
|
) {
|
||||||
val descriptor = originalPrimaryConstructor.toDescriptor()
|
val descriptor = originalPrimaryConstructor.toDescriptor()
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
|
|||||||
Reference in New Issue
Block a user