Refactoring: prepare AutoImportFix for subclassing: count suggestions in virtual method.

This commit is contained in:
Nikolay Krasko
2015-10-12 02:13:20 +03:00
parent a7519853cb
commit c84995f8dd
2 changed files with 73 additions and 67 deletions
@@ -30,6 +30,7 @@ import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.idea.JetBundle import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -57,14 +58,16 @@ public class AutoImportFix(element: KtSimpleNameExpression) : KotlinQuickFixActi
@Volatile private var anySuggestionFound: Boolean? = null @Volatile private var anySuggestionFound: Boolean? = null
private val suggestions: Collection<DeclarationDescriptor> by CachedValueProperty( public val suggestions: Collection<DeclarationDescriptor> by CachedValueProperty(
{ {
val descriptors = computeSuggestions(element) val descriptors = computeSuggestions()
anySuggestionFound = !descriptors.isEmpty() anySuggestionFound = !descriptors.isEmpty()
descriptors descriptors
}, },
{ PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount() }) { PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount() })
private fun getSupportedErrors(): Collection<DiagnosticFactory<*>> = ERRORS
override fun showHint(editor: Editor): Boolean { override fun showHint(editor: Editor): Boolean {
if (!element.isValid() || isOutdated()) return false if (!element.isValid() || isOutdated()) return false
@@ -74,7 +77,7 @@ public class AutoImportFix(element: KtSimpleNameExpression) : KotlinQuickFixActi
if (!ApplicationManager.getApplication()!!.isUnitTestMode()) { if (!ApplicationManager.getApplication()!!.isUnitTestMode()) {
val addImportAction = createAction(element.project, editor) val addImportAction = createAction(element.project, editor)
val hintText = ShowAutoImportPass.getMessage(suggestions.size() > 1, addImportAction.highestPriorityFqName.asString()) val hintText = ShowAutoImportPass.getMessage(suggestions.size > 1, addImportAction.highestPriorityFqName.asString())
HintManager.getInstance().showQuestionHint(editor, hintText, element.getTextOffset(), element.getTextRange()!!.getEndOffset(), addImportAction) HintManager.getInstance().showQuestionHint(editor, hintText, element.getTextOffset(), element.getTextRange()!!.getEndOffset(), addImportAction)
} }
@@ -100,22 +103,7 @@ public class AutoImportFix(element: KtSimpleNameExpression) : KotlinQuickFixActi
private fun createAction(project: Project, editor: Editor) = KotlinAddImportAction(project, editor, element, suggestions) private fun createAction(project: Project, editor: Editor) = KotlinAddImportAction(project, editor, element, suggestions)
companion object : JetSingleIntentionActionFactory() { public fun computeSuggestions(): Collection<DeclarationDescriptor> {
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtSimpleNameExpression>? {
// There could be different psi elements (i.e. JetArrayAccessExpression), but we can fix only JetSimpleNameExpression case
val psiElement = diagnostic.getPsiElement()
if (psiElement is KtSimpleNameExpression) {
return AutoImportFix(psiElement)
}
return null
}
override fun isApplicableForCodeFragment() = true
private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION ) { QuickFixes.getInstance().getDiagnostics(this) }
public fun computeSuggestions(element: KtSimpleNameExpression): Collection<DeclarationDescriptor> {
if (!element.isValid()) return emptyList() if (!element.isValid()) return emptyList()
val file = element.getContainingFile() as? KtFile ?: return emptyList() val file = element.getContainingFile() as? KtFile ?: return emptyList()
@@ -140,7 +128,7 @@ public class AutoImportFix(element: KtSimpleNameExpression) : KotlinQuickFixActi
val bindingContext = element.analyze(BodyResolveMode.PARTIAL) val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val diagnostics = bindingContext.getDiagnostics().forElement(element) val diagnostics = bindingContext.getDiagnostics().forElement(element)
if (!diagnostics.any { it.getFactory() in ERRORS }) return emptyList() if (!diagnostics.any { it.getFactory() in getSupportedErrors() }) return emptyList()
val resolutionScope = element.getResolutionScope(bindingContext, file.getResolutionFacade()) val resolutionScope = element.getResolutionScope(bindingContext, file.getResolutionFacade())
val containingDescriptor = resolutionScope.ownerDescriptor val containingDescriptor = resolutionScope.ownerDescriptor
@@ -171,13 +159,31 @@ public class AutoImportFix(element: KtSimpleNameExpression) : KotlinQuickFixActi
result.addAll(indicesHelper.getCallableTopLevelExtensions({ it == referenceName }, callTypeAndReceiver, element, bindingContext)) result.addAll(indicesHelper.getCallableTopLevelExtensions({ it == referenceName }, callTypeAndReceiver, element, bindingContext))
return if (result.size() > 1) return if (result.size > 1)
reduceCandidatesBasedOnDependencyRuleViolation(result, file) Helper.reduceCandidatesBasedOnDependencyRuleViolation(result, file)
else else
result result
} }
private fun reduceCandidatesBasedOnDependencyRuleViolation(candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> { companion object : JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtSimpleNameExpression>? {
// There could be different psi elements (i.e. JetArrayAccessExpression), but we can fix only JetSimpleNameExpression case
val psiElement = diagnostic.getPsiElement()
if (psiElement is KtSimpleNameExpression) {
return AutoImportFix(psiElement)
}
return null
}
override fun isApplicableForCodeFragment() = true
private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION ) { QuickFixes.getInstance().getDiagnostics(this) }
}
private object Helper {
public fun reduceCandidatesBasedOnDependencyRuleViolation(
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
val project = file.project val project = file.project
val validationManager = DependencyValidationManager.getInstance(project) val validationManager = DependencyValidationManager.getInstance(project)
return candidates.filter { return candidates.filter {
@@ -87,7 +87,7 @@ public class KotlinReferenceImporter : ReferenceImporter {
val bindingContext = analyze(BodyResolveMode.PARTIAL) val bindingContext = analyze(BodyResolveMode.PARTIAL)
if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false
var suggestions = AutoImportFix.computeSuggestions(this) var suggestions = AutoImportFix(this).suggestions
if (suggestions.distinctBy { it.importableFqName!! }.size() != 1) return false if (suggestions.distinctBy { it.importableFqName!! }.size() != 1) return false