Find Usages: Support of secondary constructors and delegation calls

This commit is contained in:
Alexey Sedunov
2015-03-19 21:08:52 +03:00
parent 312a1db273
commit d19e6337a3
28 changed files with 342 additions and 27 deletions
@@ -54,8 +54,13 @@ public fun PsiReference.matchesTarget(candidateTarget: PsiElement): Boolean {
|| it is JetObjectDeclaration && it.isCompanion() && it.getNonStrictParentOfType<JetClass>() == unwrappedCandidate || it is JetObjectDeclaration && it.isCompanion() && it.getNonStrictParentOfType<JetClass>() == unwrappedCandidate
} }
} }
else { // TODO: Workaround for Kotlin constructor search in Java code. To be removed after refactoring of the search API
if (targets.any { unwrappedCandidate.isConstructorOf(it) }) return true else if (this is PsiJavaCodeReferenceElement && unwrappedCandidate is JetSecondaryConstructor) {
var parent = getElement().getParent()
if (parent is PsiAnonymousClass) {
parent = parent.getParent()
}
if ((parent as? PsiNewExpression)?.resolveConstructor()?.unwrapped == unwrappedCandidate) return true
} }
if (this is PsiReferenceExpression && candidateTarget is JetObjectDeclaration && unwrappedTargets.size() == 1) { if (this is PsiReferenceExpression && candidateTarget is JetObjectDeclaration && unwrappedTargets.size() == 1) {
val referredClass = unwrappedTargets.first() val referredClass = unwrappedTargets.first()
@@ -40,6 +40,11 @@ import org.jetbrains.kotlin.idea.util.application.runReadAction
import java.util.Collections import java.util.Collections
import com.intellij.find.findUsages.JavaFindUsagesHandler import com.intellij.find.findUsages.JavaFindUsagesHandler
import com.intellij.find.findUsages.JavaFindUsagesHandlerFactory import com.intellij.find.findUsages.JavaFindUsagesHandlerFactory
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.util.CommonProcessors
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
public class KotlinFindClassUsagesHandler( public class KotlinFindClassUsagesHandler(
jetClass: JetClassOrObject, jetClass: JetClassOrObject,
@@ -78,12 +83,23 @@ public class KotlinFindClassUsagesHandler(
val classOrObject = element as JetClassOrObject val classOrObject = element as JetClassOrObject
val uniqueProcessor = CommonProcessors.UniqueProcessor(processor)
return runReadAction { return runReadAction {
val target = kotlinOptions.toSearchTarget(classOrObject, true) val target = kotlinOptions.toSearchTarget(classOrObject, true)
val classUsages = kotlinOptions.toClassHelper().newRequest(target).search() val classUsages = kotlinOptions.toClassHelper().newRequest(target).search()
val declarationUsages = kotlinOptions.toClassDeclarationsHelper().newRequest(target).search() val declarationUsages = kotlinOptions.toClassDeclarationsHelper().newRequest(target).search()
(classUsages + declarationUsages).all { ref -> KotlinFindUsagesHandler.processUsage(processor, ref) } && processInheritors() if (kotlinOptions.searchConstructorUsages) {
val constructors = classOrObject.toLightClass()?.getConstructors() ?: PsiMethod.EMPTY_ARRAY
for (constructor in constructors) {
constructor.processDelegationCallConstructorUsages(constructor.getUseScope()) {
it.getCalleeExpression()?.getReference()?.let { KotlinFindUsagesHandler.processUsage(uniqueProcessor, it) }
}
}
}
(classUsages + declarationUsages).all { KotlinFindUsagesHandler.processUsage(uniqueProcessor, it)} && processInheritors()
} }
} }
@@ -26,17 +26,13 @@ import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference; import com.intellij.psi.PsiReference;
import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageInfo;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor; import com.intellij.util.Processor;
import jet.runtime.typeinfo.JetValueParameter;
import kotlin.Function1;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.LightClassUtil; import org.jetbrains.kotlin.asJava.LightClassUtil;
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.idea.findUsages.*; import org.jetbrains.kotlin.idea.findUsages.*;
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindFunctionUsagesDialog; import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindFunctionUsagesDialog;
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindPropertyUsagesDialog; import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindPropertyUsagesDialog;
@@ -44,7 +40,6 @@ import org.jetbrains.kotlin.idea.search.declarationsSearch.DeclarationsSearchPac
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest; import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest;
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearch; import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearch;
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchHelper; import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchHelper;
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchPackage;
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchRequest; import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchRequest;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
@@ -158,18 +153,23 @@ public abstract class KotlinFindMemberUsagesHandler<T extends JetNamedDeclaratio
UsagesSearchRequest request = UsagesSearchRequest request =
getSearchHelper(kotlinOptions).newRequest(FindUsagesPackage.<T>toSearchTarget(options, (T) element, true)); getSearchHelper(kotlinOptions).newRequest(FindUsagesPackage.<T>toSearchTarget(options, (T) element, true));
final CommonProcessors.UniqueProcessor<UsageInfo> uniqueProcessor =
new CommonProcessors.UniqueProcessor<UsageInfo>(processor);
for (PsiReference ref : UsagesSearch.INSTANCE$.search(request)) { for (PsiReference ref : UsagesSearch.INSTANCE$.search(request)) {
processUsage(processor, ref); processUsage(uniqueProcessor, ref);
} }
if (element instanceof JetSecondaryConstructor || element instanceof PsiMethod) { PsiMethod psiMethod =
UsagesSearchPackage.processDelegationCallConstructorUsages(element, options.searchScope, new Function1<PsiElement, Unit>() { element instanceof PsiMethod
@Override ? (PsiMethod) element
public Unit invoke(PsiElement element) { : element instanceof JetSecondaryConstructor
processUsage(processor, element); ? LightClassUtil.getLightClassMethod((JetFunction) element)
return null; : null;
} if (psiMethod != null) {
}); for (PsiReference ref : MethodReferencesSearch.search(psiMethod, options.searchScope, true)) {
processUsage(uniqueProcessor, ref.getElement());
}
} }
if (kotlinOptions.getSearchOverrides()) { if (kotlinOptions.getSearchOverrides()) {
@@ -180,7 +180,7 @@ public abstract class KotlinFindMemberUsagesHandler<T extends JetNamedDeclaratio
new PsiElementProcessor<PsiMethod>() { new PsiElementProcessor<PsiMethod>() {
@Override @Override
public boolean execute(@NotNull PsiMethod method) { public boolean execute(@NotNull PsiMethod method) {
return processUsage(processor, method.getNavigationElement()); return processUsage(uniqueProcessor, method.getNavigationElement());
} }
} }
) )
@@ -0,0 +1,7 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// OPTIONS: usages
public class J {
public <caret>J(int i) {
}
}
@@ -0,0 +1,13 @@
class A: J {
constructor(): super(1) {
}
}
class B: J(1) {
}
fun test() {
J(2)
}
@@ -0,0 +1,3 @@
New instance creation (12: 5) J(2)
Supertype (7: 10) class B: J(1) {
Unclassified usage (2: 20) constructor(): super(1) {
@@ -0,0 +1,7 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// OPTIONS: usages
public class J {
public <caret>J() {
}
}
@@ -0,0 +1,17 @@
class A: J {
constructor(i: Int): super() {
}
constructor() {
}
}
class B: J() {
}
fun test() {
J()
}
@@ -0,0 +1,4 @@
New instance creation (16: 5) J()
Supertype (11: 10) class B: J() {
Unclassified usage (2: 26) constructor(i: Int): super() {
Unclassified usage (6: 19) constructor() {
@@ -0,0 +1,12 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// FIND_BY_REF
// OPTIONS: usages
public class JJ extends B {
public JJ(int i) {
super("");
}
void test() {
new <caret>B("");
}
}
@@ -0,0 +1,23 @@
open class B {
constructor(): this("") {
}
constructor(s: String) {
}
}
open class A : B {
constructor(a: Int) : super("") {
}
}
class C : B("") {
}
fun test() {
B("")
}
@@ -0,0 +1,6 @@
New instance creation (10: 13) new B("");
New instance creation (22: 5) B("")
Supertype (17: 11) class C : B("") {
Unclassified usage (12: 27) constructor(a: Int) : super("") {
Unclassified usage (2: 20) constructor(): this("") {
Unclassified usage (6: 9) super("");
@@ -0,0 +1,12 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// FIND_BY_REF
// OPTIONS: usages
public class JJ extends B {
public JJ(int i) {
<caret>super("");
}
void test() {
new B("");
}
}
@@ -0,0 +1,23 @@
open class B {
constructor(): this("") {
}
constructor(s: String) {
}
}
open class A : B {
constructor(a: Int) : super("") {
}
}
class C : B("") {
}
fun test() {
B("")
}
@@ -0,0 +1,6 @@
New instance creation (10: 13) new B("");
New instance creation (22: 5) B("")
Supertype (17: 11) class C : B("") {
Unclassified usage (12: 27) constructor(a: Int) : super("") {
Unclassified usage (2: 20) constructor(): this("") {
Unclassified usage (6: 9) super("");
@@ -3,6 +3,10 @@
package server package server
open class <caret>Server { open class <caret>Server {
constructor(name: String): this() {
}
companion object { companion object {
val NAME = "Server" val NAME = "Server"
} }
@@ -25,6 +25,16 @@ object ClientObject: Server() {
} }
class Client2: Server {
constructor(name: String) {
}
constructor(): super() {
}
}
fun Client.bar(s: Server) { fun Client.bar(s: Server) {
foo(s) foo(s)
} }
@@ -1,2 +1,5 @@
Supertype (24: 22) object ClientObject: Server() { Supertype (24: 22) object ClientObject: Server() {
Supertype (5: 15) class Client: Server() { Supertype (5: 15) class Client: Server() {
Unclassified usage (29: 31) constructor(name: String) {
Unclassified usage (33: 20) constructor(): super() {
Unclassified usage (6: 32) constructor(name: String): this() {
@@ -1,6 +1,5 @@
Unclassified usage (12: 17) public void setFoo(String s) { Unclassified usage (12: 17) public void setFoo(String s) {
Unclassified usage (13: 9) set(value: String) { Unclassified usage (13: 9) set(value: String) {
Unclassified usage (25: 18) override var foo: String = "" Unclassified usage (25: 18) override var foo: String = ""
Unclassified usage (25: 18) override var foo: String = ""
Unclassified usage (7: 19) public String getFoo() { Unclassified usage (7: 19) public String getFoo() {
Unclassified usage (9: 9) get() { Unclassified usage (9: 9) get() {
@@ -1,8 +1,6 @@
Unclassified usage (11: 9) set(value: String) { Unclassified usage (11: 9) set(value: String) {
Unclassified usage (12: 17) public void setFoo(String s) { Unclassified usage (12: 17) public void setFoo(String s) {
Unclassified usage (23: 18) override var foo: String = "" Unclassified usage (23: 18) override var foo: String = ""
Unclassified usage (23: 18) override var foo: String = ""
Unclassified usage (26: 30) open class E<T>(override var foo: T): A<T>(foo)
Unclassified usage (26: 30) open class E<T>(override var foo: T): A<T>(foo) Unclassified usage (26: 30) open class E<T>(override var foo: T): A<T>(foo)
Unclassified usage (7: 19) public String getFoo() { Unclassified usage (7: 19) public String getFoo() {
Unclassified usage (7: 9) get() { Unclassified usage (7: 9) get() {
@@ -0,0 +1,29 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetSecondaryConstructor
// OPTIONS: usages
open class B {
<caret>constructor() {
}
constructor(a: Int): this() {
}
}
class A : B {
constructor(a: Int) : super() {
}
constructor() {
}
}
class C : B() {
}
fun test() {
B()
}
@@ -0,0 +1,13 @@
public class J extends B {
public J(int i) {
super();
}
public J() {
}
void test() {
new B();
}
}
@@ -0,0 +1,8 @@
New instance creation (11: 13) new B();
New instance creation (28: 5) B()
Supertype (23: 11) class C : B() {
Unclassified usage (14: 27) constructor(a: Int) : super() {
Unclassified usage (18: 19) constructor() {
Unclassified usage (3: 9) super();
Unclassified usage (6: 12) public J() {
Unclassified usage (8: 26) constructor(a: Int): this() {
@@ -0,0 +1,25 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetSecondaryConstructor
// OPTIONS: usages
open class B {
constructor(): this("") {
}
<caret>constructor(s: String) {
}
}
open class A : B {
constructor(a: Int) : super("") {
}
}
class C: B("") {
}
fun test() {
B("")
}
@@ -0,0 +1,9 @@
public class JJ extends B {
public JJ(int i) {
super("");
}
void test() {
new B("");
}
}
@@ -0,0 +1,6 @@
New instance creation (24: 5) B("")
New instance creation (7: 13) new B("");
Supertype (19: 10) class C: B("") {
Unclassified usage (14: 27) constructor(a: Int) : super("") {
Unclassified usage (3: 9) super("");
Unclassified usage (4: 20) constructor(): this("") {
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.jetbrains.kotlin.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.JetTestUtils; import org.jetbrains.kotlin.test.JetTestUtils;
import static com.intellij.codeInsight.TargetElementUtil.*;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
@@ -326,7 +327,7 @@ public abstract class AbstractJetFindUsagesTest extends JetLightCodeInsightFixtu
PsiElement originalElement = PsiElement originalElement =
InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// FIND_BY_REF") InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// FIND_BY_REF")
? TargetElementUtilBase.findTargetElement(myFixture.getEditor(), TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED) ? TargetElementUtilBase.findTargetElement(myFixture.getEditor(), REFERENCED_ELEMENT_ACCEPTED | NEW_AS_CONSTRUCTOR)
: myFixture.getElementAtCaret(); : myFixture.getElementAtCaret();
if (InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// FIND_BY_MIRROR_ELEMENT")) { if (InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// FIND_BY_MIRROR_ELEMENT")) {
assert originalElement instanceof PsiCompiledElement : "PsiCompiledElement is expected: " + originalElement; assert originalElement instanceof PsiCompiledElement : "PsiCompiledElement is expected: " + originalElement;
@@ -45,6 +45,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
Kotlin.FindPackageUsages.class, Kotlin.FindPackageUsages.class,
Kotlin.FindParameterUsages.class, Kotlin.FindParameterUsages.class,
Kotlin.FindPropertyUsages.class, Kotlin.FindPropertyUsages.class,
Kotlin.FindSecondaryConstructorUsages.class,
Kotlin.FindTypeParameterUsages.class, Kotlin.FindTypeParameterUsages.class,
Kotlin.FindWithFilteringImports.class, Kotlin.FindWithFilteringImports.class,
Kotlin.FindWithStructuralGrouping.class, Kotlin.FindWithStructuralGrouping.class,
@@ -879,6 +880,27 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
} }
} }
@TestMetadata("idea/testData/findUsages/kotlin/findSecondaryConstructorUsages")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FindSecondaryConstructorUsages extends AbstractJetFindUsagesTest {
public void testAllFilesPresentInFindSecondaryConstructorUsages() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/findSecondaryConstructorUsages"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
}
@TestMetadata("defaultSecondaryConstructor.0.kt")
public void testDefaultSecondaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findSecondaryConstructorUsages/defaultSecondaryConstructor.0.kt");
doTest(fileName);
}
@TestMetadata("secondaryConstructor.0.kt")
public void testSecondaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findSecondaryConstructorUsages/secondaryConstructor.0.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/findUsages/kotlin/findTypeParameterUsages") @TestMetadata("idea/testData/findUsages/kotlin/findTypeParameterUsages")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1000,6 +1022,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
@TestMetadata("idea/testData/findUsages/java") @TestMetadata("idea/testData/findUsages/java")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({ @InnerTestClasses({
Java.FindConstructorUsages.class,
Java.FindJavaClassUsages.class, Java.FindJavaClassUsages.class,
Java.FindJavaFieldUsages.class, Java.FindJavaFieldUsages.class,
Java.FindJavaMethodUsages.class, Java.FindJavaMethodUsages.class,
@@ -1010,6 +1033,39 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/java"), Pattern.compile("^(.+)\\.0\\.java$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/java"), Pattern.compile("^(.+)\\.0\\.java$"), true);
} }
@TestMetadata("idea/testData/findUsages/java/findConstructorUsages")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FindConstructorUsages extends AbstractJetFindUsagesTest {
public void testAllFilesPresentInFindConstructorUsages() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/java/findConstructorUsages"), Pattern.compile("^(.+)\\.0\\.java$"), true);
}
@TestMetadata("javaConstructorInDelegationCall.0.java")
public void testJavaConstructorInDelegationCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findConstructorUsages/javaConstructorInDelegationCall.0.java");
doTest(fileName);
}
@TestMetadata("javaDefaultConstructorInDelegationCall.0.java")
public void testJavaDefaultConstructorInDelegationCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findConstructorUsages/javaDefaultConstructorInDelegationCall.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");
doTest(fileName);
}
@TestMetadata("secondaryConstructorByJavaSuperCall.0.java")
public void testSecondaryConstructorByJavaSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findConstructorUsages/secondaryConstructorByJavaSuperCall.0.java");
doTest(fileName);
}
}
@TestMetadata("idea/testData/findUsages/java/findJavaClassUsages") @TestMetadata("idea/testData/findUsages/java/findJavaClassUsages")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)