Refactor light fields: move all implementation into one file and prettify code

This commit is contained in:
Pavel V. Talanov
2015-10-29 18:07:07 +03:00
parent e6b498f943
commit e5f075c7f6
9 changed files with 93 additions and 218 deletions
@@ -1,40 +0,0 @@
/*
* 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.*
import org.jetbrains.kotlin.psi.KtEnumEntry
class KotlinLightEnumConstant(
manager: PsiManager,
origin: KtEnumEntry,
enumConstant: PsiEnumConstant,
containingClass: PsiClass,
private val initializingClass: PsiEnumConstantInitializer?
) : KotlinLightField<KtEnumEntry, PsiEnumConstant>(manager, origin, enumConstant, containingClass), PsiEnumConstant {
override fun copy() = KotlinLightEnumConstant(getManager()!!, getOrigin(), getDelegate(), getContainingClass()!!, initializingClass)
// 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? = initializingClass
override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer =
initializingClass ?: throw UnsupportedOperationException("Can't create enum constant body: ${getDelegate().getName()}")
override fun resolveConstructor(): PsiMethod? = getDelegate().resolveConstructor()
override fun resolveMethod(): PsiMethod? = getDelegate().resolveMethod()
override fun resolveMethodGenerics(): JavaResolveResult = getDelegate().resolveMethodGenerics()
}
@@ -16,135 +16,122 @@
package org.jetbrains.kotlin.asJava
import com.intellij.lang.Language
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.util.TextRange
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightElement
import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.search.SearchScope
import com.intellij.util.IncorrectOperationException
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
public interface KotlinLightField : PsiField, KotlinLightElement<KtDeclaration, PsiField>
// Copied from com.intellij.psi.impl.light.LightField
abstract class KotlinLightField<T : KtDeclaration, D : PsiField>(
manager: PsiManager,
private val origin: T,
private val delegate: D,
private val containingClass: PsiClass
) : LightElement(manager, JavaLanguage.INSTANCE), PsiField, KotlinLightElement<T, D> {
sealed class KotlinLightFieldImpl(
private val origin: KtDeclaration?,
private val delegate: PsiField,
private val containingClass: KotlinLightClass
) : LightElement(delegate.manager, KotlinLanguage.INSTANCE), KotlinLightField {
@Throws(IncorrectOperationException::class)
override fun setInitializer(initializer: PsiExpression?) = throw IncorrectOperationException("Not supported")
abstract override fun copy(): KotlinLightField<T, D>
override fun getUseScope() = origin?.useScope ?: super.getUseScope()
override fun getName() = delegate.name
override fun getNameIdentifier() = delegate.nameIdentifier
override fun getDocComment() = delegate.docComment
override fun isDeprecated() = delegate.isDeprecated
override fun getContainingClass() = containingClass
override fun getType() = delegate.type
override fun getTypeElement() = delegate.typeElement
override fun getInitializer() = delegate.initializer
override fun hasInitializer() = delegate.hasInitializer()
@Throws(IncorrectOperationException::class)
override fun setInitializer(initializer: PsiExpression?) {
throw IncorrectOperationException("Not supported")
}
override fun normalizeDeclaration() = throw IncorrectOperationException("Not supported")
override fun getUseScope(): SearchScope {
return origin.useScope
}
override fun getName(): String? {
return delegate.name
}
override fun getNameIdentifier(): PsiIdentifier {
return delegate.nameIdentifier
}
override fun getDocComment(): PsiDocComment? {
return delegate.docComment
}
override fun isDeprecated(): Boolean {
return delegate.isDeprecated
}
override fun getContainingClass(): PsiClass? {
return containingClass
}
override fun getType(): PsiType {
return delegate.type
}
override fun getTypeElement(): PsiTypeElement? {
return delegate.typeElement
}
override fun getInitializer(): PsiExpression? {
return delegate.initializer
}
override fun hasInitializer(): Boolean {
return delegate.hasInitializer()
}
override fun computeConstantValue() = delegate.computeConstantValue()
@Throws(IncorrectOperationException::class)
override fun normalizeDeclaration() {
throw IncorrectOperationException("Not supported")
}
override fun setName(@NonNls name: String) = throw IncorrectOperationException("Not supported")
override fun computeConstantValue(): Any? {
return delegate.computeConstantValue()
}
override fun getModifierList() = delegate.modifierList
@Throws(IncorrectOperationException::class)
override fun setName(@NonNls name: String): PsiElement {
throw IncorrectOperationException("Not supported")
}
override fun hasModifierProperty(@NonNls name: String) = delegate.hasModifierProperty(name)
override fun getModifierList(): PsiModifierList? {
return delegate.modifierList
}
override fun getText() = delegate.text
override fun hasModifierProperty(@NonNls name: String): Boolean {
return delegate.hasModifierProperty(name)
}
override fun getTextRange() = TextRange(-1, -1)
override fun getText(): String {
return delegate.text
}
override fun isValid() = containingClass.isValid
override fun getTextRange(): TextRange {
return TextRange(-1, -1)
}
override fun toString(): String = "${this.javaClass.simpleName}:$name"
override fun isValid(): Boolean {
return containingClass.isValid
}
override fun getOrigin() = origin
override fun toString(): String {
return "KotlinLightField:" + name!!
}
override fun getDelegate() = delegate
override fun getOrigin(): T {
return origin
}
override fun getDelegate(): D {
return delegate
}
override fun getNavigationElement(): PsiElement {
return getOrigin()
}
override fun getLanguage(): Language {
return KotlinLanguage.INSTANCE
}
override fun getNavigationElement() = origin ?: super.getNavigationElement()
override fun isEquivalentTo(another: PsiElement?): Boolean {
if (another is KotlinLightField<*, *> && origin.isEquivalentTo(another.getOrigin())) {
if (another is KotlinLightField && origin == another.getOrigin() && delegate == another.getDelegate()) {
return true
}
return super.isEquivalentTo(another)
}
override fun isWritable(): Boolean {
return getOrigin().isWritable
override fun isWritable() = getOrigin()?.isWritable ?: false
override fun copy() = Factory.create(origin?.copy() as? KtDeclaration, delegate, containingClass)
class KotlinLightEnumConstant(
origin: KtEnumEntry,
enumConstant: PsiEnumConstant,
containingClass: KotlinLightClass,
private val initializingClass: PsiEnumConstantInitializer?
) : KotlinLightFieldImpl(origin, enumConstant, containingClass), PsiEnumConstant {
override fun getDelegate() = super.getDelegate() as PsiEnumConstant
// 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() = getDelegate().argumentList
override fun getInitializingClass(): PsiEnumConstantInitializer? = initializingClass
override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer =
initializingClass ?: throw UnsupportedOperationException("Can't create enum constant body: ${getDelegate().getName()}")
override fun resolveConstructor() = getDelegate().resolveConstructor()
override fun resolveMethod() = getDelegate().resolveMethod()
override fun resolveMethodGenerics() = getDelegate().resolveMethodGenerics()
}
public class KotlinLightFieldForDeclaration(origin: KtDeclaration?, delegate: PsiField, containingClass: KotlinLightClass)
: KotlinLightFieldImpl(origin, delegate, containingClass)
companion object Factory {
fun create(origin: KtDeclaration?, delegate: PsiField, containingClass: KotlinLightClass): KotlinLightField {
if (origin is KtEnumEntry) {
assert(delegate is PsiEnumConstant) { "Field delegate should be an enum constant (${delegate.name}):\n${origin.getElementTextWithContext()}" }
val enumConstant = delegate as PsiEnumConstant
val enumConstantFqName = FqName(containingClass.getFqName().asString() + "." + origin.name)
val initializingClass = if (origin.declarations.isEmpty())
null
else
KotlinLightClassForEnumEntry(delegate.manager, enumConstantFqName, origin, enumConstant)
return KotlinLightEnumConstant(origin, enumConstant, containingClass, initializingClass)
}
return KotlinLightFieldForDeclaration(origin, delegate, containingClass)
}
}
}
@@ -1,29 +0,0 @@
/*
* 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.*
import org.jetbrains.kotlin.psi.KtDeclaration
class KotlinLightFieldForDeclaration(
manager: PsiManager,
origin: KtDeclaration,
field: PsiField,
containingClass: PsiClass
) : KotlinLightField<KtDeclaration, PsiField>(manager, origin, field, containingClass) {
override fun copy() = KotlinLightFieldForDeclaration(getManager()!!, getOrigin(), getDelegate(), getContainingClass()!!)
}
@@ -1,28 +0,0 @@
/*
* 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.PsiClass
import com.intellij.psi.PsiField
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.light.LightField
public class KotlinNoOriginLightField(manager: PsiManager, field: PsiField, containingClass: PsiClass) :
LightField(manager, field, containingClass) {
override fun toString() = "KotlinNoOriginLightField:${getName()}"
}
@@ -122,22 +122,7 @@ public abstract class KotlinWrappingLightClass extends AbstractLightClass implem
@Override
public PsiField fun(PsiField field) {
KtDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(field);
if (declaration instanceof KtEnumEntry) {
assert field instanceof PsiEnumConstant : "Field delegate should be an enum constant (" + field.getName() + "):\n" +
PsiUtilsKt.getElementTextWithContext(declaration);
KtEnumEntry enumEntry = (KtEnumEntry) declaration;
PsiEnumConstant enumConstant = (PsiEnumConstant) field;
FqName enumConstantFqName = new FqName(getFqName().asString() + "." + enumEntry.getName());
KotlinLightClassForEnumEntry initializingClass =
enumEntry.getDeclarations().isEmpty()
? null
: new KotlinLightClassForEnumEntry(myManager, enumConstantFqName, enumEntry, enumConstant);
return new KotlinLightEnumConstant(myManager, enumEntry, enumConstant, KotlinWrappingLightClass.this, initializingClass);
}
if (declaration != null) {
return new KotlinLightFieldForDeclaration(myManager, declaration, field, KotlinWrappingLightClass.this);
}
return new KotlinNoOriginLightField(myManager, field, KotlinWrappingLightClass.this);
return KotlinLightFieldImpl.Factory.create(declaration, field, KotlinWrappingLightClass.this);
}
});
}
@@ -179,7 +179,7 @@ public object LightClassUtil {
}
for (field in psiClass.fields) {
if (field is KotlinLightField<*, *> && field.getOrigin() === declaration) {
if (field is KotlinLightField && field.getOrigin() === declaration) {
return field
}
}
@@ -192,7 +192,7 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
if (originLightClass != null) {
val lightDeclarations: List<KotlinLightElement<*, *>?> =
originLightClass.methods.map { it as? KotlinLightMethod } +
originLightClass.fields.map { it as? KotlinLightFieldForDeclaration }
originLightClass.fields.map { it as? KotlinLightField }
for (declaration in element.declarations) {
val lightDeclaration = lightDeclarations.find { it?.getOrigin() == declaration }
@@ -20,7 +20,7 @@ import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.KotlinLightClass
import org.jetbrains.kotlin.asJava.KotlinLightFieldForDeclaration
import org.jetbrains.kotlin.asJava.KotlinLightField
import org.jetbrains.kotlin.idea.quickfix.AddConstModifierFix
import org.jetbrains.kotlin.idea.quickfix.AddConstModifierIntention
import org.jetbrains.kotlin.idea.quickfix.replaceReferencesToGetterByReferenceToField
@@ -39,7 +39,7 @@ class DeprecatedUsageOfStaticFieldInspection : LocalInspectionTool(), CleanupLoc
val resolvedTo = expression.reference?.resolve() as? PsiField ?: return
if (!resolvedTo.hasModifierProperty(PsiModifier.STATIC) || !resolvedTo.isDeprecated) return
val kotlinProperty = (resolvedTo as? KotlinLightFieldForDeclaration)?.getOrigin() as? KtProperty
val kotlinProperty = (resolvedTo as? KotlinLightField)?.getOrigin() as? KtProperty
// NOTE: this is hack to avoid test failing with "action is still available" error
if (kotlinProperty?.hasJvmFieldAnnotationOrConstModifier() ?: false) return
@@ -88,7 +88,7 @@ class DeprecatedUsageOfStaticFieldInspection : LocalInspectionTool(), CleanupLoc
abstract class StaticFieldUsageFix: LocalQuickFix {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val deprecatedField = descriptor.psiElement.reference?.resolve() as? PsiField ?: return
val kotlinProperty = (deprecatedField as? KotlinLightFieldForDeclaration)?.getOrigin() as? KtProperty
val kotlinProperty = (deprecatedField as? KotlinLightField)?.getOrigin() as? KtProperty
if (kotlinProperty != null && kotlinProperty.hasJvmFieldAnnotationOrConstModifier()) return
@@ -422,7 +422,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
identifier = Identifier("size()", isNullable).assignNoPrototype()
}
else if (qualifier != null) {
if (target is KotlinLightField<*, *> && target.getOrigin() is KtObjectDeclaration) {
if (target is KotlinLightField && target.getOrigin() is KtObjectDeclaration) {
result = codeConverter.convertExpression(qualifier)
return
}