Code simplifications

This commit is contained in:
Valentin Kipyatkov
2015-10-14 22:35:56 +03:00
parent 78ac41a676
commit 9bb159d4bc
2 changed files with 62 additions and 79 deletions
@@ -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())