Smaller availability range for add argument name intention

This commit is contained in:
Valentin Kipyatkov
2015-06-24 11:22:45 +02:00
parent 9d83510af5
commit 98c0c636b3
14 changed files with 71 additions and 19 deletions
@@ -216,6 +216,8 @@ public fun PsiElement.getStartOffsetIn(ancestor: PsiElement): Int {
return offset
}
public fun TextRange.containsInside(offset: Int): Boolean = getStartOffset() < offset && offset < getEndOffset()
public val PsiChildRange.textRange: TextRange?
get() {
if (isEmpty) return null
@@ -25,14 +25,14 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.psiUtil.containsInside
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
public abstract class JetSelfTargetingIntention<TElement : JetElement>(
public val elementType: Class<TElement>,
private var text: String,
private val familyName: String = text,
private val firstElementOfTypeOnly: Boolean = false
private val familyName: String = text
) : IntentionAction {
protected val defaultText: String = text
@@ -65,16 +65,17 @@ public abstract class JetSelfTargetingIntention<TElement : JetElement>(
elementsToCheck += commonParent.parentsWithSelf
}
val elementsOfType = elementsToCheck.filterIsInstance(elementType)
if (firstElementOfTypeOnly) {
val candidate = elementsOfType.firstOrNull() ?: return null
return if (isApplicableTo(candidate, offset)) candidate else null
}
else {
return elementsOfType.firstOrNull { isApplicableTo(it, offset) }
for (element in elementsToCheck) {
if (elementType.isInstance(element) && isApplicableTo(element as TElement, offset)) {
return element as TElement
}
if (!allowCaretInsideElement(element) && element.getTextRange().containsInside(offset)) break
}
return null
}
protected open fun allowCaretInsideElement(element: PsiElement): Boolean = true
final override fun isAvailable(project: Project, editor: Editor, file: PsiFile)
= getTarget(editor, file) != null
@@ -91,9 +92,8 @@ public abstract class JetSelfTargetingIntention<TElement : JetElement>(
public abstract class JetSelfTargetingRangeIntention<TElement : JetElement>(
elementType: Class<TElement>,
text: String,
familyName: String = text,
firstElementOfTypeOnly: Boolean = false
) : JetSelfTargetingIntention<TElement>(elementType, text, familyName, firstElementOfTypeOnly) {
familyName: String = text
) : JetSelfTargetingIntention<TElement>(elementType, text, familyName) {
public abstract fun applicabilityRange(element: TElement): TextRange?
@@ -106,9 +106,8 @@ public abstract class JetSelfTargetingRangeIntention<TElement : JetElement>(
public abstract class JetSelfTargetingOffsetIndependentIntention<TElement : JetElement>(
elementType: Class<TElement>,
text: String,
familyName: String = text,
firstElementOfTypeOnly: Boolean = false
) : JetSelfTargetingRangeIntention<TElement>(elementType, text, familyName, firstElementOfTypeOnly) {
familyName: String = text
) : JetSelfTargetingRangeIntention<TElement>(elementType, text, familyName) {
public abstract fun isApplicableTo(element: TElement): Boolean
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.conversion.copy.end
import org.jetbrains.kotlin.idea.conversion.copy.start
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus
@@ -44,6 +46,9 @@ public class AddNameToArgumentIntention
return true
}
override fun allowCaretInsideElement(element: PsiElement)
= element !is JetValueArgumentList && element !is JetContainerNode
override fun applyTo(element: JetValueArgument, editor: Editor) {
val name = detectNameToAdd(element)!!
val newArgument = JetPsiFactory(element).createArgument(element.getArgumentExpression()!!, name, element.getSpreadElement() != null)
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -25,7 +26,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.JetType
public class ConvertToBlockBodyIntention : JetSelfTargetingIntention<JetDeclarationWithBody>(
javaClass(), "Convert to block body", firstElementOfTypeOnly = true
javaClass(), "Convert to block body"
) {
override fun isApplicableTo(element: JetDeclarationWithBody, caretOffset: Int): Boolean {
if (element is JetFunctionLiteral || element.hasBlockBody() || !element.hasBody()) return false
@@ -43,6 +44,8 @@ public class ConvertToBlockBodyIntention : JetSelfTargetingIntention<JetDeclarat
}
}
override fun allowCaretInsideElement(element: PsiElement) = element !is JetDeclaration
override fun applyTo(element: JetDeclarationWithBody, editor: Editor) {
convert(element)
}
@@ -33,13 +33,15 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependentIntention<JetDeclarationWithBody>(
javaClass(), "Convert to expression body", firstElementOfTypeOnly = true
javaClass(), "Convert to expression body"
) {
override fun isApplicableTo(element: JetDeclarationWithBody): Boolean {
val value = calcValue(element)
return value != null && !containsReturn(value)
}
override fun allowCaretInsideElement(element: PsiElement) = element !is JetDeclaration
override fun applyTo(element: JetDeclarationWithBody, editor: Editor) {
applyToInternal(element) {
val typeRef = it.getTypeReference()!!
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.core.moveInsideParentheses
import org.jetbrains.kotlin.psi.JetFunctionLiteralArgument
import org.jetbrains.kotlin.psi.psiUtil.containsInside
public class MoveLambdaInsideParenthesesIntention : JetSelfTargetingIntention<JetFunctionLiteralArgument>(javaClass(), "Move lambda argument into parentheses"), LowPriorityAction {
override fun isApplicableTo(element: JetFunctionLiteralArgument, caretOffset: Int): Boolean {
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containsInside
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.JetParenthesizedExpression
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.containsInside
public class RemoveUnnecessaryParenthesesIntention : JetSelfTargetingIntention<JetParenthesizedExpression>(javaClass(), "Remove unnecessary parentheses") {
override fun isApplicableTo(element: JetParenthesizedExpression, caretOffset: Int): Boolean {
@@ -63,8 +63,6 @@ fun JetContainerNode.description(): String? {
return null
}
fun TextRange.containsInside(offset: Int) = getStartOffset() < offset && offset < getEndOffset()
fun isAutoCreatedItUsage(expression: JetSimpleNameExpression): Boolean {
if (expression.getReferencedName() != "it") return false
val context = expression.analyze()
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
fun foo(p: Int){}
fun bar(list: List<Int>) {
foo(list[<caret>1])
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
fun foo(p: Int){}
fun bar() {
foo("".hashCode(<caret>))
}
@@ -0,0 +1,5 @@
fun foo(p: Int){}
fun bar() {
foo("".hashCode<caret>())
}
@@ -0,0 +1,5 @@
fun foo(p: Int){}
fun bar() {
foo(p = "".hashCode<caret>())
}
@@ -130,6 +130,24 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("notInsideIndices.kt")
public void testNotInsideIndices() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addNameToArgument/notInsideIndices.kt");
doTest(fileName);
}
@TestMetadata("notInsideNestedArgumentList.kt")
public void testNotInsideNestedArgumentList() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addNameToArgument/notInsideNestedArgumentList.kt");
doTest(fileName);
}
@TestMetadata("notInsideNestedArgumentList2.kt")
public void testNotInsideNestedArgumentList2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addNameToArgument/notInsideNestedArgumentList2.kt");
doTest(fileName);
}
@TestMetadata("notLast.kt")
public void testNotLast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/addNameToArgument/notLast.kt");