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
}
}
else {
if (targets.any { unwrappedCandidate.isConstructorOf(it) }) return true
// 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) {
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) {
val referredClass = unwrappedTargets.first()
@@ -40,6 +40,11 @@ import org.jetbrains.kotlin.idea.util.application.runReadAction
import java.util.Collections
import com.intellij.find.findUsages.JavaFindUsagesHandler
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(
jetClass: JetClassOrObject,
@@ -78,12 +83,23 @@ public class KotlinFindClassUsagesHandler(
val classOrObject = element as JetClassOrObject
val uniqueProcessor = CommonProcessors.UniqueProcessor(processor)
return runReadAction {
val target = kotlinOptions.toSearchTarget(classOrObject, true)
val classUsages = kotlinOptions.toClassHelper().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.search.PsiElementProcessor;
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.util.CommonProcessors;
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.Nullable;
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.dialogs.KotlinFindFunctionUsagesDialog;
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.usagesSearch.UsagesSearch;
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.psi.*;
@@ -158,18 +153,23 @@ public abstract class KotlinFindMemberUsagesHandler<T extends JetNamedDeclaratio
UsagesSearchRequest request =
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)) {
processUsage(processor, ref);
processUsage(uniqueProcessor, ref);
}
if (element instanceof JetSecondaryConstructor || element instanceof PsiMethod) {
UsagesSearchPackage.processDelegationCallConstructorUsages(element, options.searchScope, new Function1<PsiElement, Unit>() {
@Override
public Unit invoke(PsiElement element) {
processUsage(processor, element);
return null;
}
});
PsiMethod psiMethod =
element instanceof PsiMethod
? (PsiMethod) element
: element instanceof JetSecondaryConstructor
? LightClassUtil.getLightClassMethod((JetFunction) element)
: null;
if (psiMethod != null) {
for (PsiReference ref : MethodReferencesSearch.search(psiMethod, options.searchScope, true)) {
processUsage(uniqueProcessor, ref.getElement());
}
}
if (kotlinOptions.getSearchOverrides()) {
@@ -180,7 +180,7 @@ public abstract class KotlinFindMemberUsagesHandler<T extends JetNamedDeclaratio
new PsiElementProcessor<PsiMethod>() {
@Override
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
open class <caret>Server {
constructor(name: String): this() {
}
companion object {
val NAME = "Server"
}
@@ -25,6 +25,16 @@ object ClientObject: Server() {
}
class Client2: Server {
constructor(name: String) {
}
constructor(): super() {
}
}
fun Client.bar(s: Server) {
foo(s)
}
@@ -1,2 +1,5 @@
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 (13: 9) set(value: 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 (9: 9) get() {
Unclassified usage (9: 9) get() {
@@ -1,8 +1,6 @@
Unclassified usage (11: 9) set(value: String) {
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 (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: 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.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.JetTestUtils;
import static com.intellij.codeInsight.TargetElementUtil.*;
import java.io.File;
import java.io.FilenameFilter;
@@ -326,7 +327,7 @@ public abstract class AbstractJetFindUsagesTest extends JetLightCodeInsightFixtu
PsiElement originalElement =
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();
if (InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// FIND_BY_MIRROR_ELEMENT")) {
assert originalElement instanceof PsiCompiledElement : "PsiCompiledElement is expected: " + originalElement;
@@ -45,6 +45,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
Kotlin.FindPackageUsages.class,
Kotlin.FindParameterUsages.class,
Kotlin.FindPropertyUsages.class,
Kotlin.FindSecondaryConstructorUsages.class,
Kotlin.FindTypeParameterUsages.class,
Kotlin.FindWithFilteringImports.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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1000,6 +1022,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
@TestMetadata("idea/testData/findUsages/java")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({
Java.FindConstructorUsages.class,
Java.FindJavaClassUsages.class,
Java.FindJavaFieldUsages.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);
}
@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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)