Go to (show) implementations: skip light methods that are generated with DELEGATION or DELEGATION_TO_DEFAULT_IMPLS JvmDeclarationOriginKind

Add some unrelated tests for fake overrides
This commit is contained in:
Pavel V. Talanov
2015-12-21 19:37:23 +03:00
parent de6f52030c
commit 99966c17da
15 changed files with 371 additions and 32 deletions
@@ -27,19 +27,20 @@ import com.intellij.psi.impl.java.stubs.*;
import com.intellij.psi.stubs.StubBase;
import com.intellij.psi.stubs.StubElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.annotations.Nullable;
class ClsWrapperStubPsiFactory extends StubPsiFactory {
public static final Key<PsiElement> ORIGIN_ELEMENT = Key.create("ORIGIN_ELEMENT");
public static final Key<LightElementOrigin> ORIGIN = Key.create("ORIGIN");
private final StubPsiFactory delegate = new ClsStubPsiFactory();
public static KtDeclaration getOriginalDeclaration(PsiMember member) {
@Nullable
public static LightMemberOrigin getMemberOrigin(@NotNull PsiMember member) {
if (member instanceof ClsRepositoryPsiElement<?>) {
StubElement stubElement = ((ClsRepositoryPsiElement<?>) member).getStub();
if (stubElement instanceof UserDataHolder) {
PsiElement original = ((UserDataHolder) stubElement).getUserData(ORIGIN_ELEMENT);
if (original instanceof KtDeclaration) {
return (KtDeclaration) original;
LightElementOrigin origin = ((UserDataHolder) stubElement).getUserData(ORIGIN);
if (origin instanceof LightMemberOrigin) {
return (LightMemberOrigin) origin;
}
}
}
@@ -48,8 +49,8 @@ class ClsWrapperStubPsiFactory extends StubPsiFactory {
}
@Override
public PsiClass createClass(PsiClassStub stub) {
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
public PsiClass createClass(@NotNull PsiClassStub stub) {
final PsiElement origin = getOriginalElement(stub);
if (origin == null) return delegate.createClass(stub);
return new ClsClassImpl(stub) {
@@ -61,6 +62,12 @@ class ClsWrapperStubPsiFactory extends StubPsiFactory {
};
}
@Nullable
private static PsiElement getOriginalElement(@NotNull StubElement stub) {
LightElementOrigin origin = ((StubBase) stub).getUserData(ORIGIN);
return origin != null ? origin.getOriginalElement() : null;
}
@Override
public PsiAnnotation createAnnotation(PsiAnnotationStub stub) {
return delegate.createAnnotation(stub);
@@ -78,7 +85,7 @@ class ClsWrapperStubPsiFactory extends StubPsiFactory {
@Override
public PsiField createField(PsiFieldStub stub) {
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
final PsiElement origin = getOriginalElement(stub);
if (origin == null) return delegate.createField(stub);
if (stub.isEnumConstant()) {
return new ClsEnumConstantImpl(stub) {
@@ -25,14 +25,19 @@ import com.intellij.psi.util.*
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
public interface KtLightMethod : PsiMethod, KtLightElement<KtDeclaration, PsiMethod>
public interface KtLightMethod : PsiMethod, KtLightElement<KtDeclaration, PsiMethod> {
val isDelegated: Boolean
}
sealed class KtLightMethodImpl(
private val delegate: PsiMethod,
private val origin: KtDeclaration?,
private val lightMethodOrigin: LightMemberOrigin?,
containingClass: KtLightClass
): LightMethod(delegate.manager, delegate, containingClass), KtLightMethod {
) : LightMethod(delegate.manager, delegate, containingClass), KtLightMethod {
private val origin = lightMethodOrigin?.originalElement as? KtDeclaration
override fun getContainingClass(): KtLightClass = super.getContainingClass() as KtLightClass
private val paramsList: CachedValue<PsiParameterList> by lazy {
@@ -70,7 +75,11 @@ sealed class KtLightMethodImpl(
override fun getOrigin() = origin
override fun getParent(): PsiElement? = containingClass
override fun getText() = origin?.text ?: ""
override fun getTextRange() = origin?.textRange ?: TextRange.EMPTY_RANGE
override fun getTextRange() = origin?.textRange ?: TextRange.EMPTY_RANGE
override val isDelegated: Boolean
get() = lightMethodOrigin?.originKind == JvmDeclarationOriginKind.DELEGATION
|| lightMethodOrigin?.originKind == JvmDeclarationOriginKind.DELEGATION_TO_DEFAULT_IMPLS
override fun accept(visitor: PsiElementVisitor) {
if (visitor is JavaElementVisitor) {
@@ -114,7 +123,7 @@ sealed class KtLightMethodImpl(
}
override fun copy(): PsiElement {
return Factory.create(delegate, origin?.copy() as? KtDeclaration, containingClass)
return Factory.create(delegate, lightMethodOrigin?.copy(), containingClass)
}
override fun getUseScope() = origin?.useScope ?: super.getUseScope()
@@ -143,14 +152,14 @@ sealed class KtLightMethodImpl(
override fun hashCode(): Int = ((name.hashCode() * 31 + (origin?.hashCode() ?: 0)) * 31 + containingClass.hashCode()) * 31 + delegate.hashCode()
override fun toString(): String = "${this.javaClass.simpleName}:$name"
private class KtLightMethodForDeclaration(
delegate: PsiMethod, origin: KtDeclaration?, containingClass: KtLightClass
delegate: PsiMethod, origin: LightMemberOrigin?, containingClass: KtLightClass
) : KtLightMethodImpl(delegate, origin, containingClass)
private class KtLightAnnotationMethod(
delegate: PsiAnnotationMethod,
origin: KtDeclaration?,
origin: LightMemberOrigin?,
containingClass: KtLightClass
) : KtLightMethodImpl(delegate, origin, containingClass), PsiAnnotationMethod {
override fun getDefaultValue() = getDelegate().defaultValue
@@ -159,7 +168,7 @@ sealed class KtLightMethodImpl(
companion object Factory {
fun create(
delegate: PsiMethod, origin: KtDeclaration?, containingClass: KtLightClass
delegate: PsiMethod, origin: LightMemberOrigin?, containingClass: KtLightClass
): KtLightMethodImpl {
return when (delegate) {
is PsiAnnotationMethod -> KtLightAnnotationMethod(delegate, origin, containingClass)
@@ -33,7 +33,10 @@ import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtProperty;
import org.jetbrains.kotlin.psi.KtPropertyAccessor;
import java.util.List;
@@ -119,8 +122,8 @@ public abstract class KtWrappingLightClass extends AbstractLightClass implements
return ContainerUtil.map(getDelegate().getFields(), new Function<PsiField, PsiField>() {
@Override
public PsiField fun(PsiField field) {
KtDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(field);
return KtLightFieldImpl.Factory.create(declaration, field, KtWrappingLightClass.this);
LightMemberOrigin origin = ClsWrapperStubPsiFactory.getMemberOrigin(field);
return KtLightFieldImpl.Factory.create(origin != null ? origin.getOriginalElement() : null, field, KtWrappingLightClass.this);
}
});
}
@@ -131,12 +134,14 @@ public abstract class KtWrappingLightClass extends AbstractLightClass implements
return ArraysKt.map(getDelegate().getMethods(), new Function1<PsiMethod, PsiMethod>() {
@Override
public PsiMethod invoke(PsiMethod method) {
KtDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(method);
if (declaration instanceof KtPropertyAccessor) {
declaration = PsiTreeUtil.getParentOfType(declaration, KtProperty.class);
LightMemberOrigin origin = ClsWrapperStubPsiFactory.getMemberOrigin(method);
KtDeclaration originalElement = origin != null ? origin.getOriginalElement() : null;
if (originalElement instanceof KtPropertyAccessor) {
//noinspection ConstantConditions
origin = origin.copy(PsiTreeUtil.getParentOfType(originalElement, KtProperty.class), origin.getOriginKind());
}
return KtLightMethodImpl.Factory.create(method, declaration, KtWrappingLightClass.this);
return KtLightMethodImpl.Factory.create(method, origin, KtWrappingLightClass.this);
}
});
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.asJava
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
interface LightElementOrigin {
val originalElement: PsiElement?
val originKind: JvmDeclarationOriginKind?
object None : LightElementOrigin {
override val originalElement: PsiElement?
get() = null
override val originKind: JvmDeclarationOriginKind?
get() = null
override fun toString() = "NONE"
}
}
fun JvmDeclarationOrigin.toLightMemberOrigin(): LightElementOrigin {
val originalElement = element
return when (originalElement) {
is KtDeclaration -> LightMemberOrigin(originalElement, originKind)
else -> LightElementOrigin.None
}
}
data class LightMemberOrigin(override val originalElement: KtDeclaration, override val originKind: JvmDeclarationOriginKind) : LightElementOrigin
data class LightClassOrigin(override val originalElement: PsiElement?) : LightElementOrigin {
override val originKind: JvmDeclarationOriginKind? get() = null
}
fun PsiElement?.toLightClassOrigin(): LightElementOrigin {
return if (this != null) LightClassOrigin(this) else LightElementOrigin.None
}
fun LightMemberOrigin.copy() = LightMemberOrigin(originalElement.copy() as KtDeclaration, originKind)
@@ -92,7 +92,7 @@ public class StubClassBuilder extends AbstractClassBuilder {
parentStack.push(v.getResult());
}
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN, LightElementOriginKt.toLightClassOrigin(origin));
}
@NotNull
@@ -109,7 +109,7 @@ public class StubClassBuilder extends AbstractClassBuilder {
if (internalVisitor != EMPTY_METHOD_VISITOR) {
// If stub for method generated
markLastChild(origin.getElement());
markLastChild(origin);
}
return internalVisitor;
@@ -129,22 +129,24 @@ public class StubClassBuilder extends AbstractClassBuilder {
if (internalVisitor != EMPTY_FIELD_VISITOR) {
// If stub for field generated
markLastChild(origin.getElement());
markLastChild(origin);
}
return internalVisitor;
}
private void markLastChild(@Nullable PsiElement origin) {
private void markLastChild(@NotNull JvmDeclarationOrigin origin) {
List children = v.getResult().getChildrenStubs();
StubBase last = (StubBase) children.get(children.size() - 1);
PsiElement oldOrigin = last.getUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT);
LightElementOrigin oldOrigin = last.getUserData(ClsWrapperStubPsiFactory.ORIGIN);
if (oldOrigin != null) {
throw new IllegalStateException("Rewriting origin element: " + oldOrigin.getText() + " for stub " + last.toString());
PsiElement originalElement = oldOrigin.getOriginalElement();
throw new IllegalStateException("Rewriting origin element: " +
(originalElement != null ? originalElement.getText() : null) + " for stub " + last.toString());
}
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN, LightElementOriginKt.toLightMemberOrigin(origin));
}
@Override
@@ -41,6 +41,7 @@ public class KotlinDefinitionsSearcher implements QueryExecutor<PsiElement, Defi
public boolean execute(@NotNull DefinitionsScopedSearch.SearchParameters queryParameters, @NotNull Processor<PsiElement> consumer) {
PsiElement element = queryParameters.getElement();
SearchScope scope = queryParameters.getScope();
consumer = skipDelegatedMethodsConsumer(consumer);
if (element instanceof KtClass) {
return processClassImplementations((KtClass) element, consumer);
@@ -64,6 +65,23 @@ public class KotlinDefinitionsSearcher implements QueryExecutor<PsiElement, Defi
return true;
}
@NotNull
private static Processor<PsiElement> skipDelegatedMethodsConsumer(@NotNull final Processor<PsiElement> baseConsumer) {
return new Processor<PsiElement>() {
@Override
public boolean process(PsiElement element) {
if (isDelegated(element)) {
return true;
}
return baseConsumer.process(element);
}
};
}
private static boolean isDelegated(@NotNull PsiElement element) {
return element instanceof KtLightMethod && ((KtLightMethod) element).isDelegated();
}
private static boolean processClassImplementations(final KtClass klass, Processor<PsiElement> consumer) {
PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
@@ -122,6 +140,8 @@ public class KotlinDefinitionsSearcher implements QueryExecutor<PsiElement, Defi
MethodImplementationsSearch.getOverridingMethods(method, implementations, scope);
for (PsiMethod implementation : implementations) {
if (isDelegated(implementation)) continue;
PsiElement mirrorElement = implementation instanceof KtLightMethod
? ((KtLightMethod) implementation).getOrigin() : null;
if (mirrorElement instanceof KtProperty || mirrorElement instanceof KtParameter) {
@@ -0,0 +1,26 @@
package testing
interface I {
fun <caret>f() {
}
}
class A : I
class B : I {
override fun f() {
}
}
class C : I
interface II: I
interface III: I {
override fun f() {
}
}
// REF: (in testing.B).f()
// REF: (in testing.III).f()
@@ -0,0 +1,24 @@
package testing
interface I {
val <caret>p: Int
get() = 0
}
class A : I
class B : I {
override val p = 5
}
class C : I
interface II: I
interface III : I {
override val p: Int get() = 1
}
// REF: (in testing.B).p
// REF: (in testing.III).p
@@ -0,0 +1,36 @@
package testing
interface I {
fun <caret>f() {
}
}
class A : I
class B : I {
override fun f() {
}
}
class C : I
interface II: I
interface III: I {
override fun f() {
}
}
class A1(i: I) : I by i
class B1(i: I) : I by i {
override fun f() {
}
}
class C1(i: I) : I by i
// REF: (in testing.B).f()
// REF: (in testing.B1).f()
// REF: (in testing.III).f()
@@ -0,0 +1,19 @@
package testing
interface I {
fun <caret>f() {
}
}
class A(i: I) : I by i
class B(i: I) : I by i {
override fun f() {
}
}
class C(i: I) : I by i
// REF: (in testing.B).f()
@@ -0,0 +1,19 @@
package testing
interface I {
val <caret>p: Int
get() = 0
}
class A(i: I) : I by i
class B(i: I) : I by i {
override val p = 5
}
class C(i: I) : I by i
// REF: (in testing.B).p
@@ -0,0 +1,16 @@
package testing
open class C {
open fun <caret>f() {
}
}
class A : C()
class B : C() {
override fun f() {
}
}
// REF: (in testing.B).f()
@@ -0,0 +1,36 @@
package testing
interface I<T> {
fun <caret>f(): T {
}
}
class A<T> : I<T>
class B<T> : I<T> {
override fun f(): T {
}
}
class C<T> : I<T>
interface II<T>: I<T>
interface III<T>: I<T> {
override fun f(): T {
}
}
class A1<T>(i: I<T>) : I<T> by i
class B1<T>(i: I<T>) : I<T> by i {
override fun f(): T {
}
}
class C1<T>(i: I<T>) : I<T> by i
// REF: (in testing.B).f()
// REF: (in testing.B1).f()
// REF: (in testing.III).f()
@@ -0,0 +1,15 @@
package testing
open class C<T> {
open fun <caret>f(): T {
}
}
class A : C<Int>()
class B : C<String>() {
override fun f() = "A"
}
// REF: (in testing.B).f()
@@ -59,18 +59,66 @@ public class KotlinGotoImplementationTestGenerated extends AbstractKotlinGotoImp
doTest(fileName);
}
@TestMetadata("DefaultImplFunction.kt")
public void testDefaultImplFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/DefaultImplFunction.kt");
doTest(fileName);
}
@TestMetadata("DefaultImplProperty.kt")
public void testDefaultImplProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/DefaultImplProperty.kt");
doTest(fileName);
}
@TestMetadata("DelegatedAndDefaultImplFunction.kt")
public void testDelegatedAndDefaultImplFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/DelegatedAndDefaultImplFunction.kt");
doTest(fileName);
}
@TestMetadata("DelegatedFunction.kt")
public void testDelegatedFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/DelegatedFunction.kt");
doTest(fileName);
}
@TestMetadata("DelegatedProperty.kt")
public void testDelegatedProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/DelegatedProperty.kt");
doTest(fileName);
}
@TestMetadata("EnumEntriesInheritance.kt")
public void testEnumEntriesInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/EnumEntriesInheritance.kt");
doTest(fileName);
}
@TestMetadata("FakeOverride.kt")
public void testFakeOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/FakeOverride.kt");
doTest(fileName);
}
@TestMetadata("FunctionOverrideNavigation.kt")
public void testFunctionOverrideNavigation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/FunctionOverrideNavigation.kt");
doTest(fileName);
}
@TestMetadata("GenericDelegatedAndDefaultImplFunction.kt")
public void testGenericDelegatedAndDefaultImplFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/GenericDelegatedAndDefaultImplFunction.kt");
doTest(fileName);
}
@TestMetadata("GenericFakeOverride.kt")
public void testGenericFakeOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/GenericFakeOverride.kt");
doTest(fileName);
}
@TestMetadata("ImplementGenericWithPrimitives.kt")
public void testImplementGenericWithPrimitives() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/implementations/ImplementGenericWithPrimitives.kt");