Minor: fix warnings & refactoring
This commit is contained in:
@@ -17,17 +17,15 @@
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.nextStatement
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.previousStatement
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineCount
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||
import org.jetbrains.kotlin.j2k.isInSingleLine
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.calls.CallExpressionElement
|
||||
|
||||
class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.java, "Add braces") {
|
||||
override fun isApplicableTo(element: KtElement, caretOffset: Int): Boolean {
|
||||
@@ -37,7 +35,7 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
|
||||
val parent = expression.parent
|
||||
return when (parent) {
|
||||
is KtContainerNode -> {
|
||||
val description = parent.description()!!
|
||||
val description = parent.description() ?: return false
|
||||
text = "Add braces to '$description' statement"
|
||||
true
|
||||
}
|
||||
@@ -53,7 +51,7 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
|
||||
|
||||
override fun applyTo(element: KtElement, editor: Editor?) {
|
||||
if (editor == null) throw IllegalArgumentException("This intention requires an editor")
|
||||
val expression = element.getTargetExpression(editor.caretModel.offset)!!
|
||||
val expression = element.getTargetExpression(editor.caretModel.offset) ?: return
|
||||
var isCommentBeneath = false
|
||||
var isCommentInside = false
|
||||
val psiFactory = KtPsiFactory(element)
|
||||
@@ -76,9 +74,9 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
|
||||
// Check if \n before first received comment sibling
|
||||
// if false, the normal procedure of adding braces occurs.
|
||||
isCommentBeneath =
|
||||
sibling.prevSibling is PsiWhiteSpace &&
|
||||
sibling.prevSibling.textContains('\n') &&
|
||||
(sibling.prevSibling.prevSibling is PsiComment || sibling.prevSibling.prevSibling is PsiElement)
|
||||
sibling.prevSibling is PsiWhiteSpace &&
|
||||
sibling.prevSibling.textContains('\n') &&
|
||||
(sibling.prevSibling.prevSibling is PsiComment || sibling.prevSibling.prevSibling is PsiElement)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +115,7 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
|
||||
when (element) {
|
||||
is KtDoWhileExpression ->
|
||||
// remove new line between '}' and while
|
||||
(element.body!!.parent.nextSibling as? PsiWhiteSpace)?.delete()
|
||||
(element.body?.parent?.nextSibling as? PsiWhiteSpace)?.delete()
|
||||
is KtIfExpression ->
|
||||
(result?.parent?.nextSibling as? PsiWhiteSpace)?.delete()
|
||||
}
|
||||
@@ -131,7 +129,7 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
|
||||
is KtIfExpression -> {
|
||||
val thenExpr = then ?: return null
|
||||
val elseExpr = `else`
|
||||
if (elseExpr != null && caretLocation >= elseKeyword!!.startOffset) {
|
||||
if (elseExpr != null && caretLocation >= elseKeyword?.startOffset ?: return null) {
|
||||
elseExpr
|
||||
} else {
|
||||
thenExpr
|
||||
|
||||
@@ -48,8 +48,7 @@ abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement
|
||||
|
||||
val elements = element.elements()
|
||||
if (!hasLineBreakAfter(elements.last())) {
|
||||
val rpar = element.allChildren.lastOrNull { it.node.elementType == KtTokens.RPAR }
|
||||
rpar?.startOffset?.let { document.insertString(it, "\n") }
|
||||
element.allChildren.lastOrNull { it.node.elementType == KtTokens.RPAR }?.startOffset?.let { document.insertString(it, "\n") }
|
||||
}
|
||||
|
||||
for (e in elements.asReversed()) {
|
||||
@@ -60,8 +59,8 @@ abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement
|
||||
|
||||
val documentManager = PsiDocumentManager.getInstance(project)
|
||||
documentManager.commitDocument(document)
|
||||
val psiFile = documentManager.getPsiFile(document)!!
|
||||
val newList = PsiTreeUtil.getParentOfType(psiFile.findElementAt(startOffset)!!, listClass)!!
|
||||
val psiFile = documentManager.getPsiFile(document) ?: return
|
||||
val newList = PsiTreeUtil.getParentOfType(psiFile.findElementAt(startOffset) ?: return, listClass) ?: return
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(psiFile, newList.textRange)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.CodeInsightBundle
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiFileSystemItem
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
@@ -34,18 +33,18 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
|
||||
class IntroduceVariableIntention : SelfTargetingRangeIntention<PsiElement>(
|
||||
PsiElement::class.java, CodeInsightBundle.message("intention.introduce.variable.text")
|
||||
PsiElement::class.java, CodeInsightBundle.message("intention.introduce.variable.text")
|
||||
) {
|
||||
private fun getExpressionToProcess(element: PsiElement): KtExpression? {
|
||||
if (element is PsiFileSystemItem) return null
|
||||
val startElement = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace::class.java) ?: element
|
||||
return startElement.parentsWithSelf
|
||||
.filterIsInstance<KtExpression>()
|
||||
.takeWhile { it !is KtDeclarationWithBody }
|
||||
.firstOrNull {
|
||||
val parent = it.parent
|
||||
parent is KtBlockExpression || parent is KtDeclarationWithBody && !parent.hasBlockBody() && parent.bodyExpression == it
|
||||
}
|
||||
.filterIsInstance<KtExpression>()
|
||||
.takeWhile { it !is KtDeclarationWithBody }
|
||||
.firstOrNull {
|
||||
val parent = it.parent
|
||||
parent is KtBlockExpression || parent is KtDeclarationWithBody && !parent.hasBlockBody() && parent.bodyExpression == it
|
||||
}
|
||||
}
|
||||
|
||||
override fun applicabilityRange(element: PsiElement): TextRange? {
|
||||
@@ -58,7 +57,7 @@ class IntroduceVariableIntention : SelfTargetingRangeIntention<PsiElement>(
|
||||
override fun applyTo(element: PsiElement, editor: Editor?) {
|
||||
val expression = getExpressionToProcess(element) ?: return
|
||||
KotlinIntroduceVariableHandler.doRefactoring(
|
||||
element.project, editor, expression, isVar = false, occurrencesToReplace = null, onNonInteractiveFinish = null
|
||||
element.project, editor, expression, isVar = false, occurrencesToReplace = null, onNonInteractiveFinish = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,7 @@ class RemoveBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class
|
||||
override fun isApplicableTo(element: KtElement, caretOffset: Int): Boolean {
|
||||
val block = element.findChildBlock() ?: return false
|
||||
val singleStatement = block.statements.singleOrNull() ?: return false
|
||||
val container = block.parent
|
||||
when (container) {
|
||||
when (val container = block.parent) {
|
||||
is KtContainerNode -> {
|
||||
if (singleStatement is KtIfExpression) {
|
||||
val elseExpression = (container.parent as? KtIfExpression)?.`else`
|
||||
@@ -74,7 +73,8 @@ class RemoveBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class
|
||||
if (construct is KtIfExpression &&
|
||||
container.node.elementType == KtNodeTypes.ELSE &&
|
||||
construct.parent is KtExpression &&
|
||||
construct.parent !is KtStatementExpression) {
|
||||
construct.parent !is KtStatementExpression
|
||||
) {
|
||||
construct.replace(factory.createExpressionByPattern("($0)", construct))
|
||||
}
|
||||
}
|
||||
|
||||
+18
-19
@@ -46,25 +46,23 @@ class ReplaceExplicitFunctionLiteralParamWithItIntention : PsiElementBaseIntenti
|
||||
if (parameter.destructuringDeclaration != null) return false
|
||||
|
||||
if (functionLiteral.anyDescendantOfType<KtFunctionLiteral> { literal ->
|
||||
literal.usesName(element.text) &&
|
||||
(!literal.hasParameterSpecification() || literal.usesName("it"))
|
||||
} ) return false
|
||||
literal.usesName(element.text) && (!literal.hasParameterSpecification() || literal.usesName("it"))
|
||||
}) return false
|
||||
|
||||
text = "Replace explicit parameter '${parameter.name}' with 'it'"
|
||||
return true
|
||||
}
|
||||
|
||||
private fun KtFunctionLiteral.usesName(name: String): Boolean =
|
||||
anyDescendantOfType<KtSimpleNameExpression> {
|
||||
nameExpr -> nameExpr.getReferencedName() == name
|
||||
}
|
||||
private fun KtFunctionLiteral.usesName(name: String): Boolean = anyDescendantOfType<KtSimpleNameExpression> { nameExpr ->
|
||||
nameExpr.getReferencedName() == name
|
||||
}
|
||||
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
|
||||
override fun invoke(project: Project, editor: Editor, element: PsiElement) {
|
||||
val caretOffset = editor.caretModel.offset
|
||||
val functionLiteral = targetFunctionLiteral(element, editor.caretModel.offset)!!
|
||||
val cursorInParameterList = functionLiteral.valueParameterList!!.textRange.containsOffset(caretOffset)
|
||||
val functionLiteral = targetFunctionLiteral(element, editor.caretModel.offset) ?: return
|
||||
val cursorInParameterList = functionLiteral.valueParameterList?.textRange?.containsOffset(caretOffset) ?: return
|
||||
ParamRenamingProcessor(editor, functionLiteral, cursorInParameterList).run()
|
||||
}
|
||||
|
||||
@@ -83,22 +81,23 @@ class ReplaceExplicitFunctionLiteralParamWithItIntention : PsiElementBaseIntenti
|
||||
}
|
||||
|
||||
private class ParamRenamingProcessor(
|
||||
val editor: Editor,
|
||||
val functionLiteral: KtFunctionLiteral,
|
||||
val cursorWasInParameterList: Boolean
|
||||
) : RenameProcessor(editor.project,
|
||||
functionLiteral.valueParameters.single(),
|
||||
"it",
|
||||
false,
|
||||
false
|
||||
val editor: Editor,
|
||||
val functionLiteral: KtFunctionLiteral,
|
||||
val cursorWasInParameterList: Boolean
|
||||
) : RenameProcessor(
|
||||
editor.project,
|
||||
functionLiteral.valueParameters.single(),
|
||||
"it",
|
||||
false,
|
||||
false
|
||||
) {
|
||||
override fun performRefactoring(usages: Array<out UsageInfo>) {
|
||||
super.performRefactoring(usages)
|
||||
|
||||
functionLiteral.deleteChildRange(functionLiteral.valueParameterList, functionLiteral.arrow!!)
|
||||
functionLiteral.deleteChildRange(functionLiteral.valueParameterList, functionLiteral.arrow ?: return)
|
||||
|
||||
if (cursorWasInParameterList) {
|
||||
editor.caretModel.moveToOffset(functionLiteral.bodyExpression!!.textOffset)
|
||||
editor.caretModel.moveToOffset(functionLiteral.bodyExpression?.textOffset ?: return)
|
||||
}
|
||||
|
||||
val project = functionLiteral.project
|
||||
|
||||
+8
-8
@@ -28,23 +28,23 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
|
||||
class ReplaceItWithExplicitFunctionLiteralParamIntention : SelfTargetingOffsetIndependentIntention<KtNameReferenceExpression> (
|
||||
KtNameReferenceExpression::class.java, "Replace 'it' with explicit parameter"
|
||||
class ReplaceItWithExplicitFunctionLiteralParamIntention : SelfTargetingOffsetIndependentIntention<KtNameReferenceExpression>(
|
||||
KtNameReferenceExpression::class.java, "Replace 'it' with explicit parameter"
|
||||
), LowPriorityAction {
|
||||
override fun isApplicableTo(element: KtNameReferenceExpression)
|
||||
= isAutoCreatedItUsage(element)
|
||||
override fun isApplicableTo(element: KtNameReferenceExpression) = isAutoCreatedItUsage(element)
|
||||
|
||||
override fun applyTo(element: KtNameReferenceExpression, editor: Editor?) {
|
||||
if (editor == null) throw IllegalArgumentException("This intention requires an editor")
|
||||
val target = element.mainReference.resolveToDescriptors(element.analyze()).single()
|
||||
|
||||
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(target.containingDeclaration!!) as KtFunctionLiteral
|
||||
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(target.containingDeclaration ?: return) as KtFunctionLiteral
|
||||
|
||||
val newExpr = KtPsiFactory(element).createExpression("{ it -> }") as KtLambdaExpression
|
||||
functionLiteral.addRangeAfter(
|
||||
newExpr.functionLiteral.valueParameterList,
|
||||
newExpr.functionLiteral.arrow!!,
|
||||
functionLiteral.lBrace)
|
||||
newExpr.functionLiteral.valueParameterList,
|
||||
newExpr.functionLiteral.arrow ?: return,
|
||||
functionLiteral.lBrace
|
||||
)
|
||||
PsiDocumentManager.getInstance(element.project).doPostponedOperationsAndUnblockDocument(editor.document)
|
||||
|
||||
val paramToRename = functionLiteral.valueParameters.single()
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.codeInsight.template.*
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
@@ -47,7 +46,7 @@ import org.jetbrains.kotlin.utils.ifEmpty
|
||||
class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
|
||||
KtCallableDeclaration::class.java,
|
||||
"Specify type explicitly"
|
||||
), LowPriorityAction {
|
||||
) {
|
||||
|
||||
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
|
||||
if (element.containingFile is KtCodeFragment) return null
|
||||
|
||||
@@ -156,11 +156,7 @@ open class AddModifierFix(
|
||||
object MakeClassOpenFactory : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val typeReference = diagnostic.psiElement as KtTypeReference
|
||||
val bindingContext = typeReference.analyze(BodyResolveMode.PARTIAL)
|
||||
val type = bindingContext[BindingContext.TYPE, typeReference] ?: return null
|
||||
val classDescriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(classDescriptor) as? KtClass ?: return null
|
||||
if (!declaration.canRefactor()) return null
|
||||
val declaration = typeReference.classForRefactor() ?: return null
|
||||
if (declaration.isEnum() || declaration.isData()) return null
|
||||
return AddModifierFix(declaration, KtTokens.OPEN_KEYWORD)
|
||||
}
|
||||
@@ -181,3 +177,12 @@ open class AddModifierFix(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun KtTypeReference.classForRefactor(): KtClass? {
|
||||
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||
val type = bindingContext[BindingContext.TYPE, this] ?: return null
|
||||
val classDescriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(classDescriptor) as? KtClass ?: return null
|
||||
if (!declaration.canRefactor()) return null
|
||||
return declaration
|
||||
}
|
||||
@@ -117,8 +117,7 @@ class AddExclExclCallFix(psiElement: PsiElement, val checkImplicitReceivers: Boo
|
||||
return when (psiElement) {
|
||||
is KtArrayAccessExpression -> psiElement.expressionForCall()
|
||||
is KtOperationReferenceExpression -> {
|
||||
val parent = psiElement.parent
|
||||
when (parent) {
|
||||
when (val parent = psiElement.parent) {
|
||||
is KtUnaryExpression -> parent.baseExpression.expressionForCall()
|
||||
is KtBinaryExpression -> {
|
||||
val receiver = if (KtPsiUtil.isInOrNotInOperation(parent)) parent.right else parent.left
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.intellij.psi.PsiErrorElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
@@ -52,11 +51,12 @@ import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.ReceiverType
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.util.receiverTypesWithIndex
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -81,8 +81,8 @@ import java.util.*
|
||||
* Check possibility and perform fix for unresolved references.
|
||||
*/
|
||||
internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
||||
expression: T,
|
||||
private val factory: Factory
|
||||
expression: T,
|
||||
private val factory: Factory
|
||||
) : KotlinQuickFixAction<T>(expression), HighPriorityAction, HintAction {
|
||||
private val project = expression.project
|
||||
|
||||
@@ -115,8 +115,7 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
||||
|
||||
override fun getFamilyName() = KotlinBundle.message("import.fix")
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: KtFile)
|
||||
= element != null && suggestions.isNotEmpty()
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: KtFile) = element != null && suggestions.isNotEmpty()
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val element = element ?: return
|
||||
@@ -197,21 +196,22 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
||||
|
||||
private fun checkErrorStillPresent(bindingContext: BindingContext): Boolean {
|
||||
return elementsToCheckDiagnostics()
|
||||
.flatMap { bindingContext.diagnostics.forElement(it) }
|
||||
.any { diagnostic -> diagnostic.factory in getSupportedErrors() }
|
||||
.flatMap { bindingContext.diagnostics.forElement(it) }
|
||||
.any { diagnostic -> diagnostic.factory in getSupportedErrors() }
|
||||
}
|
||||
|
||||
protected open fun elementsToCheckDiagnostics(): Collection<PsiElement> = listOfNotNull(element)
|
||||
|
||||
abstract fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor>
|
||||
|
||||
private fun reduceCandidatesBasedOnDependencyRuleViolation(
|
||||
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
|
||||
candidates: Collection<DeclarationDescriptor>, file: PsiFile
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val project = file.project
|
||||
val validationManager = DependencyValidationManager.getInstance(project)
|
||||
return candidates.filter {
|
||||
@@ -229,11 +229,11 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
||||
|
||||
open fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<ImportFixBase<*>> = emptyList()
|
||||
|
||||
override final fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
final override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
return createImportAction(diagnostic)?.apply { computeSuggestions() }
|
||||
}
|
||||
|
||||
override final fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
||||
final override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
||||
return createImportActionsForAllProblems(sameTypeDiagnostics).onEach { it.computeSuggestions() }
|
||||
}
|
||||
}
|
||||
@@ -242,10 +242,10 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
||||
|
||||
internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T, factory: Factory) : ImportFixBase<T>(expression, factory) {
|
||||
override fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
val expression = element ?: return emptyList()
|
||||
|
||||
@@ -284,13 +284,14 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override val importNames: Collection<Name> = ((element?.mainReference?.resolvesByNames ?: emptyList()) + importNamesForMembers()).distinct()
|
||||
override val importNames: Collection<Name> =
|
||||
((element?.mainReference?.resolvesByNames ?: emptyList()) + importNamesForMembers()).distinct()
|
||||
|
||||
private fun collectMemberCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
|
||||
val element = element ?: return emptyList()
|
||||
@@ -314,78 +315,92 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix
|
||||
|
||||
val explicitReceiverTypes = actualReceiverTypes.filterNot { it.implicit }
|
||||
|
||||
val checkDispatchReceiver = when(callTypeAndReceiver) {
|
||||
val checkDispatchReceiver = when (callTypeAndReceiver) {
|
||||
is CallTypeAndReceiver.OPERATOR, is CallTypeAndReceiver.INFIX -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
val processor = { descriptor: CallableDescriptor ->
|
||||
if (descriptor.canBeReferencedViaImport() && filterByCallType(descriptor)
|
||||
&& descriptor.isValidByReceiversFor(explicitReceiverTypes, actualReceiverTypes, checkDispatchReceiver)) {
|
||||
&& descriptor.isValidByReceiversFor(explicitReceiverTypes, actualReceiverTypes, checkDispatchReceiver)
|
||||
) {
|
||||
result.add(descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
indicesHelper.processKotlinCallablesByName(
|
||||
name,
|
||||
filter = { declaration -> (declaration.parent as? KtClassBody)?.parent is KtObjectDeclaration },
|
||||
processor = processor
|
||||
name,
|
||||
filter = { declaration -> (declaration.parent as? KtClassBody)?.parent is KtObjectDeclaration },
|
||||
processor = processor
|
||||
)
|
||||
|
||||
if (TargetPlatformDetector.getPlatform(element.containingKtFile) == JvmPlatform) {
|
||||
indicesHelper.processJvmCallablesByName(
|
||||
name,
|
||||
filter = { it.hasModifierProperty(PsiModifier.STATIC) },
|
||||
processor = processor
|
||||
name,
|
||||
filter = { it.hasModifierProperty(PsiModifier.STATIC) },
|
||||
processor = processor
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private fun CallableDescriptor.isValidByReceiversFor(explicitReceiverTypes: Collection<ReceiverType>,
|
||||
allReceiverTypes: Collection<ReceiverType>,
|
||||
checkDispatchReceiver: Boolean): Boolean {
|
||||
private fun CallableDescriptor.isValidByReceiversFor(
|
||||
explicitReceiverTypes: Collection<ReceiverType>,
|
||||
allReceiverTypes: Collection<ReceiverType>,
|
||||
checkDispatchReceiver: Boolean
|
||||
): Boolean {
|
||||
val bothReceivers = listOfNotNull(extensionReceiverParameter, dispatchReceiverParameter.takeIf { checkDispatchReceiver })
|
||||
|
||||
val receiverTypesPerReceiver = generateSequence(explicitReceiverTypes.ifEmpty { allReceiverTypes }) { allReceiverTypes }
|
||||
|
||||
return bothReceivers
|
||||
.zip(receiverTypesPerReceiver.asIterable())
|
||||
.all { (receiver, possibleTypes) -> possibleTypes.any { it.type.isSubtypeOf(receiver.type) } }
|
||||
.zip(receiverTypesPerReceiver.asIterable())
|
||||
.all { (receiver, possibleTypes) -> possibleTypes.any { it.type.isSubtypeOf(receiver.type) } }
|
||||
}
|
||||
|
||||
override fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
return super.fillCandidates(name, callTypeAndReceiver, bindingContext, indicesHelper) + collectMemberCandidates(name, callTypeAndReceiver, bindingContext, indicesHelper)
|
||||
return super.fillCandidates(name, callTypeAndReceiver, bindingContext, indicesHelper) + collectMemberCandidates(
|
||||
name,
|
||||
callTypeAndReceiver,
|
||||
bindingContext,
|
||||
indicesHelper
|
||||
)
|
||||
}
|
||||
|
||||
companion object MyFactory : Factory() {
|
||||
override fun createImportAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportFix)
|
||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportFix)
|
||||
}
|
||||
}
|
||||
|
||||
internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression) : ImportFixBase<KtSimpleNameExpression>(expression, MyFactory) {
|
||||
internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression) :
|
||||
ImportFixBase<KtSimpleNameExpression>(expression, MyFactory) {
|
||||
override fun getCallTypeAndReceiver() = element?.let {
|
||||
CallTypeAndReceiver.detect(it) as? CallTypeAndReceiver.CALLABLE_REFERENCE
|
||||
}
|
||||
|
||||
override fun fillCandidates(name: String, callTypeAndReceiver: CallTypeAndReceiver<*, *>, bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper): List<DeclarationDescriptor> {
|
||||
override fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
val expression = element ?: return emptyList()
|
||||
|
||||
val filterByCallType = callTypeAndReceiver.toFilter()
|
||||
// TODO Type-aliases
|
||||
return indicesHelper.getClassesByName(expression, name)
|
||||
.asSequence()
|
||||
.map { it.constructors }.flatten()
|
||||
.filter { it.importableFqName != null }
|
||||
.filter(filterByCallType)
|
||||
.toList()
|
||||
.asSequence()
|
||||
.map { it.constructors }.flatten()
|
||||
.filter { it.importableFqName != null }
|
||||
.filter(filterByCallType)
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun createAction(project: Project, editor: Editor, element: KtExpression): KotlinAddImportAction {
|
||||
@@ -396,7 +411,7 @@ internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression)
|
||||
|
||||
companion object MyFactory : Factory() {
|
||||
override fun createImportAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportConstructorReferenceFix)
|
||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportConstructorReferenceFix)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,14 +422,14 @@ internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase
|
||||
|
||||
companion object MyFactory : Factory() {
|
||||
override fun createImportAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtExpression)?.let(::InvokeImportFix)
|
||||
(diagnostic.psiElement as? KtExpression)?.let(::InvokeImportFix)
|
||||
}
|
||||
}
|
||||
|
||||
internal open class ArrayAccessorImportFix(
|
||||
element: KtArrayAccessExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val showHint: Boolean
|
||||
element: KtArrayAccessExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val showHint: Boolean
|
||||
) : OrdinaryImportFixBase<KtArrayAccessExpression>(element, MyFactory) {
|
||||
|
||||
override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.OPERATOR(it.arrayExpression!!) }
|
||||
@@ -445,9 +460,9 @@ internal open class ArrayAccessorImportFix(
|
||||
}
|
||||
|
||||
internal class DelegateAccessorsImportFix(
|
||||
element: KtExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val solveSeveralProblems: Boolean
|
||||
element: KtExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val solveSeveralProblems: Boolean
|
||||
) : OrdinaryImportFixBase<KtExpression>(element, MyFactory) {
|
||||
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
||||
@@ -472,9 +487,9 @@ internal class DelegateAccessorsImportFix(
|
||||
}
|
||||
|
||||
override fun createImportAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtExpression)?.let {
|
||||
DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false)
|
||||
}
|
||||
(diagnostic.psiElement as? KtExpression)?.let {
|
||||
DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false)
|
||||
}
|
||||
|
||||
|
||||
override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<DelegateAccessorsImportFix> {
|
||||
@@ -486,9 +501,9 @@ internal class DelegateAccessorsImportFix(
|
||||
}
|
||||
|
||||
internal class ComponentsImportFix(
|
||||
element: KtExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val solveSeveralProblems: Boolean
|
||||
element: KtExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val solveSeveralProblems: Boolean
|
||||
) : OrdinaryImportFixBase<KtExpression>(element, MyFactory) {
|
||||
|
||||
override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.OPERATOR(it) }
|
||||
@@ -503,12 +518,12 @@ internal class ComponentsImportFix(
|
||||
|
||||
companion object MyFactory : Factory() {
|
||||
private fun importNames(diagnostics: Collection<Diagnostic>) =
|
||||
diagnostics.map { Name.identifier(Errors.COMPONENT_FUNCTION_MISSING.cast(it).a.identifier) }
|
||||
diagnostics.map { Name.identifier(Errors.COMPONENT_FUNCTION_MISSING.cast(it).a.identifier) }
|
||||
|
||||
override fun createImportAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtExpression)?.let {
|
||||
ComponentsImportFix(it, importNames(listOf(diagnostic)), false)
|
||||
}
|
||||
(diagnostic.psiElement as? KtExpression)?.let {
|
||||
ComponentsImportFix(it, importNames(listOf(diagnostic)), false)
|
||||
}
|
||||
|
||||
override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<ComponentsImportFix> {
|
||||
val element = sameTypeDiagnostics.first().psiElement
|
||||
@@ -520,7 +535,7 @@ internal class ComponentsImportFix(
|
||||
}
|
||||
|
||||
internal class ImportForMismatchingArgumentsFix(
|
||||
expression: KtSimpleNameExpression
|
||||
expression: KtSimpleNameExpression
|
||||
) : ImportFixBase<KtSimpleNameExpression>(expression, MyFactory) {
|
||||
override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.detect(it) }
|
||||
|
||||
@@ -530,17 +545,19 @@ internal class ImportForMismatchingArgumentsFix(
|
||||
val element = element ?: return emptyList()
|
||||
val callExpression = element.parent as? KtCallExpression ?: return emptyList()
|
||||
return callExpression.valueArguments +
|
||||
callExpression.valueArguments.mapNotNull { it.getArgumentExpression() } +
|
||||
callExpression.valueArguments.mapNotNull { it.getArgumentName()?.referenceExpression } +
|
||||
listOfNotNull(callExpression.valueArgumentList,
|
||||
callExpression.referenceExpression())
|
||||
callExpression.valueArguments.mapNotNull { it.getArgumentExpression() } +
|
||||
callExpression.valueArguments.mapNotNull { it.getArgumentName()?.referenceExpression } +
|
||||
listOfNotNull(
|
||||
callExpression.valueArgumentList,
|
||||
callExpression.referenceExpression()
|
||||
)
|
||||
}
|
||||
|
||||
override fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
val element = element ?: return emptyList()
|
||||
|
||||
@@ -567,9 +584,9 @@ internal class ImportForMismatchingArgumentsFix(
|
||||
val resolutionScopeWithAddedImport = resolutionScope.addImportingScope(ExplicitImportsScope(listOf(descriptor)))
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(elementToAnalyze)
|
||||
val newBindingContext = elementToAnalyze.analyzeInContext(
|
||||
resolutionScopeWithAddedImport,
|
||||
dataFlowInfo = dataFlowInfo,
|
||||
contextDependency = ContextDependency.DEPENDENT // to not check complete inference
|
||||
resolutionScopeWithAddedImport,
|
||||
dataFlowInfo = dataFlowInfo,
|
||||
contextDependency = ContextDependency.DEPENDENT // to not check complete inference
|
||||
)
|
||||
return newBindingContext.diagnostics.none { it.severity == Severity.ERROR }
|
||||
}
|
||||
@@ -583,13 +600,13 @@ internal class ImportForMismatchingArgumentsFix(
|
||||
}
|
||||
|
||||
indicesHelper
|
||||
.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext) { it == name }
|
||||
.forEach(::processDescriptor)
|
||||
.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext) { it == name }
|
||||
.forEach(::processDescriptor)
|
||||
|
||||
if (!isSelectorInQualified(element)) {
|
||||
indicesHelper
|
||||
.getTopLevelCallablesByName(name)
|
||||
.forEach(::processDescriptor)
|
||||
.getTopLevelCallablesByName(name)
|
||||
.forEach(::processDescriptor)
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -609,8 +626,7 @@ internal object ImportForMissingOperatorFactory : ImportFixBase.Factory() {
|
||||
override fun createImportAction(diagnostic: Diagnostic): ImportFixBase<*>? {
|
||||
val element = diagnostic.psiElement as? KtExpression ?: return null
|
||||
val operatorDescriptor = Errors.OPERATOR_MODIFIER_REQUIRED.cast(diagnostic).a
|
||||
val name = operatorDescriptor.name
|
||||
when (name) {
|
||||
when (val name = operatorDescriptor.name) {
|
||||
OperatorNameConventions.GET, OperatorNameConventions.SET -> {
|
||||
if (element is KtArrayAccessExpression) {
|
||||
return object : ArrayAccessorImportFix(element, listOf(name), false) {
|
||||
@@ -634,4 +650,6 @@ private fun KotlinIndicesHelper.getClassesByName(expressionForPlatform: KtExpres
|
||||
kindFilter = { kind -> kind != ClassKind.ENUM_ENTRY })
|
||||
}
|
||||
|
||||
private fun CallTypeAndReceiver<*, *>.toFilter() = { descriptor: DeclarationDescriptor -> this.callType.descriptorKindFilter.accepts(descriptor) }
|
||||
private fun CallTypeAndReceiver<*, *>.toFilter() = { descriptor: DeclarationDescriptor ->
|
||||
callType.descriptorKindFilter.accepts(descriptor)
|
||||
}
|
||||
@@ -45,11 +45,7 @@ class MakeClassAnAnnotationClassFix(annotationClass: KtClass) : KotlinQuickFixAc
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val typeReference = diagnostic.psiElement.getNonStrictParentOfType<KtAnnotationEntry>()?.typeReference ?: return null
|
||||
val bindingContext = typeReference.analyze(BodyResolveMode.PARTIAL)
|
||||
val type = bindingContext[BindingContext.TYPE, typeReference] ?: return null
|
||||
val classDescriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
val klass = DescriptorToSourceUtils.descriptorToDeclaration(classDescriptor) as? KtClass ?: return null
|
||||
if (!klass.canRefactor()) return null
|
||||
val klass = typeReference.classForRefactor() ?: return null
|
||||
return MakeClassAnAnnotationClassFix(klass)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user