Navigate to receiver from this in extension function (KT-16991)
#KT-16991 Fixed #KT-13013 In Progress
This commit is contained in:
+18
-1
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.util.BitUtil
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||
import org.jetbrains.kotlin.idea.intentions.isAutoCreatedItUsage
|
||||
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
|
||||
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
class KotlinTargetElementEvaluator : TargetElementEvaluatorEx {
|
||||
@@ -48,6 +50,20 @@ class KotlinTargetElementEvaluator : TargetElementEvaluatorEx {
|
||||
val lambdaExpression = descriptorWithSource.source.getPsi()?.parent as? KtLambdaExpression ?: return null
|
||||
return lambdaExpression.leftCurlyBrace.treeNext?.psi
|
||||
}
|
||||
|
||||
// Navigate to receiver element for this in extension declaration
|
||||
fun findReceiverForThisInExtensionFunction(ref: PsiReference): PsiElement? {
|
||||
val element: PsiElement = ref.element
|
||||
if (element.text != "this") return null
|
||||
|
||||
if (element !is KtNameReferenceExpression) return null
|
||||
val callableDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() as? CallableDescriptor ?: return null
|
||||
|
||||
if (!callableDescriptor.isExtension) return null
|
||||
val callableDeclaration = callableDescriptor.source.getPsi() as? KtCallableDeclaration ?: return null
|
||||
|
||||
return callableDeclaration.receiverTypeReference
|
||||
}
|
||||
}
|
||||
|
||||
override fun includeSelfInGotoImplementation(element: PsiElement): Boolean = !(element is KtClass && element.isAbstract())
|
||||
@@ -67,7 +83,8 @@ class KotlinTargetElementEvaluator : TargetElementEvaluatorEx {
|
||||
}
|
||||
|
||||
if (BitUtil.isSet(flags, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED)) {
|
||||
return findLambdaOpenLBraceForGeneratedIt(ref)
|
||||
return findLambdaOpenLBraceForGeneratedIt(ref) ?:
|
||||
findReceiverForThisInExtensionFunction(ref)
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// FILE: before.kt
|
||||
class A {
|
||||
fun String.foo() {
|
||||
this<caret>@A
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: after.kt
|
||||
class <caret>A {
|
||||
fun String.foo() {
|
||||
this@A
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// FILE: before.kt
|
||||
class A {
|
||||
fun String.foo() {
|
||||
this<caret>@foo
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: after.kt
|
||||
class A {
|
||||
fun <caret>String.foo() {
|
||||
this@foo
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// FILE: before.kt
|
||||
interface Foo
|
||||
|
||||
fun foo(a: Any) {}
|
||||
|
||||
fun Foo.bar() {
|
||||
foo(this<caret>)
|
||||
}
|
||||
|
||||
|
||||
// FILE: after.kt
|
||||
interface Foo
|
||||
|
||||
fun foo(a: Any) {}
|
||||
|
||||
fun <caret>Foo.bar() {
|
||||
foo(this)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// FILE: before.kt
|
||||
interface Foo
|
||||
|
||||
fun foo(a: Foo.() -> Unit) {}
|
||||
|
||||
fun bar() {
|
||||
foo {
|
||||
<caret>this
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: after.kt
|
||||
interface Foo
|
||||
|
||||
fun foo(a: Foo.() -> Unit) {}
|
||||
|
||||
fun bar() {
|
||||
foo <caret>{
|
||||
this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// FILE: before.kt
|
||||
val String.test: String
|
||||
get() { return <caret>this }
|
||||
|
||||
// FILE: after.kt
|
||||
val <caret>String.test: String
|
||||
get() { return this }
|
||||
@@ -65,4 +65,34 @@ public class GotoDeclarationTestGenerated extends AbstractGotoDeclarationTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/itParameterInLambda.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledThisToClass.test")
|
||||
public void testLabeledThisToClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/labeledThisToClass.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledThisToMemberExtension.test")
|
||||
public void testLabeledThisToMemberExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/labeledThisToMemberExtension.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("thisExtensionFunction.test")
|
||||
public void testThisExtensionFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/thisExtensionFunction.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("thisExtensionLambda.test")
|
||||
public void testThisExtensionLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/thisExtensionLambda.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("thisInExtensionPropertyAccessor.test")
|
||||
public void testThisInExtensionPropertyAccessor() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/thisInExtensionPropertyAccessor.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user