Code simplifications
This commit is contained in:
@@ -26,17 +26,20 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.rename.inplace.MyLookupExpression
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.util.*
|
||||
|
||||
class MapPlatformClassToKotlinFix(
|
||||
@@ -57,28 +60,27 @@ class MapPlatformClassToKotlinFix(
|
||||
override fun getFamilyName() = "Change to Kotlin class"
|
||||
|
||||
public override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
val context = file.analyzeFully()
|
||||
val diagnostics = context.diagnostics
|
||||
val bindingContext = file.analyzeFully()
|
||||
|
||||
val imports = ArrayList<JetImportDirective>()
|
||||
val usages = ArrayList<JetUserType>()
|
||||
|
||||
for (diagnostic in diagnostics) {
|
||||
for (diagnostic in bindingContext.diagnostics) {
|
||||
if (diagnostic.factory !== Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN) continue
|
||||
|
||||
val refExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: continue
|
||||
val descriptor = resolveToClass(refExpr, context)
|
||||
if (descriptor == null || descriptor != platformClass) continue
|
||||
val imp = PsiTreeUtil.getParentOfType(refExpr, JetImportDirective::class.java)
|
||||
if (imp == null) {
|
||||
val type = PsiTreeUtil.getParentOfType(refExpr, JetUserType::class.java) ?: continue
|
||||
usages.add(type)
|
||||
} else {
|
||||
imports.add(imp)
|
||||
if (resolveToClass(refExpr, bindingContext) != platformClass) continue
|
||||
|
||||
val import = refExpr.getStrictParentOfType<JetImportDirective>()
|
||||
if (import != null) {
|
||||
imports.add(import)
|
||||
}
|
||||
else {
|
||||
usages.add(refExpr.getStrictParentOfType<JetUserType>() ?: continue)
|
||||
}
|
||||
}
|
||||
|
||||
for (imp in imports) {
|
||||
imp.delete()
|
||||
}
|
||||
imports.forEach { it.delete() }
|
||||
|
||||
if (usages.isEmpty()) {
|
||||
// if we are not going to replace any usages, there's no reason to continue at all
|
||||
@@ -97,7 +99,7 @@ class MapPlatformClassToKotlinFix(
|
||||
}
|
||||
|
||||
private fun replaceUsagesWithFirstClass(project: Project, usages: List<JetUserType>): List<PsiElement> {
|
||||
val replacementClass = possibleClasses.iterator().next()
|
||||
val replacementClass = possibleClasses.first()
|
||||
val replacementClassName = replacementClass.name.asString()
|
||||
val replacedElements = ArrayList<PsiElement>()
|
||||
for (usage in usages) {
|
||||
@@ -113,81 +115,62 @@ class MapPlatformClassToKotlinFix(
|
||||
return replacedElements
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val PRIMARY_USAGE = "PrimaryUsage"
|
||||
private val OTHER_USAGE = "OtherUsage"
|
||||
private val PRIMARY_USAGE = "PrimaryUsage"
|
||||
private val OTHER_USAGE = "OtherUsage"
|
||||
|
||||
private fun buildAndShowTemplate(
|
||||
project: Project, editor: Editor, file: PsiFile,
|
||||
replacedElements: Collection<PsiElement>, options: LinkedHashSet<String>) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
|
||||
private fun buildAndShowTemplate(
|
||||
project: Project, editor: Editor, file: PsiFile,
|
||||
replacedElements: Collection<PsiElement>, options: LinkedHashSet<String>
|
||||
) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
|
||||
|
||||
val primaryReplacedExpression = replacedElements.iterator().next()
|
||||
val primaryReplacedExpression = replacedElements.iterator().next()
|
||||
|
||||
val caretModel = editor.caretModel
|
||||
val oldOffset = caretModel.offset
|
||||
caretModel.moveToOffset(file.node.startOffset)
|
||||
val caretModel = editor.caretModel
|
||||
val oldOffset = caretModel.offset
|
||||
caretModel.moveToOffset(file.node.startOffset)
|
||||
|
||||
val builder = TemplateBuilderImpl(file)
|
||||
val expression = MyLookupExpression(primaryReplacedExpression.text, options, null, null, false, "Choose an appropriate Kotlin class")
|
||||
val builder = TemplateBuilderImpl(file)
|
||||
val expression = MyLookupExpression(primaryReplacedExpression.text, options, null, null, false, "Choose an appropriate Kotlin class")
|
||||
|
||||
builder.replaceElement(primaryReplacedExpression, PRIMARY_USAGE, expression, true)
|
||||
for (replacedExpression in replacedElements) {
|
||||
if (replacedExpression === primaryReplacedExpression) continue
|
||||
builder.replaceElement(replacedExpression, OTHER_USAGE, PRIMARY_USAGE, false)
|
||||
builder.replaceElement(primaryReplacedExpression, PRIMARY_USAGE, expression, true)
|
||||
for (replacedExpression in replacedElements) {
|
||||
if (replacedExpression === primaryReplacedExpression) continue
|
||||
builder.replaceElement(replacedExpression, OTHER_USAGE, PRIMARY_USAGE, false)
|
||||
}
|
||||
|
||||
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object : TemplateEditingAdapter() {
|
||||
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
||||
caretModel.moveToOffset(oldOffset)
|
||||
}
|
||||
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object : TemplateEditingAdapter() {
|
||||
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
||||
caretModel.moveToOffset(oldOffset)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val typeExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: return null
|
||||
|
||||
val context = typeExpr.analyze()
|
||||
val platformClass = resolveToClass(typeExpr, context) ?: return null
|
||||
|
||||
val possibleClasses = Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN.cast(diagnostic).a
|
||||
return MapPlatformClassToKotlinFix(typeExpr, platformClass, possibleClasses)
|
||||
}
|
||||
|
||||
private fun getImportOrUsageFromDiagnostic(diagnostic: Diagnostic): JetReferenceExpression? {
|
||||
val imp = QuickFixUtil.getParentElementOfType(diagnostic, JetImportDirective::class.java)
|
||||
val typeExpr: JetReferenceExpression?
|
||||
if (imp == null) {
|
||||
val type = QuickFixUtil.getParentElementOfType(diagnostic, JetUserType::class.java) ?: return null
|
||||
typeExpr = type.referenceExpression
|
||||
} else {
|
||||
val importRef = imp.importedReference
|
||||
if (importRef == null || importRef !is JetDotQualifiedExpression) return null
|
||||
val refExpr = (importRef as JetDotQualifiedExpression?)?.getSelectorExpression()
|
||||
if (refExpr == null || refExpr !is JetReferenceExpression) return null
|
||||
typeExpr = refExpr
|
||||
val import = diagnostic.psiElement.getNonStrictParentOfType<JetImportDirective>()
|
||||
return if (import != null) {
|
||||
import.importedReference?.getQualifiedElementSelector() as? JetReferenceExpression
|
||||
}
|
||||
return typeExpr
|
||||
}
|
||||
|
||||
fun createFactory(): JetSingleIntentionActionFactory {
|
||||
return object : JetSingleIntentionActionFactory() {
|
||||
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val typeExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: return null
|
||||
|
||||
val context = typeExpr.analyze()
|
||||
val platformClass = resolveToClass(typeExpr, context) ?: return null
|
||||
|
||||
val parametrizedDiagnostic = Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN.cast(diagnostic)
|
||||
|
||||
return MapPlatformClassToKotlinFix(typeExpr, platformClass, parametrizedDiagnostic.a)
|
||||
}
|
||||
else {
|
||||
(diagnostic.psiElement.getNonStrictParentOfType<JetUserType>() ?: return null).referenceExpression
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveToClass(referenceExpression: JetReferenceExpression, context: BindingContext): ClassDescriptor? {
|
||||
val descriptor = context.get(BindingContext.REFERENCE_TARGET, referenceExpression)
|
||||
val ambiguousTargets = context.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression)
|
||||
if (descriptor is ClassDescriptor) {
|
||||
return descriptor
|
||||
} else if (ambiguousTargets != null) {
|
||||
for (target in ambiguousTargets) {
|
||||
if (target is ClassDescriptor) {
|
||||
return target
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
return referenceExpression.mainReference.resolveToDescriptors(context).firstIsInstanceOrNull<ClassDescriptor>()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ public class QuickFixRegistrar : QuickFixContributor {
|
||||
|
||||
SMARTCAST_IMPOSSIBLE.registerFactory(CastExpressionFix.createFactoryForSmartCastImpossible())
|
||||
|
||||
PLATFORM_CLASS_MAPPED_TO_KOTLIN.registerFactory(MapPlatformClassToKotlinFix.createFactory())
|
||||
PLATFORM_CLASS_MAPPED_TO_KOTLIN.registerFactory(MapPlatformClassToKotlinFix)
|
||||
|
||||
MANY_CLASSES_IN_SUPERTYPE_LIST.registerFactory(RemoveSupertypeFix.createFactory())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user