Find Usages: Support primary constructors

#KT-7881 Fixed
This commit is contained in:
Alexey Sedunov
2015-06-08 18:42:13 +03:00
parent 1ea2c24562
commit e2d758463f
18 changed files with 188 additions and 9 deletions
@@ -79,7 +79,7 @@ public fun PsiReference.matchesTarget(candidateTarget: PsiElement): Boolean {
}
}
// TODO: Workaround for Kotlin constructor search in Java code. To be removed after refactoring of the search API
else if (this is PsiJavaCodeReferenceElement && unwrappedCandidate is JetSecondaryConstructor) {
else if (this is PsiJavaCodeReferenceElement && unwrappedCandidate is JetConstructor<*>) {
var parent = getElement().getParent()
if (parent is PsiAnonymousClass) {
parent = parent.getParent()
@@ -104,7 +104,7 @@ private fun PsiElement.isConstructorOf(unwrappedCandidate: PsiElement) =
// call to Java constructor
(this is PsiMethod && isConstructor() && getContainingClass() == unwrappedCandidate) ||
// call to Kotlin constructor
(this is JetSecondaryConstructor && getStrictParentOfType<JetClass>() == unwrappedCandidate)
(this is JetConstructor<*> && getClassOrObject() == unwrappedCandidate)
fun AbstractJetReference<out JetExpression>.renameImplicitConventionalCall(newName: String?): JetExpression {
if (newName == null) return expression
@@ -86,7 +86,8 @@ fun PsiReference.isConstructorUsage(jetClassOrObject: JetClassOrObject): Boolean
val descriptor = getConstructorCallDescriptor()
if (descriptor !is ConstructorDescriptor) return false
return DescriptorToSourceUtils.descriptorToDeclaration(descriptor.getContainingDeclaration()) == jetClassOrObject
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor.getContainingDeclaration())
return declaration == jetClassOrObject || (declaration is JetConstructor<*> && declaration.getClassOrObject() == jetClassOrObject)
}
checkJavaUsage() || checkKotlinUsage()
@@ -118,7 +119,7 @@ public fun PsiElement.processDelegationCallConstructorUsages(scope: SearchScope,
private fun PsiElement.processDelegationCallKotlinConstructorUsages(scope: SearchScope, process: (JetConstructorDelegationCall) -> Unit) {
val element = unwrapped
val klass = when (element) {
is JetSecondaryConstructor -> element.getClassOrObject()
is JetConstructor<*> -> element.getClassOrObject()
is JetClass -> element
else -> return
}
@@ -46,14 +46,14 @@ public class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandle
element is JetProperty ||
element is JetParameter ||
element is JetTypeParameter ||
element is JetSecondaryConstructor
element is JetConstructor<*>
public override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler? {
val handler = when (element) {
is JetClassOrObject ->
KotlinFindClassUsagesHandler(element, this)
is JetNamedFunction, is JetProperty, is JetParameter, is JetSecondaryConstructor -> {
is JetNamedFunction, is JetProperty, is JetParameter, is JetConstructor<*> -> {
val declaration = element as JetNamedDeclaration
if (forHighlightUsages) return KotlinFindMemberUsagesHandler.getInstance(declaration, this)
@@ -123,7 +123,7 @@ public abstract class KotlinFindMemberUsagesHandler<T extends JetNamedDeclaratio
protected abstract UsagesSearchHelper<T> getSearchHelper(KotlinCallableFindUsagesOptions options);
private static Iterable<PsiMethod> getLightMethods(JetNamedDeclaration element) {
if (element instanceof JetNamedFunction || element instanceof JetSecondaryConstructor) {
if (element instanceof JetFunction) {
PsiMethod method = LightClassUtil.getLightClassMethod((JetFunction) element);
return method != null ? Collections.singletonList(method) : Collections.<PsiMethod>emptyList();
}
@@ -163,7 +163,7 @@ public abstract class KotlinFindMemberUsagesHandler<T extends JetNamedDeclaratio
PsiMethod psiMethod =
element instanceof PsiMethod
? (PsiMethod) element
: element instanceof JetSecondaryConstructor
: element instanceof JetConstructor
? LightClassUtil.getLightClassMethod((JetFunction) element)
: null;
if (psiMethod != null) {
@@ -17,12 +17,22 @@
package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.codeInsight.TargetElementEvaluator
import com.intellij.codeInsight.TargetElementEvaluatorEx
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import com.intellij.psi.PsiReference
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetPrimaryConstructor
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
public class JetTargetElementEvaluator : TargetElementEvaluator {
public class JetTargetElementEvaluator : TargetElementEvaluatorEx {
override fun includeSelfInGotoImplementation(element: PsiElement): Boolean = !(element is JetClass && element.isAbstract())
override fun getElementByReference(ref: PsiReference, flags: Int): PsiElement? = null
override fun isIdentifierPart(file: PsiFile, text: CharSequence?, offset: Int): Boolean {
// '(' is considered identifier part if it belongs to primary constructor without 'constructor' keyword
return file.findElementAt(offset)?.getNonStrictParentOfType<JetPrimaryConstructor>()?.getTextOffset() == offset
}
}
@@ -0,0 +1,14 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// OPTIONS: usages
// FIND_BY_REF
// WITH_FILE_NAME
class J extends A {
constructor(n: Int) {
super(n);
}
static void test() {
new A();
new <caret>A(1);
}
}
@@ -0,0 +1,14 @@
open class A (n: Int) {
constructor(): this(1)
}
class B: A {
constructor(n: Int): super(n)
}
class C(): A(1)
fun test() {
A()
A(1)
}
@@ -0,0 +1,6 @@
[primaryConstructorByJavaRef.0.java] New instance creation (12: 13) new A(1);
[primaryConstructorByJavaRef.0.java] Unclassified usage (7: 9) super(n);
[primaryConstructorByJavaRef.1.kt] New instance creation (13: 5) A(1)
[primaryConstructorByJavaRef.1.kt] Supertype (9: 12) class C(): A(1)
[primaryConstructorByJavaRef.1.kt] Unclassified usage (2: 20) constructor(): this(1)
[primaryConstructorByJavaRef.1.kt] Unclassified usage (6: 26) constructor(n: Int): super(n)
@@ -0,0 +1,14 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// OPTIONS: usages
// FIND_BY_REF
// WITH_FILE_NAME
class J extends A {
constructor(n: Int) {
<caret>super(n);
}
static void test() {
new A();
new A(1);
}
}
@@ -0,0 +1,14 @@
open class A (n: Int) {
constructor(): this(1)
}
class B: A {
constructor(n: Int): super(n)
}
class C(): A(1)
fun test() {
A()
A(1)
}
@@ -0,0 +1,6 @@
[primaryConstructorByJavaSuperRef.0.java] New instance creation (12: 13) new A(1);
[primaryConstructorByJavaSuperRef.0.java] Unclassified usage (7: 9) super(n);
[primaryConstructorByJavaSuperRef.1.kt] New instance creation (13: 5) A(1)
[primaryConstructorByJavaSuperRef.1.kt] Supertype (9: 12) class C(): A(1)
[primaryConstructorByJavaSuperRef.1.kt] Unclassified usage (2: 20) constructor(): this(1)
[primaryConstructorByJavaSuperRef.1.kt] Unclassified usage (6: 26) constructor(n: Int): super(n)
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetPrimaryConstructor
// OPTIONS: usages
// FIND_BY_REF
open class A (n: Int) {
constructor(): this(1)
}
class B: A {
constructor(n: Int): super(n)
}
class C(): A(1)
fun test() {
A()
<caret>A(1)
}
@@ -0,0 +1,4 @@
New instance creation (16: 5) A(1)
Supertype (12: 12) class C(): A(1)
Unclassified usage (5: 20) constructor(): this(1)
Unclassified usage (9: 26) constructor(n: Int): super(n)
@@ -0,0 +1,16 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetPrimaryConstructor
// OPTIONS: usages
open class A <caret>(n: Int) {
constructor(): this(1)
}
class B: A {
constructor(n: Int): super(n)
}
class C(): A(1)
fun test() {
A()
A(1)
}
@@ -0,0 +1,4 @@
New instance creation (15: 5) A(1)
Supertype (11: 12) class C(): A(1)
Unclassified usage (4: 20) constructor(): this(1)
Unclassified usage (8: 26) constructor(n: Int): super(n)
@@ -0,0 +1,16 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetPrimaryConstructor
// OPTIONS: usages
open class A <caret>constructor(n: Int) {
constructor(): this(1)
}
class B: A {
constructor(n: Int): super(n)
}
class C(): A(1)
fun test() {
A()
A(1)
}
@@ -0,0 +1,4 @@
New instance creation (15: 5) A(1)
Supertype (11: 12) class C(): A(1)
Unclassified usage (4: 20) constructor(): this(1)
Unclassified usage (8: 26) constructor(n: Int): super(n)
@@ -736,6 +736,33 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
}
}
@TestMetadata("idea/testData/findUsages/kotlin/findPrimaryConstructorUsages")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FindPrimaryConstructorUsages extends AbstractJetFindUsagesTest {
public void testAllFilesPresentInFindPrimaryConstructorUsages() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/findPrimaryConstructorUsages"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
}
@TestMetadata("primaryConstructorByRef.0.kt")
public void testPrimaryConstructorByRef() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findPrimaryConstructorUsages/primaryConstructorByRef.0.kt");
doTest(fileName);
}
@TestMetadata("primaryConstructorNoKeyword.0.kt")
public void testPrimaryConstructorNoKeyword() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findPrimaryConstructorUsages/primaryConstructorNoKeyword.0.kt");
doTest(fileName);
}
@TestMetadata("primaryConstructorWithKeyword.0.kt")
public void testPrimaryConstructorWithKeyword() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findPrimaryConstructorUsages/primaryConstructorWithKeyword.0.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/findUsages/kotlin/findPropertyUsages")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1056,6 +1083,18 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
doTest(fileName);
}
@TestMetadata("primaryConstructorByJavaRef.0.java")
public void testPrimaryConstructorByJavaRef() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findConstructorUsages/primaryConstructorByJavaRef.0.java");
doTest(fileName);
}
@TestMetadata("primaryConstructorByJavaSuperRef.0.java")
public void testPrimaryConstructorByJavaSuperRef() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findConstructorUsages/primaryConstructorByJavaSuperRef.0.java");
doTest(fileName);
}
@TestMetadata("secondaryConstructorByJavaNewExpression.0.java")
public void testSecondaryConstructorByJavaNewExpression() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findConstructorUsages/secondaryConstructorByJavaNewExpression.0.java");