Refactored to use exiting impl of AutoImportBase
This commit is contained in:
committed by
Valentin Kipyatkov
parent
9d56716897
commit
f40bb57d79
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
|
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -59,7 +60,7 @@ import java.util.*
|
|||||||
/**
|
/**
|
||||||
* Check possibility and perform fix for unresolved references.
|
* Check possibility and perform fix for unresolved references.
|
||||||
*/
|
*/
|
||||||
internal abstract class AutoImportFixBase<T: KtExpression>(expression: T) :
|
internal abstract class AutoImportFixBase<T : KtExpression>(expression: T) :
|
||||||
KotlinQuickFixAction<T>(expression), HighPriorityAction, HintAction {
|
KotlinQuickFixAction<T>(expression), HighPriorityAction, HintAction {
|
||||||
|
|
||||||
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(element.project).modificationCount
|
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(element.project).modificationCount
|
||||||
@@ -126,8 +127,6 @@ internal abstract class AutoImportFixBase<T: KtExpression>(expression: T) :
|
|||||||
|
|
||||||
val file = element.containingFile as KtFile
|
val file = element.containingFile as KtFile
|
||||||
|
|
||||||
fun filterByCallType(descriptor: DeclarationDescriptor) = callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor)
|
|
||||||
|
|
||||||
val searchScope = getResolveScope(file)
|
val searchScope = getResolveScope(file)
|
||||||
|
|
||||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
@@ -146,25 +145,10 @@ internal abstract class AutoImportFixBase<T: KtExpression>(expression: T) :
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = ArrayList<DeclarationDescriptor>()
|
|
||||||
|
|
||||||
val indicesHelper = KotlinIndicesHelper(resolutionFacade, searchScope, ::isVisible)
|
val indicesHelper = KotlinIndicesHelper(resolutionFacade, searchScope, ::isVisible)
|
||||||
|
|
||||||
val expression = element
|
val result = fillCandidates(callTypeAndReceiver, file, bindingContext,
|
||||||
if (expression is KtSimpleNameExpression) {
|
indicesHelper, nameStr, filterByCallType = { callTypeAndReceiver.callType.descriptorKindFilter.accepts(it) })
|
||||||
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
|
||||||
if (ProjectStructureUtil.isJsKotlinModule(file)) {
|
|
||||||
indicesHelper.getKotlinClasses({ it == nameStr }, { true }).filterTo(result, ::filterByCallType)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
indicesHelper.getJvmClassesByName(nameStr).filterTo(result, ::filterByCallType)
|
|
||||||
}
|
|
||||||
|
|
||||||
indicesHelper.getTopLevelCallablesByName(nameStr).filterTo(result, ::filterByCallType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext) { it == nameStr })
|
|
||||||
|
|
||||||
return if (result.size > 1)
|
return if (result.size > 1)
|
||||||
reduceCandidatesBasedOnDependencyRuleViolation(result, file)
|
reduceCandidatesBasedOnDependencyRuleViolation(result, file)
|
||||||
@@ -172,6 +156,10 @@ internal abstract class AutoImportFixBase<T: KtExpression>(expression: T) :
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun fillCandidates(callTypeAndReceiver: CallTypeAndReceiver<*, *>, file: KtFile,
|
||||||
|
bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper,
|
||||||
|
nameStr: String, filterByCallType: (descriptor: DeclarationDescriptor) -> (Boolean)): List<DeclarationDescriptor>
|
||||||
|
|
||||||
private fun reduceCandidatesBasedOnDependencyRuleViolation(
|
private fun reduceCandidatesBasedOnDependencyRuleViolation(
|
||||||
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
|
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
|
||||||
val project = file.project
|
val project = file.project
|
||||||
@@ -183,7 +171,32 @@ internal abstract class AutoImportFixBase<T: KtExpression>(expression: T) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AutoImportFix(expression: KtSimpleNameExpression) : AutoImportFixBase<KtSimpleNameExpression>(expression) {
|
internal abstract class AutoImportFixBaseDynamicContext<T : KtExpression>(expression: T) : AutoImportFixBase<T>(expression) {
|
||||||
|
override fun fillCandidates(callTypeAndReceiver: CallTypeAndReceiver<*, *>, file: KtFile, bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper, nameStr: String, filterByCallType: (DeclarationDescriptor) -> Boolean): List<DeclarationDescriptor> {
|
||||||
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
|
|
||||||
|
val expression = element
|
||||||
|
|
||||||
|
if (expression is KtSimpleNameExpression) {
|
||||||
|
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
||||||
|
if (ProjectStructureUtil.isJsKotlinModule(file)) {
|
||||||
|
indicesHelper.getKotlinClasses({ it == nameStr }, { true }).filterTo(result, filterByCallType)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indicesHelper.getJvmClassesByName(nameStr).filterTo(result, filterByCallType)
|
||||||
|
}
|
||||||
|
|
||||||
|
indicesHelper.getTopLevelCallablesByName(nameStr).filterTo(result, filterByCallType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, expression, bindingContext) { it == nameStr })
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AutoImportFix(expression: KtSimpleNameExpression) : AutoImportFixBaseDynamicContext<KtSimpleNameExpression>(expression) {
|
||||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
||||||
|
|
||||||
override val importNames: Collection<Name> = run {
|
override val importNames: Collection<Name> = run {
|
||||||
@@ -211,6 +224,7 @@ internal class AutoImportFix(expression: KtSimpleNameExpression) : AutoImportFix
|
|||||||
emptyList<Name>()
|
emptyList<Name>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun getSupportedErrors() = ERRORS
|
override fun getSupportedErrors() = ERRORS
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
@@ -223,7 +237,8 @@ internal class AutoImportFix(expression: KtSimpleNameExpression) : AutoImportFix
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MissingInvokeAutoImportFix(expression: KtExpression) : AutoImportFixBase<KtExpression>(expression) {
|
|
||||||
|
internal class MissingInvokeAutoImportFix(expression: KtExpression) : AutoImportFixBaseDynamicContext<KtExpression>(expression) {
|
||||||
override val importNames = OperatorNameConventions.INVOKE.singletonList()
|
override val importNames = OperatorNameConventions.INVOKE.singletonList()
|
||||||
|
|
||||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element)
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element)
|
||||||
@@ -239,7 +254,7 @@ internal class MissingInvokeAutoImportFix(expression: KtExpression) : AutoImport
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal open class MissingArrayAccessorAutoImportFix(element: KtArrayAccessExpression, override val importNames: Collection<Name>, private val showHint: Boolean) :
|
internal open class MissingArrayAccessorAutoImportFix(element: KtArrayAccessExpression, override val importNames: Collection<Name>, private val showHint: Boolean) :
|
||||||
AutoImportFixBase<KtArrayAccessExpression>(element) {
|
AutoImportFixBaseDynamicContext<KtArrayAccessExpression>(element) {
|
||||||
override fun getCallTypeAndReceiver() =
|
override fun getCallTypeAndReceiver() =
|
||||||
CallTypeAndReceiver.OPERATOR(element.arrayExpression!!)
|
CallTypeAndReceiver.OPERATOR(element.arrayExpression!!)
|
||||||
|
|
||||||
@@ -274,7 +289,7 @@ internal open class MissingArrayAccessorAutoImportFix(element: KtArrayAccessExpr
|
|||||||
|
|
||||||
internal class MissingDelegateAccessorsAutoImportFix(
|
internal class MissingDelegateAccessorsAutoImportFix(
|
||||||
element: KtExpression, override val importNames: Collection<Name>, private val solveSeveralProblems: Boolean) :
|
element: KtExpression, override val importNames: Collection<Name>, private val solveSeveralProblems: Boolean) :
|
||||||
AutoImportFixBase<KtExpression>(element) {
|
AutoImportFixBaseDynamicContext<KtExpression>(element) {
|
||||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
||||||
|
|
||||||
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||||
@@ -315,7 +330,7 @@ internal class MissingDelegateAccessorsAutoImportFix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class MissingComponentsAutoImportFix(element: KtExpression, override val importNames: Collection<Name>, private val solveSeveralProblems: Boolean) :
|
internal class MissingComponentsAutoImportFix(element: KtExpression, override val importNames: Collection<Name>, private val solveSeveralProblems: Boolean) :
|
||||||
AutoImportFixBase<KtExpression>(element) {
|
AutoImportFixBaseDynamicContext<KtExpression>(element) {
|
||||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element)
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element)
|
||||||
|
|
||||||
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||||
@@ -349,6 +364,64 @@ internal class MissingComponentsAutoImportFix(element: KtExpression, override va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class AutoImportStaticFix(expression: KtSimpleNameExpression) : AutoImportFixBase<KtSimpleNameExpression>(expression) {
|
||||||
|
|
||||||
|
override fun getText() = KotlinBundle.message("import.static.fix")
|
||||||
|
|
||||||
|
override fun fillCandidates(callTypeAndReceiver: CallTypeAndReceiver<*, *>, file: KtFile, bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper, nameStr: String, filterByCallType: (DeclarationDescriptor) -> Boolean): List<DeclarationDescriptor> {
|
||||||
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
|
val expression = element
|
||||||
|
if (expression is KtSimpleNameExpression) {
|
||||||
|
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
||||||
|
indicesHelper.getKotlinStatics(nameStr).filterTo(result, filterByCallType)
|
||||||
|
if (!(ProjectStructureUtil.isJsKotlinModule(file))) {
|
||||||
|
indicesHelper.getJvmStatics(nameStr).filterTo(result, filterByCallType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
||||||
|
|
||||||
|
override val importNames: Collection<Name> = run {
|
||||||
|
if (element.getIdentifier() == null) {
|
||||||
|
val conventionName = KtPsiUtil.getConventionName(element)
|
||||||
|
if (conventionName != null) {
|
||||||
|
if (element is KtOperationReferenceExpression) {
|
||||||
|
val elementType = element.firstChild.node.elementType
|
||||||
|
if (elementType in OperatorConventions.ASSIGNMENT_OPERATIONS) {
|
||||||
|
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[elementType]
|
||||||
|
val counterpartName = OperatorConventions.BINARY_OPERATION_NAMES[counterpart]
|
||||||
|
if (counterpartName != null) {
|
||||||
|
return@run listOf(conventionName, counterpartName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return@run conventionName.singletonOrEmptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Name.isValidIdentifier(element.getReferencedName())) {
|
||||||
|
return@run Name.identifier(element.getReferencedName()).singletonOrEmptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyList<Name>()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSupportedErrors(): Collection<DiagnosticFactory<*>> = ERRORS
|
||||||
|
|
||||||
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
|
override fun createAction(diagnostic: Diagnostic) =
|
||||||
|
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::AutoImportStaticFix)
|
||||||
|
|
||||||
|
override fun isApplicableForCodeFragment() = true
|
||||||
|
|
||||||
|
private val ERRORS: Collection<DiagnosticFactory<*>> by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
object AutoImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory() {
|
object AutoImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
val element = diagnostic.psiElement as? KtExpression ?: return null
|
val element = diagnostic.psiElement as? KtExpression ?: return null
|
||||||
@@ -357,7 +430,7 @@ object AutoImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory(
|
|||||||
when (name) {
|
when (name) {
|
||||||
OperatorNameConventions.GET, OperatorNameConventions.SET -> {
|
OperatorNameConventions.GET, OperatorNameConventions.SET -> {
|
||||||
if (element is KtArrayAccessExpression) {
|
if (element is KtArrayAccessExpression) {
|
||||||
return object: MissingArrayAccessorAutoImportFix(element, name.singletonList(), false) {
|
return object : MissingArrayAccessorAutoImportFix(element, name.singletonList(), false) {
|
||||||
override fun getSupportedErrors() = Errors.OPERATOR_MODIFIER_REQUIRED.singletonList()
|
override fun getSupportedErrors() = Errors.OPERATOR_MODIFIER_REQUIRED.singletonList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.hint.HintManager
|
|
||||||
import com.intellij.codeInsight.intention.HighPriorityAction
|
|
||||||
import com.intellij.codeInspection.HintAction
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
|
||||||
import com.intellij.openapi.editor.Editor
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.packageDependencies.DependencyValidationManager
|
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
|
||||||
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
|
|
||||||
import org.jetbrains.kotlin.idea.actions.createSingleImportAction
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
|
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
|
||||||
import org.jetbrains.kotlin.idea.core.isVisible
|
|
||||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
|
||||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
|
||||||
import org.jetbrains.kotlin.utils.CachedValueProperty
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Semoro on 08.07.16.
|
|
||||||
* ©XCodersTeam, 2016
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AutoStaticImportFix(expression: KtSimpleNameExpression) :
|
|
||||||
KotlinQuickFixAction<KtSimpleNameExpression>(expression), HighPriorityAction, HintAction {
|
|
||||||
|
|
||||||
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(element.project).modificationCount
|
|
||||||
|
|
||||||
private val suggestionCount: Int by CachedValueProperty(
|
|
||||||
calculator = { computeSuggestions().size },
|
|
||||||
timestampCalculator = { PsiModificationTracker.SERVICE.getInstance(element.project).modificationCount }
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
override fun showHint(editor: Editor): Boolean {
|
|
||||||
if (!element.isValid || isOutdated()) return false
|
|
||||||
|
|
||||||
if (ApplicationManager.getApplication().isUnitTestMode && HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) return false
|
|
||||||
|
|
||||||
if (suggestionCount == 0) return false
|
|
||||||
|
|
||||||
return createAction(element.project, editor).showHint()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getText() = KotlinBundle.message("import.static.fix")
|
|
||||||
|
|
||||||
override fun getFamilyName() = KotlinBundle.message("import.fix")
|
|
||||||
|
|
||||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile)
|
|
||||||
= super.isAvailable(project, editor, file) && suggestionCount > 0
|
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
|
||||||
CommandProcessor.getInstance().runUndoTransparentAction {
|
|
||||||
createAction(project, editor!!).execute()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun startInWriteAction() = true
|
|
||||||
|
|
||||||
private fun isOutdated() = modificationCountOnCreate != PsiModificationTracker.SERVICE.getInstance(element.project).modificationCount
|
|
||||||
|
|
||||||
private fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
|
||||||
return createSingleImportAction(project, editor, element, computeSuggestions())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun computeSuggestions(): Collection<DeclarationDescriptor> {
|
|
||||||
if (!element.isValid) return listOf()
|
|
||||||
if (element.containingFile !is KtFile) return emptyList()
|
|
||||||
|
|
||||||
val callTypeAndReceiver = getCallTypeAndReceiver()
|
|
||||||
|
|
||||||
if (callTypeAndReceiver is CallTypeAndReceiver.UNKNOWN) return emptyList()
|
|
||||||
|
|
||||||
if (importNames.isEmpty()) return emptyList()
|
|
||||||
|
|
||||||
return importNames.flatMapTo(LinkedHashSet()) {
|
|
||||||
computeSuggestionsForName(it, callTypeAndReceiver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun computeSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>):
|
|
||||||
Collection<DeclarationDescriptor> {
|
|
||||||
val nameStr = name.asString()
|
|
||||||
if (nameStr.isEmpty()) return emptyList()
|
|
||||||
|
|
||||||
val file = element.containingFile as KtFile
|
|
||||||
|
|
||||||
fun filterByCallType(descriptor: DeclarationDescriptor) = callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor)
|
|
||||||
|
|
||||||
val searchScope = getResolveScope(file)
|
|
||||||
|
|
||||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
|
||||||
|
|
||||||
val diagnostics = bindingContext.diagnostics.forElement(element)
|
|
||||||
|
|
||||||
if (!diagnostics.any { it.factory in getSupportedErrors() }) return emptyList()
|
|
||||||
|
|
||||||
val resolutionFacade = element.getResolutionFacade()
|
|
||||||
|
|
||||||
fun isVisible(descriptor: DeclarationDescriptor): Boolean {
|
|
||||||
if (descriptor is DeclarationDescriptorWithVisibility) {
|
|
||||||
return descriptor.isVisible(element, callTypeAndReceiver.receiver as? KtExpression, bindingContext, resolutionFacade)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = ArrayList<DeclarationDescriptor>()
|
|
||||||
|
|
||||||
val indicesHelper = KotlinIndicesHelper(resolutionFacade, searchScope, ::isVisible)
|
|
||||||
|
|
||||||
val expression = element
|
|
||||||
if (expression is KtSimpleNameExpression) {
|
|
||||||
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
|
||||||
indicesHelper.getKotlinStatics(nameStr).filterTo(result, ::filterByCallType)
|
|
||||||
if (!(ProjectStructureUtil.isJsKotlinModule(file))) {
|
|
||||||
indicesHelper.getJvmStatics(nameStr).filterTo(result, ::filterByCallType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return if (result.size > 1)
|
|
||||||
reduceCandidatesBasedOnDependencyRuleViolation(result, file)
|
|
||||||
else
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reduceCandidatesBasedOnDependencyRuleViolation(
|
|
||||||
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
|
|
||||||
val project = file.project
|
|
||||||
val validationManager = DependencyValidationManager.getInstance(project)
|
|
||||||
return candidates.filter {
|
|
||||||
val targetFile = DescriptorToSourceUtilsIde.getAnyDeclaration(project, it)?.containingFile ?: return@filter true
|
|
||||||
validationManager.getViolatorDependencyRules(file, targetFile).isEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
|
||||||
|
|
||||||
val importNames: Collection<Name> = run {
|
|
||||||
if (element.getIdentifier() == null) {
|
|
||||||
val conventionName = KtPsiUtil.getConventionName(element)
|
|
||||||
if (conventionName != null) {
|
|
||||||
if (element is KtOperationReferenceExpression) {
|
|
||||||
val elementType = element.firstChild.node.elementType
|
|
||||||
if (elementType in OperatorConventions.ASSIGNMENT_OPERATIONS) {
|
|
||||||
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[elementType]
|
|
||||||
val counterpartName = OperatorConventions.BINARY_OPERATION_NAMES[counterpart]
|
|
||||||
if (counterpartName != null) {
|
|
||||||
return@run listOf(conventionName, counterpartName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return@run conventionName.singletonOrEmptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Name.isValidIdentifier(element.getReferencedName())) {
|
|
||||||
return@run Name.identifier(element.getReferencedName()).singletonOrEmptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
emptyList<Name>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSupportedErrors(): Collection<DiagnosticFactory<*>> = ERRORS
|
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
|
||||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let { AutoStaticImportFix(it) }
|
|
||||||
|
|
||||||
override fun isApplicableForCodeFragment() = true
|
|
||||||
|
|
||||||
private val ERRORS: Collection<DiagnosticFactory<*>> by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -128,7 +128,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
|||||||
NON_PRIVATE_CONSTRUCTOR_IN_ENUM.registerFactory(removeModifierFactory)
|
NON_PRIVATE_CONSTRUCTOR_IN_ENUM.registerFactory(removeModifierFactory)
|
||||||
NON_PRIVATE_CONSTRUCTOR_IN_SEALED.registerFactory(removeModifierFactory)
|
NON_PRIVATE_CONSTRUCTOR_IN_SEALED.registerFactory(removeModifierFactory)
|
||||||
|
|
||||||
UNRESOLVED_REFERENCE.registerFactory(AutoStaticImportFix)
|
UNRESOLVED_REFERENCE.registerFactory(AutoImportStaticFix)
|
||||||
UNRESOLVED_REFERENCE.registerFactory(AutoImportFix)
|
UNRESOLVED_REFERENCE.registerFactory(AutoImportFix)
|
||||||
|
|
||||||
UNRESOLVED_REFERENCE.registerFactory(AddTestLibQuickFix)
|
UNRESOLVED_REFERENCE.registerFactory(AddTestLibQuickFix)
|
||||||
|
|||||||
Reference in New Issue
Block a user