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.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,13 +115,13 @@ 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).commitAllDocuments()
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document) PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
@@ -137,6 +139,7 @@ class MapPlatformClassToKotlinFix(
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() { TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object : TemplateEditingAdapter() {
override fun templateFinished(template: Template?, brokenOff: Boolean) { override fun templateFinished(template: Template?, brokenOff: Boolean) {
caretModel.moveToOffset(oldOffset) caretModel.moveToOffset(oldOffset)
@@ -144,50 +147,30 @@ class MapPlatformClassToKotlinFix(
}) })
} }
private fun getImportOrUsageFromDiagnostic(diagnostic: Diagnostic): JetReferenceExpression? { companion object : JetSingleIntentionActionFactory() {
val imp = QuickFixUtil.getParentElementOfType(diagnostic, JetImportDirective::class.java) override fun createAction(diagnostic: Diagnostic): IntentionAction? {
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
}
return typeExpr
}
fun createFactory(): JetSingleIntentionActionFactory {
return object : JetSingleIntentionActionFactory() {
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val typeExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: return null val typeExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: return null
val context = typeExpr.analyze() val context = typeExpr.analyze()
val platformClass = resolveToClass(typeExpr, context) ?: return null val platformClass = resolveToClass(typeExpr, context) ?: return null
val parametrizedDiagnostic = Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN.cast(diagnostic) val possibleClasses = Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN.cast(diagnostic).a
return MapPlatformClassToKotlinFix(typeExpr, platformClass, possibleClasses)
return MapPlatformClassToKotlinFix(typeExpr, platformClass, parametrizedDiagnostic.a)
} }
private fun getImportOrUsageFromDiagnostic(diagnostic: Diagnostic): JetReferenceExpression? {
val import = diagnostic.psiElement.getNonStrictParentOfType<JetImportDirective>()
return if (import != null) {
import.importedReference?.getQualifiedElementSelector() as? JetReferenceExpression
}
else {
(diagnostic.psiElement.getNonStrictParentOfType<JetUserType>() ?: return null).referenceExpression
} }
} }
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())