Implement search of derived Kotlin classes/traits and Java classes/interfaces

This commit is contained in:
Alexey Sedunov
2013-08-14 15:44:29 +04:00
parent a7e46a4ba7
commit 7357add55c
30 changed files with 395 additions and 41 deletions
@@ -272,6 +272,7 @@ find.what.overriding.methods.checkbox=Over&riding functions
find.options.include.overloaded.methods.checkbox=Include o&verloaded functions and extensions
find.what.functions.usages.checkbox=Usages of &functions
find.what.properties.usages.checkbox=Usages of &properties
find.what.constructor.usages.checkbox=Usages of &constructor
find.what.derived.traits.checkbox=&Derived traits
find.what.derived.classes.checkbox=&Derived classes
@@ -19,6 +19,8 @@ import javax.swing.*;
public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
private StateRestoringCheckBox constructorUsages;
private StateRestoringCheckBox derivedClasses;
private StateRestoringCheckBox derivedTraits;
public KotlinFindClassUsagesDialog(
PsiClass klass,
@@ -47,22 +49,22 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
FindBundle.message("find.what.fields.usages.checkbox"),
JetBundle.message("find.what.properties.usages.checkbox")
);
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.implementing.classes.checkbox"),
JetBundle.message("find.what.implementing.classes.checkbox")
);
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.derived.interfaces.checkbox"),
JetBundle.message("find.what.derived.traits.checkbox")
);
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.derived.classes.checkbox"),
JetBundle.message("find.what.derived.classes.checkbox")
);
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.implementing.classes.checkbox"));
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.interfaces.checkbox"));
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.classes.checkbox"));
derivedClasses = addCheckboxToPanel(
JetBundle.message("find.what.derived.classes.checkbox"),
getFindUsagesOptions().isDerivedClasses,
findWhatPanel,
true
);
derivedTraits = addCheckboxToPanel(
JetBundle.message("find.what.derived.traits.checkbox"),
getFindUsagesOptions().isDerivedInterfaces,
findWhatPanel,
true
);
constructorUsages = addCheckboxToPanel(
JetBundle.message("find.what.constructor.usages.checkbox"),
getFindUsagesOptions().searchConstructorUsages,
@@ -89,16 +91,18 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
@Override
protected void update() {
super.update();
if (!isOKActionEnabled() && constructorUsages.isSelected()) {
if (!isOKActionEnabled() && (constructorUsages.isSelected() || derivedTraits.isSelected() || derivedClasses.isSelected())) {
setOKActionEnabled(true);
}
}
@Override
public void calcFindUsagesOptions(JavaClassFindUsagesOptions options) {
assert options instanceof KotlinClassFindUsagesOptions;
super.calcFindUsagesOptions(options);
((KotlinClassFindUsagesOptions) options).searchConstructorUsages = constructorUsages.isSelected();
KotlinClassFindUsagesOptions kotlinOptions = (KotlinClassFindUsagesOptions) options;
kotlinOptions.searchConstructorUsages = constructorUsages.isSelected();
kotlinOptions.isDerivedClasses = derivedClasses.isSelected();
kotlinOptions.isDerivedInterfaces = derivedTraits.isSelected();
}
}
@@ -22,4 +22,18 @@ class Utils {
return false;
}
static boolean removeCheckbox(@NotNull JPanel panel, @NotNull String srcText) {
for (Component component : panel.getComponents()) {
if (component instanceof JCheckBox) {
JCheckBox checkBox = (JCheckBox) component;
if (checkBox.getText().equals(srcText)) {
panel.remove(checkBox);
return true;
}
}
}
return false;
}
}
@@ -23,8 +23,12 @@ import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.usageView.UsageInfo;
@@ -92,7 +96,63 @@ public class KotlinFindClassUsagesHandler extends KotlinFindUsagesHandler<JetCla
}
}
return processDeclarationsUsages(jetClass, processor, kotlinOptions);
if (!processInheritors(lightClass, processor, kotlinOptions)) return false;
if (!processDeclarationsUsages(jetClass, processor, kotlinOptions)) return false;
return true;
}
private static boolean processDeclarationsUsages(
@NotNull JetClass klass,
@NotNull final Processor<UsageInfo> processor,
@NotNull final JavaClassFindUsagesOptions options
) {
for (JetDeclaration declaration : klass.getDeclarations()) {
if (declaration instanceof JetNamedFunction && options.isMethodsUsages
|| declaration instanceof JetProperty && options.isFieldsUsages) {
if (!ReferencesSearch.search(new ReferencesSearch.SearchParameters(declaration, options.searchScope, false)).forEach(
new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(PsiReference ref) {
return processUsage(processor, ref, options);
}
}
)) return false;
}
}
return true;
}
private static ClassInheritorsSearch.InheritanceChecker INHERITANCE_CHECKER = new ClassInheritorsSearch.InheritanceChecker() {
@Override
public boolean checkInheritance(@NotNull PsiClass subClass, @NotNull PsiClass parentClass) {
return true;
}
};
private static boolean processInheritors(
@NotNull PsiClass klass,
@NotNull final Processor<UsageInfo> processor,
@NotNull final KotlinClassFindUsagesOptions options
) {
//noinspection unchecked
ClassInheritorsSearch.SearchParameters searchParameters = new ClassInheritorsSearch.SearchParameters(
klass, options.searchScope, options.isCheckDeepInheritance, true, true, Condition.TRUE, INHERITANCE_CHECKER
);
return ClassInheritorsSearch.search(searchParameters).forEach(
new PsiElementProcessorAdapter<PsiClass>(
new PsiElementProcessor<PsiClass>() {
@Override
public boolean execute(@NotNull PsiClass element) {
if ((element.isInterface() && options.isDerivedInterfaces)
|| (!element.isInterface() && options.isDerivedClasses)) {
return processUsage(processor, element, options);
}
return true;
}
}
)
);
}
private static DeclarationDescriptor getCallDescriptor(PsiElement element, BindingContext bindingContext) {
@@ -114,27 +174,6 @@ public class KotlinFindClassUsagesHandler extends KotlinFindUsagesHandler<JetCla
return null;
}
private static boolean processDeclarationsUsages(
@NotNull JetClass klass,
@NotNull final Processor<UsageInfo> processor,
@NotNull final JavaClassFindUsagesOptions options
) {
for (JetDeclaration declaration : klass.getDeclarations()) {
if (declaration instanceof JetNamedFunction && options.isMethodsUsages
|| declaration instanceof JetProperty && options.isFieldsUsages) {
if (!ReferencesSearch.search(new ReferencesSearch.SearchParameters(declaration, options.searchScope, false)).forEach(
new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(PsiReference ref) {
return processUsage(processor, ref, options);
}
}
)) return false;
}
}
return true;
}
private static boolean isConstructorUsage(PsiElement element, JetClass jetClass) {
PsiConstructorCall constructorCall = PsiTreeUtil.getParentOfType(element, PsiConstructorCall.class);
if (constructorCall != null && constructorCall == element.getParent()) {
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait X {
}
open class <caret>A: X {
}
open class C: Y {
}
trait Z: A {
}
@@ -0,0 +1,11 @@
class B extends A {
}
interface Y extends X {
}
interface U extends Z {
}
@@ -0,0 +1 @@
Unclassified usage (1: 7) class B extends A {
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait <caret>X {
}
open class A: X {
}
open class C: Y {
}
trait Z: A {
}
@@ -0,0 +1,11 @@
class B extends A {
}
interface Y extends X {
}
interface U extends Z {
}
@@ -0,0 +1,3 @@
Unclassified usage (11: 12) open class C: Y {
Unclassified usage (1: 7) class B extends A {
Unclassified usage (7: 12) open class A: X {
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedInterfaces
trait X {
}
open class <caret>A: X {
}
open class C: Y {
}
trait Z: A {
}
@@ -0,0 +1,11 @@
class B extends A {
}
interface Y extends X {
}
interface U extends Z {
}
@@ -0,0 +1,2 @@
Unclassified usage (15: 7) trait Z: A {
Unclassified usage (9: 11) interface U extends Z {
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedInterfaces
trait <caret>X {
}
open class A: X {
}
open class C: Y {
}
trait Z: A {
}
@@ -0,0 +1,11 @@
class B extends A {
}
interface Y extends X {
}
interface U extends Z {
}
@@ -0,0 +1,3 @@
Unclassified usage (15: 7) trait Z: A {
Unclassified usage (5: 11) interface Y extends X {
Unclassified usage (9: 11) interface U extends Z {
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait X {
}
open class <caret>A: X {
}
trait Y: X {
}
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
open class B: A() {
}
open class C: Y {
}
trait Z: A {
}
trait U: Z {
}
@@ -0,0 +1 @@
Unclassified usage (3: 12) open class B: A() {
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait <caret>X {
}
open class A: X {
}
trait Y: X {
}
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
open class B: A() {
}
open class C: Y {
}
trait Z: A {
}
trait U: Z {
}
@@ -0,0 +1,3 @@
Unclassified usage (3: 12) open class B: A() {
Unclassified usage (7: 12) open class A: X {
Unclassified usage (7: 12) open class C: Y {
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedInterfaces
trait <caret>X {
}
open class A: X {
}
trait Y: X {
}
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedInterfaces
open class B: A() {
}
open class C: Y {
}
trait Z: A {
}
trait U: Z {
}
@@ -0,0 +1,3 @@
Unclassified usage (11: 7) trait Y: X {
Unclassified usage (11: 7) trait Z: A {
Unclassified usage (15: 7) trait U: Z {
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedInterfaces
trait X {
}
open class <caret>A: X {
}
trait Y: X {
}
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedInterfaces
open class B: A() {
}
open class C: Y {
}
trait Z: A {
}
trait U: Z {
}
@@ -0,0 +1,2 @@
Unclassified usage (11: 7) trait Z: A {
Unclassified usage (15: 7) trait U: Z {
@@ -74,6 +74,12 @@ public abstract class AbstractJetFindUsagesTest extends LightCodeInsightFixtureT
else if (s.equals("constructorUsages")) {
options.searchConstructorUsages = true;
}
else if (s.equals("derivedInterfaces")) {
options.isDerivedInterfaces = true;
}
else if (s.equals("derivedClasses")) {
options.isDerivedClasses = true;
}
else if (s.equals("functionUsages")) {
options.isMethodsUsages = true;
}
@@ -78,6 +78,26 @@ public class JetFindUsagesTest extends AbstractJetFindUsagesTest {
doTest("idea/testData/findUsages/findClassUsages/javaClassPropertyUsages2.0.kt");
}
@TestMetadata("javaDerivedClassUsages1.0.kt")
public void testJavaDerivedClassUsages1() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/javaDerivedClassUsages1.0.kt");
}
@TestMetadata("javaDerivedClassUsages2.0.kt")
public void testJavaDerivedClassUsages2() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/javaDerivedClassUsages2.0.kt");
}
@TestMetadata("javaDerivedInterfaceUsages1.0.kt")
public void testJavaDerivedInterfaceUsages1() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/javaDerivedInterfaceUsages1.0.kt");
}
@TestMetadata("javaDerivedInterfaceUsages2.0.kt")
public void testJavaDerivedInterfaceUsages2() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/javaDerivedInterfaceUsages2.0.kt");
}
@TestMetadata("kotlinClassAllUsages.0.kt")
public void testKotlinClassAllUsages() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.0.kt");
@@ -123,6 +143,26 @@ public class JetFindUsagesTest extends AbstractJetFindUsagesTest {
doTest("idea/testData/findUsages/findClassUsages/kotlinClassPropertyUsages2.0.kt");
}
@TestMetadata("kotlinDerivedClassUsages1.0.kt")
public void testKotlinDerivedClassUsages1() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/kotlinDerivedClassUsages1.0.kt");
}
@TestMetadata("kotlinDerivedClassUsages2.0.kt")
public void testKotlinDerivedClassUsages2() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/kotlinDerivedClassUsages2.0.kt");
}
@TestMetadata("kotlinDerivedInterfaceUsages1.0.kt")
public void testKotlinDerivedInterfaceUsages1() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/kotlinDerivedInterfaceUsages1.0.kt");
}
@TestMetadata("kotlinDerivedInterfaceUsages2.0.kt")
public void testKotlinDerivedInterfaceUsages2() throws Exception {
doTest("idea/testData/findUsages/findClassUsages/kotlinDerivedInterfaceUsages2.0.kt");
}
}
@TestMetadata("idea/testData/findUsages/findMethodUsages")