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