diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt index 5127caf7eb8..ec25113ed21 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils internal open class KtLightClassForAnonymousDeclaration(fqNameFunction: ((KtClassOrObject) -> FqName), classOrObject: KtClassOrObject) : - KtLightClassForSourceDeclaration(fqNameFunction, classOrObject), PsiAnonymousClass { + KtLightClassForLocalDeclaration(fqNameFunction, classOrObject), PsiAnonymousClass { private var cachedBaseType: SoftReference? = null @@ -120,7 +120,7 @@ internal open class KtLightClassForAnonymousDeclaration(fqNameFunction: ((KtClas override fun getTypeParameterList() = null override fun isEnum() = false - override fun copy(): PsiElement = KtLightClassForAnonymousDeclaration({ classFqName }, classOrObject) + override fun copy(): PsiElement = KtLightClassForAnonymousDeclaration(classFqNameFunction, classOrObject) companion object { private val LOG = Logger.getInstance(KtLightClassForAnonymousDeclaration::class.java) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForEnumEntry.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForEnumEntry.kt index 43b87bb639b..c3864e1f602 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForEnumEntry.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForEnumEntry.kt @@ -28,4 +28,6 @@ internal class KtLightClassForEnumEntry( ): KtLightClassForAnonymousDeclaration({ fqName }, enumEntry), PsiEnumConstantInitializer { override fun getEnumConstant(): PsiEnumConstant = enumConstant override fun copy() = KtLightClassForEnumEntry(classFqName, classOrObject as KtEnumEntry, enumConstant) + + override fun getParent() = enumConstant } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt index ae59aec3a8e..cb900a9325a 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt @@ -21,10 +21,11 @@ import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtClassOrObject -open class KtLightClassForInterfaceDefaultImpls( +class KtLightClassForInterfaceDefaultImpls( classFqName: FqName, classOrObject: KtClassOrObject) : KtLightClassForSourceDeclaration({ classFqName }, classOrObject){ + override fun getParent() = containingClass override fun copy(): PsiElement { return KtLightClassForInterfaceDefaultImpls(classFqName, classOrObject.copy() as KtClassOrObject) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt new file mode 100644 index 00000000000..a08b4f6cd31 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2010-2016 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.classes + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.impl.light.LightClass +import com.intellij.psi.impl.light.LightMethod +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType + +open class KtLightClassForLocalDeclaration( + classFqNameFunction: (KtClassOrObject) -> FqName, + classOrObject: KtClassOrObject +) : KtLightClassForSourceDeclaration(classFqNameFunction, classOrObject) { + + override fun copy(): PsiElement = KtLightClassForLocalDeclaration(classFqNameFunction, classOrObject.copy() as KtClassOrObject) + + override fun getParent() = _parent + + private val _parent: PsiElement? by lazy(LazyThreadSafetyMode.PUBLICATION, this::computeParent) + + private fun computeParent(): PsiElement? { + fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? { + if (method == null || name == null) return null + + var containingClass: PsiClass? = method.containingClass ?: return null + + val currentFileName = classOrObject.containingFile.name + + var createWrapper = forceMethodWrapping + // Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views + if (containingClass is KtLightClassForFacade) { + containingClass = object : LightClass(containingClass as KtLightClassForFacade, KotlinLanguage.INSTANCE) { + override fun getName(): String? { + return currentFileName + } + } + createWrapper = true + } + + if (createWrapper) { + return object : LightMethod(myManager, method, containingClass!!, KotlinLanguage.INSTANCE) { + override fun getParent(): PsiElement { + return getContainingClass()!! + } + + override fun getName(): String { + return name + } + } + } + + return method + } + + var declaration: PsiElement? = KtPsiUtil.getTopmostParentOfTypes( + classOrObject, + KtNamedFunction::class.java, + KtConstructor::class.java, + KtProperty::class.java, + KtAnonymousInitializer::class.java, + KtParameter::class.java) + + if (declaration is KtParameter) { + declaration = declaration.getStrictParentOfType() + } + + if (declaration is KtFunction) { + return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false) + } + + // Represent the property as a fake method with the same name + if (declaration is KtProperty) { + return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true) + } + + if (declaration is KtAnonymousInitializer) { + val parent = declaration.parent + val grandparent = parent.parent + + if (parent is KtClassBody && grandparent is KtClassOrObject) { + return grandparent.toLightClass() + } + } + + if (declaration is KtClass) { + return declaration.toLightClass() + } + return null + } + +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index b09eb462b94..d43d026f3ba 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -23,8 +23,6 @@ import com.intellij.openapi.util.Key import com.intellij.psi.* import com.intellij.psi.impl.DebugUtil import com.intellij.psi.impl.java.stubs.PsiJavaFileStub -import com.intellij.psi.impl.light.LightClass -import com.intellij.psi.impl.light.LightMethod import com.intellij.psi.scope.PsiScopeProcessor import com.intellij.psi.search.SearchScope import com.intellij.psi.stubs.IStubElementType @@ -42,22 +40,20 @@ import org.jetbrains.kotlin.asJava.elements.KtLightModifierListWithExplicitModif import org.jetbrains.kotlin.asJava.elements.KtLightPsiReferenceList import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import java.util.* import javax.swing.Icon -open class KtLightClassForSourceDeclaration( - private val classFqNameFunction: ((KtClassOrObject) -> FqName), +abstract class KtLightClassForSourceDeclaration( + protected val classFqNameFunction: ((KtClassOrObject) -> FqName), protected val classOrObject: KtClassOrObject) : KtLightClassBase(classOrObject.manager), KtJavaMirrorMarker, StubBasedPsiElement> { private val lightIdentifier = KtLightIdentifier(this, classOrObject) @@ -76,92 +72,12 @@ open class KtLightClassForSourceDeclaration( KtLightPsiReferenceList(listDelegate, this) } - private fun getLocalClassParent(): PsiElement? { - fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? { - if (method == null || name == null) return null - - var containingClass: PsiClass? = method.containingClass ?: return null - - val currentFileName = classOrObject.containingFile.name - - var createWrapper = forceMethodWrapping - // Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views - if (containingClass is KtLightClassForFacade) { - containingClass = object : LightClass(containingClass as KtLightClassForFacade, KotlinLanguage.INSTANCE) { - override fun getName(): String? { - return currentFileName - } - } - createWrapper = true - } - - if (createWrapper) { - return object : LightMethod(myManager, method, containingClass!!, KotlinLanguage.INSTANCE) { - override fun getParent(): PsiElement { - return getContainingClass()!! - } - - override fun getName(): String { - return name - } - } - } - - return method - } - - var declaration: PsiElement? = KtPsiUtil.getTopmostParentOfTypes( - classOrObject, - KtNamedFunction::class.java, - KtConstructor::class.java, - KtProperty::class.java, - KtAnonymousInitializer::class.java, - KtParameter::class.java) - - if (declaration is KtParameter) { - declaration = declaration.getStrictParentOfType() - } - - if (declaration is KtFunction) { - return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false) - } - - // Represent the property as a fake method with the same name - if (declaration is KtProperty) { - return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true) - } - - if (declaration is KtAnonymousInitializer) { - val parent = declaration.parent - val grandparent = parent.parent - - if (parent is KtClassBody && grandparent is KtClassOrObject) { - return grandparent.toLightClass() - } - } - - if (declaration is KtClass) { - return declaration.toLightClass() - } - return null - } - - private val _parent: PsiElement? by lazy(LazyThreadSafetyMode.PUBLICATION) { - if (classOrObject.isLocal()) - getLocalClassParent() - else if (classOrObject.isTopLevel()) - containingFile - else - containingClass - } - override val kotlinOrigin: KtClassOrObject = classOrObject override fun getFqName(): FqName = classFqName - override fun copy(): PsiElement { - return KtLightClassForSourceDeclaration({ classFqName }, classOrObject.copy() as KtClassOrObject) - } + abstract override fun copy(): PsiElement + abstract override fun getParent(): PsiElement? override val clsDelegate: PsiClass by lazy(LazyThreadSafetyMode.PUBLICATION) { val javaFileStub = getJavaFileStub() @@ -261,8 +177,6 @@ open class KtLightClassForSourceDeclaration( return super.getContainingClass() } - override fun getParent(): PsiElement? = _parent - private val _typeParameterList: PsiTypeParameterList by lazy(LazyThreadSafetyMode.PUBLICATION) { LightClassUtil.buildLightTypeParameterList(this, classOrObject) } @@ -429,21 +343,27 @@ open class KtLightClassForSourceDeclaration( fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? { if (classOrObject is KtObjectDeclaration && classOrObject.isObjectLiteral()) { - if (classOrObject.containingFile.virtualFile == null) { - return null - } + if (classOrObject.containingFile.virtualFile == null) return null + val data = getLightClassDataExactly(classOrObject) ?: return null return KtLightClassForAnonymousDeclaration( - { predictFqName(it) ?: throw IllegalArgumentException("Failed to create fqname for anonymous class: " + classOrObject) }, + { data.jvmQualifiedName }, classOrObject) } + if (classOrObject.isLocal()) { + if (classOrObject.containingFile.virtualFile == null) return null + + val data = getLightClassDataExactly(classOrObject) ?: return null + return KtLightClassForLocalDeclaration({ data.jvmQualifiedName }, classOrObject) + } + if (isEnumEntryWithoutBody(classOrObject)) { return null } - val fqName = predictFqName(classOrObject) ?: return null - return KtLightClassForSourceDeclaration({ fqName }, classOrObject) + val fqName = classOrObject.fqName ?: return null + return KtLightClassImpl({ fqName }, classOrObject) } private fun isEnumEntryWithoutBody(classOrObject: KtClassOrObject): Boolean { @@ -453,15 +373,6 @@ open class KtLightClassForSourceDeclaration( return classOrObject.getBody()?.declarations?.isEmpty() ?: true } - private fun predictFqName(classOrObject: KtClassOrObject): FqName? { - if (classOrObject.isLocal()) { - if (classOrObject.containingFile.virtualFile == null) return null - val data = getLightClassDataExactly(classOrObject) - return data?.jvmQualifiedName - } - return classOrObject.fqName - } - fun getLightClassData(classOrObject: KtClassOrObject): LightClassData { return getLightClassCachedValue(classOrObject).value } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt new file mode 100644 index 00000000000..38a3880c705 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2016 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.classes + +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtClassOrObject + +// light class for top level or (inner/nested of top level) source declarations +class KtLightClassImpl( + classFqNameFunction: (KtClassOrObject) -> FqName, + classOrObject: KtClassOrObject +) : KtLightClassForSourceDeclaration(classFqNameFunction, classOrObject) { + override fun getParent() = if (classOrObject.isTopLevel()) + containingFile + else + containingClass + + override fun copy() = KtLightClassImpl(classFqNameFunction, classOrObject.copy() as KtClassOrObject) +} \ No newline at end of file