diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt index 9e3a339860f..9d63a37afa3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt @@ -16,34 +16,23 @@ package org.jetbrains.kotlin.idea.references -import com.intellij.psi.PsiReference -import com.intellij.psi.PsiElement +import com.intellij.psi.* import org.jetbrains.kotlin.asJava.unwrapped -import com.intellij.psi.PsiMethod -import org.jetbrains.kotlin.psi.JetPropertyAccessor -import org.jetbrains.kotlin.psi.JetProperty -import java.util.HashSet -import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention -import org.jetbrains.kotlin.psi.JetQualifiedExpression -import org.jetbrains.kotlin.psi.JetCallExpression -import org.jetbrains.kotlin.psi.JetObjectDeclaration -import org.jetbrains.kotlin.psi.JetClass -import com.intellij.psi.PsiPolyVariantReference -import org.jetbrains.kotlin.utils.emptyOrSingletonList -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.utils.emptyOrSingletonList +import java.util.HashSet // Navigation element of the resolved reference // For property accessor return enclosing property -// For default object return enclosing class public val PsiReference.unwrappedTargets: Set get() { fun PsiElement.adjust(): PsiElement? { val target = unwrapped?.getOriginalElement() return when { target is JetPropertyAccessor -> target.getNonStrictParentOfType() - target is JetObjectDeclaration && target.isDefault() -> target.getNonStrictParentOfType() else -> target } } @@ -62,6 +51,18 @@ public fun PsiReference.matchesTarget(candidateTarget: PsiElement): Boolean { if (this is JetReference) { return targets.any { it is PsiMethod && it.isConstructor() && it.getContainingClass() == unwrappedCandidate + || it is JetObjectDeclaration && it.isDefault() && it.getNonStrictParentOfType() == unwrappedCandidate + } + } + if (this is PsiReferenceExpression && candidateTarget is JetObjectDeclaration && unwrappedTargets.size() == 1) { + val referredClass = unwrappedTargets.first() + if (referredClass is JetClass && candidateTarget in referredClass.getDefaultObjects()) { + val parentReference = getParent().getReference() + if (parentReference != null) { + return parentReference.unwrappedTargets.any { + (it is JetProperty || it is JetNamedFunction) && it.getParent()?.getParent() == candidateTarget + } + } } } return false diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt index 459453b1515..24c5b2bcfae 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt @@ -17,18 +17,12 @@ package org.jetbrains.kotlin.idea.search.usagesSearch import com.intellij.psi.PsiReference -import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.idea.search.usagesSearch.* import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchFilter.* -import org.jetbrains.kotlin.psi.JetProperty -import org.jetbrains.kotlin.psi.JetNamedFunction import java.util.Collections import java.util.ArrayList -import org.jetbrains.kotlin.psi.JetNamedDeclaration import com.intellij.psi.PsiNamedElement import org.jetbrains.kotlin.asJava.LightClassUtil -import org.jetbrains.kotlin.psi.JetParameter -import org.jetbrains.kotlin.psi.JetPsiUtil import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.name.Name @@ -37,9 +31,10 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.idea.references.* -import org.jetbrains.kotlin.psi.JetDeclaration import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList val isTargetUsage = (PsiReference::matchesTarget).searchFilter @@ -68,6 +63,14 @@ fun PsiNamedElement.getAccessorNames(readable: Boolean = true, writable: Boolean return Collections.emptyList() } +public fun PsiNamedElement.getClassNameForDefaultObject(): String? { + return if (this is JetObjectDeclaration) { + getNonStrictParentOfType()?.getName() + } else { + null + } +} + public fun PsiNamedElement.getSpecialNamesToSearch(): List { val name = getName() return when { @@ -102,7 +105,7 @@ public abstract class UsagesSearchHelper { protected open fun makeWordList(target: UsagesSearchTarget): List { return with(target.element) { - ContainerUtil.createMaybeSingletonList(getName()) + getAccessorNames() + getSpecialNamesToSearch() + getName().singletonOrEmptyList() + getAccessorNames() + getClassNameForDefaultObject().singletonOrEmptyList() + getSpecialNamesToSearch() } } diff --git a/idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt b/idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt new file mode 100644 index 00000000000..91122ae30cf --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt @@ -0,0 +1,16 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration +// OPTIONS: usages + +import kotlin.platform.platformStatic + +class Foo { + default object { + fun f() { + } + + platformStatic fun s() { + } + + val CONST = 42 + } +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/javaUsage.1.java b/idea/testData/findUsages/kotlin/defaultObject/javaUsage.1.java new file mode 100644 index 00000000000..7bdbda1eb52 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/javaUsage.1.java @@ -0,0 +1,8 @@ +class JavaUsage { + public static void main(String[] args) { + System.out.println(Foo.CONST); + Foo.s(); + Foo.Default.f(); + Foo foo = new Foo(); // not usage of default object + } +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/javaUsage.results.txt b/idea/testData/findUsages/kotlin/defaultObject/javaUsage.results.txt new file mode 100644 index 00000000000..655a50ff2d2 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/javaUsage.results.txt @@ -0,0 +1,3 @@ +Class static member access (3: 28) System.out.println(Foo.CONST); +Class static member access (4: 9) Foo.s(); +Unclassified usage (5: 13) Foo.Default.f(); \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/named.0.kt b/idea/testData/findUsages/kotlin/defaultObject/named.0.kt new file mode 100644 index 00000000000..bb7b03a4715 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/named.0.kt @@ -0,0 +1,8 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration +// OPTIONS: usages +class Foo { + default object Bar { + fun f() { + } + } +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/named.1.kt b/idea/testData/findUsages/kotlin/defaultObject/named.1.kt new file mode 100644 index 00000000000..d13364e9e74 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/named.1.kt @@ -0,0 +1,10 @@ +fun main(args: Array) { + val p: Foo = Foo() // simple class usage + + // default object usages + Foo.f() + val x = Foo + + Foo.Bar.f() + val xx = Foo.Bar +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/named.results.txt b/idea/testData/findUsages/kotlin/defaultObject/named.results.txt new file mode 100644 index 00000000000..af67e2a4efe --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/named.results.txt @@ -0,0 +1,4 @@ +Nested class/object (5: 5) Foo.f() +Nested class/object (8: 9) Foo.Bar.f() +Unclassified usage (6: 13) val x = Foo +Unclassified usage (9: 18) val xx = Foo.Bar \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/simple.0.kt b/idea/testData/findUsages/kotlin/defaultObject/simple.0.kt new file mode 100644 index 00000000000..a98a1a37853 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/simple.0.kt @@ -0,0 +1,8 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration +// OPTIONS: usages +class Foo { + default object { + fun f() { + } + } +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/simple.1.kt b/idea/testData/findUsages/kotlin/defaultObject/simple.1.kt new file mode 100644 index 00000000000..c56cbce46e1 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/simple.1.kt @@ -0,0 +1,10 @@ +fun main(args: Array) { + val p: Foo = Foo() // simple class usage + + // default object usages + Foo.f() + val x = Foo + + Foo.Default.f() + val xx = Foo.Default +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/simple.results.txt b/idea/testData/findUsages/kotlin/defaultObject/simple.results.txt new file mode 100644 index 00000000000..2c9e009b01a --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/simple.results.txt @@ -0,0 +1,4 @@ +Nested class/object (5: 5) Foo.f() +Nested class/object (8: 9) Foo.Default.f() +Unclassified usage (6: 13) val x = Foo +Unclassified usage (9: 18) val xx = Foo.Default \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java b/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java index 2d1ed2961c9..ea18465b3ed 100644 --- a/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java @@ -38,6 +38,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest { @TestDataPath("$PROJECT_ROOT") @InnerTestClasses({ Kotlin.Conventions.class, + Kotlin.DefaultObject.class, Kotlin.FindClassUsages.class, Kotlin.FindFunctionUsages.class, Kotlin.FindObjectUsages.class, @@ -167,6 +168,33 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest { } } + @TestMetadata("idea/testData/findUsages/kotlin/defaultObject") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultObject extends AbstractJetFindUsagesTest { + public void testAllFilesPresentInDefaultObject() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/defaultObject"), Pattern.compile("^(.+)\\.0\\.kt$"), true); + } + + @TestMetadata("javaUsage.0.kt") + public void testJavaUsage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt"); + doTest(fileName); + } + + @TestMetadata("named.0.kt") + public void testNamed() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/named.0.kt"); + doTest(fileName); + } + + @TestMetadata("simple.0.kt") + public void testSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/simple.0.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/findUsages/kotlin/findClassUsages") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)