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