Fix fq-names of top-level extensions in intentions.
This commit is contained in:
@@ -34,7 +34,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
public class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(javaClass(), "Add indices to 'for' loop"), LowPriorityAction {
|
||||
private val WITH_INDEX_FQ_NAME = "kotlin.withIndex"
|
||||
private val WITH_INDEX_NAME = "withIndex"
|
||||
private val WITH_INDEX_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
|
||||
|
||||
override fun applicabilityRange(element: KtForExpression): TextRange? {
|
||||
if (element.loopParameter == null) return null
|
||||
@@ -43,14 +44,14 @@ public class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpre
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
val resolvedCall = loopRange.getResolvedCall(bindingContext)
|
||||
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() == WITH_INDEX_FQ_NAME) return null // already withIndex() call
|
||||
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() in WITH_INDEX_FQ_NAMES) return null // already withIndex() call
|
||||
|
||||
val resolutionScope = element.getResolutionScope(bindingContext, element.getResolutionFacade())
|
||||
val potentialExpression = createWithIndexExpression(loopRange)
|
||||
|
||||
val newBindingContext = potentialExpression.analyzeInContext(resolutionScope, loopRange)
|
||||
val newResolvedCall = potentialExpression.getResolvedCall(newBindingContext) ?: return null
|
||||
if (newResolvedCall.resultingDescriptor.fqNameUnsafe.asString() != WITH_INDEX_FQ_NAME) return null
|
||||
if (newResolvedCall.resultingDescriptor.fqNameUnsafe.asString() !in WITH_INDEX_FQ_NAMES) return null
|
||||
|
||||
return TextRange(element.startOffset, element.body?.startOffset ?: element.endOffset)
|
||||
}
|
||||
@@ -99,6 +100,6 @@ public class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpre
|
||||
}
|
||||
|
||||
private fun createWithIndexExpression(originalExpression: KtExpression): KtExpression {
|
||||
return KtPsiFactory(originalExpression).createExpressionByPattern("$0.withIndex()", originalExpression)
|
||||
return KtPsiFactory(originalExpression).createExpressionByPattern("$0.$WITH_INDEX_NAME()", originalExpression)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,12 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
|
||||
public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIntention<KtSimpleNameExpression>(javaClass(), "Replace with a 'for' loop") {
|
||||
private val FOR_EACH_NAME = "forEach"
|
||||
private val FOR_EACH_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$FOR_EACH_NAME" }.toSet()
|
||||
|
||||
|
||||
override fun isApplicableTo(element: KtSimpleNameExpression): Boolean {
|
||||
if (element.getReferencedName() != "forEach") return false
|
||||
if (element.getReferencedName() != FOR_EACH_NAME) return false
|
||||
|
||||
val data = extractData(element) ?: return false
|
||||
if (data.functionLiteral.getValueParameters().size() > 1) return false
|
||||
@@ -61,7 +65,7 @@ public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIn
|
||||
} ?: return null) as KtExpression //TODO: submit bug
|
||||
|
||||
val resolvedCall = expression.getResolvedCall(expression.analyze()) ?: return null
|
||||
if (DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() != "kotlin.forEach") return null
|
||||
if (DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() !in FOR_EACH_FQ_NAMES) return null
|
||||
|
||||
val receiver = resolvedCall.getCall().getExplicitReceiver() as? ExpressionReceiver ?: return null
|
||||
val argument = resolvedCall.getCall().getValueArguments().singleOrNull() ?: return null
|
||||
|
||||
@@ -41,7 +41,8 @@ public class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpr
|
||||
}
|
||||
|
||||
public class RemoveForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(javaClass(), "Remove indices in 'for' loop") {
|
||||
private val WITH_INDEX_FQ_NAME = "kotlin.withIndex"
|
||||
private val WITH_INDEX_NAME = "withIndex"
|
||||
private val WITH_INDEX_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
|
||||
|
||||
override fun applicabilityRange(element: KtForExpression): TextRange? {
|
||||
val loopRange = element.loopRange as? KtDotQualifiedExpression ?: return null
|
||||
@@ -51,7 +52,7 @@ public class RemoveForLoopIndicesIntention : SelfTargetingRangeIntention<KtForEx
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
val resolvedCall = loopRange.getResolvedCall(bindingContext)
|
||||
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() != WITH_INDEX_FQ_NAME) return null
|
||||
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() !in WITH_INDEX_FQ_NAMES) return null
|
||||
|
||||
val indexVar = multiParameter.entries[0]
|
||||
if (ReferencesSearch.search(indexVar).any()) return null
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo() {
|
||||
val x = "abcd"
|
||||
|
||||
x.forEach<caret> { it.equals('a') }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo() {
|
||||
val x = "abcd"
|
||||
|
||||
for (it in x) {
|
||||
it.equals('a')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo() {
|
||||
val x = (1..4).asSequence()
|
||||
|
||||
x.forEach<caret> { it.equals(1) }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo() {
|
||||
val x = (1..4).asSequence()
|
||||
|
||||
for (it in x) {
|
||||
it.equals(1)
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo(bar: CharSequence) {
|
||||
for ((i<caret>,a) in bar.withIndex()) {
|
||||
|
||||
}
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo(bar: CharSequence) {
|
||||
for (a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo(bar: Sequence<String>) {
|
||||
for ((i<caret>,a) in bar.withIndex()) {
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo(bar: Sequence<String>) {
|
||||
for (a in bar) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3187,6 +3187,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleCharSequence.kt")
|
||||
public void testSimpleCharSequence() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertForEachToForLoop/simpleCharSequence.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleSequence.kt")
|
||||
public void testSimpleSequence() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertForEachToForLoop/simpleSequence.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeArgumentPresent.kt")
|
||||
public void testTypeArgumentPresent() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertForEachToForLoop/typeArgumentPresent.kt");
|
||||
@@ -6932,6 +6944,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndices.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleLoopWithIndicesOverCharSequence.kt")
|
||||
public void testSimpleLoopWithIndicesOverCharSequence() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndicesOverCharSequence.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleLoopWithIndicesOverSequence.kt")
|
||||
public void testSimpleLoopWithIndicesOverSequence() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeForLoopIndices/simpleLoopWithIndicesOverSequence.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/removeUnnecessaryParentheses")
|
||||
|
||||
Reference in New Issue
Block a user