From fec64b31dc9a12f68c378094b0caa60276ebe279 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 10 Sep 2014 18:58:07 +0400 Subject: [PATCH] Fix resolve of Kotlin enum entries from Java #KT-5719 Fixed --- .../jet/asJava/KotlinWrappingLightClass.java | 20 +++-- .../asJava/light/KotlinLightEnumConstant.kt | 38 +++++++++ .../jet/asJava/light/KotlinLightField.java | 81 +++++++++---------- .../light/KotlinLightFieldForDeclaration.kt | 29 +++++++ .../EnumEntriesInSwitch.java | 16 ++++ .../EnumEntriesInSwitch.kt | 6 ++ .../checkers/KotlinAndJavaCheckerTest.java | 4 + 7 files changed, 143 insertions(+), 51 deletions(-) create mode 100644 compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightEnumConstant.kt create mode 100644 compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightFieldForDeclaration.kt create mode 100644 idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.java create mode 100644 idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.kt diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinWrappingLightClass.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinWrappingLightClass.java index fddb4ed27e6..db6bdbba0e3 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinWrappingLightClass.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinWrappingLightClass.java @@ -28,10 +28,9 @@ import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.asJava.light.KotlinLightField; -import org.jetbrains.jet.lang.psi.JetClassOrObject; -import org.jetbrains.jet.lang.psi.JetDeclaration; -import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.asJava.light.KotlinLightEnumConstant; +import org.jetbrains.jet.asJava.light.KotlinLightFieldForDeclaration; +import org.jetbrains.jet.lang.psi.*; import java.util.List; @@ -111,9 +110,16 @@ public abstract class KotlinWrappingLightClass extends AbstractLightClass implem @Override public PsiField fun(PsiField field) { JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(field); - return declaration instanceof JetProperty - ? new KotlinLightField(myManager, (JetProperty) declaration, field, KotlinWrappingLightClass.this) - : new LightField(myManager, field, KotlinWrappingLightClass.this); + if (declaration instanceof JetEnumEntry) { + assert field instanceof PsiEnumConstant : "Field delegate should be an enum constant (" + field.getName() + "):\n" + + JetPsiUtil.getElementTextWithContext(declaration); + return new KotlinLightEnumConstant(myManager, (JetEnumEntry) declaration, ((PsiEnumConstant) field), + KotlinWrappingLightClass.this); + } + if (declaration instanceof JetProperty) { + return new KotlinLightFieldForDeclaration(myManager, (JetProperty) declaration, field, KotlinWrappingLightClass.this); + } + return new LightField(myManager, field, KotlinWrappingLightClass.this); } }); } diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightEnumConstant.kt b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightEnumConstant.kt new file mode 100644 index 00000000000..c1e692e6b70 --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightEnumConstant.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2014 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.jet.asJava.light + +import com.intellij.psi.* +import org.jetbrains.jet.lang.psi.JetEnumEntry + +class KotlinLightEnumConstant( + manager: PsiManager, + origin: JetEnumEntry, + enumConstant: PsiEnumConstant, + containingClass: PsiClass +) : KotlinLightField(manager, origin, enumConstant, containingClass), PsiEnumConstant { + override fun copy() = KotlinLightEnumConstant(getManager()!!, getOrigin(), getDelegate(), getContainingClass()!!) + + // NOTE: we don't use "delegation by" because the compiler would generate method calls to ALL of PsiEnumConstant members, + // but we need only members whose implementations are not present in KotlinLightField + override fun getArgumentList(): PsiExpressionList? = getDelegate().getArgumentList() + override fun getInitializingClass(): PsiEnumConstantInitializer? = getDelegate().getInitializingClass() + override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer = getDelegate().getOrCreateInitializingClass() + override fun resolveConstructor(): PsiMethod? = getDelegate().resolveConstructor() + override fun resolveMethod(): PsiMethod? = getDelegate().resolveMethod() + override fun resolveMethodGenerics(): JavaResolveResult = getDelegate().resolveMethodGenerics() +} diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightField.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightField.java index e61d14a2b36..f13108657bd 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightField.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightField.java @@ -26,84 +26,83 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightElement; -// Copy of com.intellij.psi.impl.light.LightField -@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter") -public class KotlinLightField extends LightElement implements PsiField, KotlinLightElement { - private final JetProperty myOriginalProperty; - private final PsiField myField; - private final PsiClass myContainingClass; +// Copied from com.intellij.psi.impl.light.LightField +public abstract class KotlinLightField extends LightElement + implements PsiField, KotlinLightElement { + private final T origin; + private final D delegate; + private final PsiClass containingClass; - public KotlinLightField( - @NotNull final PsiManager manager, - @NotNull final JetProperty originalProperty, - @NotNull final PsiField field, - @NotNull final PsiClass containingClass - ) { + public KotlinLightField(@NotNull PsiManager manager, @NotNull T origin, @NotNull D delegate, @NotNull PsiClass containingClass) { super(manager, JavaLanguage.INSTANCE); - myOriginalProperty = originalProperty; - myField = field; - myContainingClass = containingClass; + this.origin = origin; + this.delegate = delegate; + this.containingClass = containingClass; } + @NotNull @Override - public void setInitializer(@Nullable final PsiExpression initializer) throws IncorrectOperationException { + public abstract KotlinLightField copy(); + + @Override + public void setInitializer(@Nullable PsiExpression initializer) throws IncorrectOperationException { throw new IncorrectOperationException("Not supported"); } @NotNull @Override public SearchScope getUseScope() { - return myField.getUseScope(); + return delegate.getUseScope(); } @Override public String getName() { - return myField.getName(); + return delegate.getName(); } @NotNull @Override public PsiIdentifier getNameIdentifier() { - return myField.getNameIdentifier(); + return delegate.getNameIdentifier(); } @Override public PsiDocComment getDocComment() { - return myField.getDocComment(); + return delegate.getDocComment(); } @Override public boolean isDeprecated() { - return myField.isDeprecated(); + return delegate.isDeprecated(); } @Override public PsiClass getContainingClass() { - return myContainingClass; + return containingClass; } @NotNull @Override public PsiType getType() { - return myField.getType(); + return delegate.getType(); } @Override public PsiTypeElement getTypeElement() { - return myField.getTypeElement(); + return delegate.getTypeElement(); } @Override public PsiExpression getInitializer() { - return myField.getInitializer(); + return delegate.getInitializer(); } @Override public boolean hasInitializer() { - return myField.hasInitializer(); + return delegate.hasInitializer(); } @Override @@ -113,33 +112,27 @@ public class KotlinLightField extends LightElement implements PsiField, KotlinLi @Override public Object computeConstantValue() { - return myField.computeConstantValue(); + return delegate.computeConstantValue(); } @Override - public PsiElement setName(@NonNls @NotNull final String name) throws IncorrectOperationException { + public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { throw new IncorrectOperationException("Not supported"); } @Override public PsiModifierList getModifierList() { - return myField.getModifierList(); + return delegate.getModifierList(); } @Override - public boolean hasModifierProperty(@NonNls @NotNull final String name) { - return myField.hasModifierProperty(name); + public boolean hasModifierProperty(@NonNls @NotNull String name) { + return delegate.hasModifierProperty(name); } @Override public String getText() { - return myField.getText(); - } - - @NotNull - @Override - public PsiElement copy() { - return new KotlinLightField(myManager, myOriginalProperty, (PsiField)myField.copy(), myContainingClass); + return delegate.getText(); } @Override @@ -149,7 +142,7 @@ public class KotlinLightField extends LightElement implements PsiField, KotlinLi @Override public boolean isValid() { - return myContainingClass.isValid(); + return containingClass.isValid(); } @Override @@ -159,14 +152,14 @@ public class KotlinLightField extends LightElement implements PsiField, KotlinLi @NotNull @Override - public JetProperty getOrigin() { - return myOriginalProperty; + public T getOrigin() { + return origin; } @NotNull @Override - public PsiField getDelegate() { - return myField; + public D getDelegate() { + return delegate; } @NotNull diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightFieldForDeclaration.kt b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightFieldForDeclaration.kt new file mode 100644 index 00000000000..c60893022a1 --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/light/KotlinLightFieldForDeclaration.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2014 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.jet.asJava.light + +import com.intellij.psi.* +import org.jetbrains.jet.lang.psi.JetProperty + +class KotlinLightFieldForDeclaration( + manager: PsiManager, + origin: JetProperty, + field: PsiField, + containingClass: PsiClass +) : KotlinLightField(manager, origin, field, containingClass) { + override fun copy() = KotlinLightFieldForDeclaration(getManager()!!, getOrigin(), getDelegate(), getContainingClass()!!) +} diff --git a/idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.java b/idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.java new file mode 100644 index 00000000000..a9ab4d53b8b --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.java @@ -0,0 +1,16 @@ +package test; + +class EnumEntriesInSwitch { + void foo() { + ZZZ a = ZZZ.A1; + switch (a) { + case A1: break; + case B1: break; + } + + switch (ZZZ.B1) { + case A1: break; + case B1: break; + } + } +} diff --git a/idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.kt b/idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.kt new file mode 100644 index 00000000000..5588b35f2e3 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/EnumEntriesInSwitch.kt @@ -0,0 +1,6 @@ +package test + +enum class ZZZ { + A1 + B1 +} diff --git a/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java b/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java index 90a2fb102cc..5585e0fa367 100644 --- a/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java @@ -76,4 +76,8 @@ public class KotlinAndJavaCheckerTest extends KotlinDaemonAnalyzerTestCase { public void testEnumAutoGeneratedMethods() throws Exception { doTest(true, true, "EnumAutoGeneratedMethods.java", "EnumAutoGeneratedMethods.kt"); } + + public void testEnumEntriesInSwitch() throws Exception { + doTest(true, true, "EnumEntriesInSwitch.java", "EnumEntriesInSwitch.kt"); + } }