Supported default objects in class usages.

This commit is contained in:
Evgeny Gerashchenko
2015-03-11 17:58:16 +03:00
parent 8874ad2c96
commit 9bcf9dceef
12 changed files with 127 additions and 24 deletions
@@ -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<PsiElement>
get() {
fun PsiElement.adjust(): PsiElement? {
val target = unwrapped?.getOriginalElement()
return when {
target is JetPropertyAccessor -> target.getNonStrictParentOfType<JetProperty>()
target is JetObjectDeclaration && target.isDefault() -> target.getNonStrictParentOfType<JetClass>()
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<JetClass>() == 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
@@ -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<JetClass>()?.getName()
} else {
null
}
}
public fun PsiNamedElement.getSpecialNamesToSearch(): List<String> {
val name = getName()
return when {
@@ -102,7 +105,7 @@ public abstract class UsagesSearchHelper<T : PsiNamedElement> {
protected open fun makeWordList(target: UsagesSearchTarget<T>): List<String> {
return with(target.element) {
ContainerUtil.createMaybeSingletonList(getName()) + getAccessorNames() + getSpecialNamesToSearch()
getName().singletonOrEmptyList() + getAccessorNames() + getClassNameForDefaultObject().singletonOrEmptyList() + getSpecialNamesToSearch()
}
}
@@ -0,0 +1,16 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration
// OPTIONS: usages
import kotlin.platform.platformStatic
class Foo {
default <caret>object {
fun f() {
}
platformStatic fun s() {
}
val CONST = 42
}
}
@@ -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
}
}
@@ -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();
@@ -0,0 +1,8 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration
// OPTIONS: usages
class Foo {
default object <caret>Bar {
fun f() {
}
}
}
@@ -0,0 +1,10 @@
fun main(args: Array<String>) {
val p: Foo = Foo() // simple class usage
// default object usages
Foo.f()
val x = Foo
Foo.Bar.f()
val xx = Foo.Bar
}
@@ -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
@@ -0,0 +1,8 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration
// OPTIONS: usages
class Foo {
default <caret>object {
fun f() {
}
}
}
@@ -0,0 +1,10 @@
fun main(args: Array<String>) {
val p: Foo = Foo() // simple class usage
// default object usages
Foo.f()
val x = Foo
Foo.Default.f()
val xx = Foo.Default
}
@@ -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
@@ -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)