Light classes in IDE: Make light class delegate construction a two step process
Step 0: Light class object is created, no delegates are computed Step 1: constructs dummy delegate which can not be relied upon to know signature of any member It can be used to construct light field and light method objects (which can correctly respond to some queries) before constructing real delegate Step 2: Construct real delegate if dummy delegate is not enough to respond to a query This speeds up multiple scenarios where getMethods() and getFields() are called on numerous classes Dummy delegate's faster consruction is achieved by using specially setup dumb analysis instead of ide analysis Introduce LazyLightClassDataHolder: which manages creation of Step 1 and Step 2 delegates Introduce MemberIndex: keeping track of member creation order, helps matching light class delegates created in different contexts KtLightMethod and Field: make use of dummy delegate KtLightMethod no longer extends LightMethod since it requires eager delegate construction KtLightMethod now implements PsiAnnotationMethod for convenience (ClsMethodImpl implements PsiAnnotationMethod)
This commit is contained in:
+29
-3
@@ -17,15 +17,23 @@
|
|||||||
package org.jetbrains.kotlin.asJava.builder
|
package org.jetbrains.kotlin.asJava.builder
|
||||||
|
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiClassType
|
||||||
import com.intellij.psi.impl.DebugUtil
|
import com.intellij.psi.impl.DebugUtil
|
||||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil.findClass
|
import org.jetbrains.kotlin.asJava.LightClassUtil.findClass
|
||||||
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder.javaFileStub
|
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder.javaFileStub
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
|
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.debugText.getDebugText
|
||||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||||
|
|
||||||
interface LightClassDataHolder {
|
interface LightClassDataHolder {
|
||||||
@@ -33,15 +41,33 @@ interface LightClassDataHolder {
|
|||||||
val extraDiagnostics: Diagnostics
|
val extraDiagnostics: Diagnostics
|
||||||
|
|
||||||
fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData
|
fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData
|
||||||
fun findData(classOrObject: KtClassOrObject): LightClassData = findData { it.findDelegate(classOrObject) }
|
|
||||||
fun findData(classFqName: FqName): LightClassData = findData { it.findDelegate(classFqName) }
|
fun findDataForDefaultImpls(classOrObject: KtClassOrObject) = findData {
|
||||||
|
it.findDelegate(classOrObject).findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false)
|
||||||
|
?: throw IllegalStateException("Couldn't get delegate for $this\n in ${DebugUtil.stubTreeToString(it)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData = findData { it.findDelegate(classOrObject) }
|
||||||
|
fun findDataForFacade(classFqName: FqName): LightClassData = findData { it.findDelegate(classFqName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LightClassData {
|
interface LightClassData {
|
||||||
val clsDelegate: PsiClass
|
val clsDelegate: PsiClass
|
||||||
|
|
||||||
|
val supertypes: Array<PsiClassType> get() { return clsDelegate.superTypes }
|
||||||
|
|
||||||
|
fun getOwnFields(containingClass: KtLightClass): List<KtLightField>
|
||||||
|
fun getOwnMethods(containingClass: KtLightClass): List<KtLightMethod>
|
||||||
}
|
}
|
||||||
|
|
||||||
class LightClassDataImpl(override val clsDelegate: PsiClass) : LightClassData {
|
class LightClassDataImpl(override val clsDelegate: PsiClass) : LightClassData {
|
||||||
|
override fun getOwnFields(containingClass: KtLightClass): List<KtLightField> {
|
||||||
|
return clsDelegate.fields.map { KtLightFieldImpl.fromClsField(it, containingClass) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOwnMethods(containingClass: KtLightClass): List<KtLightMethod> {
|
||||||
|
return clsDelegate.methods.map { KtLightMethodImpl.fromClsMethod(it, containingClass) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object InvalidLightClassDataHolder : LightClassDataHolder {
|
object InvalidLightClassDataHolder : LightClassDataHolder {
|
||||||
@@ -77,7 +103,7 @@ fun PsiJavaFileStub.findDelegate(classOrObject: KtClassOrObject): PsiClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val stubFileText = DebugUtil.stubTreeToString(this)
|
val stubFileText = DebugUtil.stubTreeToString(this)
|
||||||
throw IllegalStateException("Couldn't get delegate for $this\nin $ktFileText\nstub: \n$stubFileText")
|
throw IllegalStateException("Couldn't get delegate for ${classOrObject.getDebugText()}\nin $ktFileText\nstub: \n$stubFileText")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PsiJavaFileStub.findDelegate(classFqName: FqName): PsiClass {
|
fun PsiJavaFileStub.findDelegate(classFqName: FqName): PsiClass {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.builder
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.util.UserDataHolder
|
||||||
|
import com.intellij.psi.PsiMember
|
||||||
|
import com.intellij.psi.StubBasedPsiElement
|
||||||
|
|
||||||
|
data class MemberIndex(private val index: Int) {
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val KEY = Key.create<MemberIndex>("MEMBER_INDEX")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val PsiMember.memberIndex: MemberIndex?
|
||||||
|
get() = ((this as? StubBasedPsiElement<*>)?.stub as? UserDataHolder)?.getUserData(MemberIndex.KEY)
|
||||||
+3
-1
@@ -26,8 +26,8 @@ import com.intellij.psi.stubs.StubElement;
|
|||||||
import com.intellij.util.containers.Stack;
|
import com.intellij.util.containers.Stack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.fileClasses.OldPackageFacadeClassUtils;
|
|
||||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder;
|
import org.jetbrains.kotlin.codegen.AbstractClassBuilder;
|
||||||
|
import org.jetbrains.kotlin.fileClasses.OldPackageFacadeClassUtils;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||||
@@ -53,6 +53,7 @@ public class StubClassBuilder extends AbstractClassBuilder {
|
|||||||
private StubBuildingVisitor v;
|
private StubBuildingVisitor v;
|
||||||
private final Stack<StubElement> parentStack;
|
private final Stack<StubElement> parentStack;
|
||||||
private boolean isPackageClass = false;
|
private boolean isPackageClass = false;
|
||||||
|
private int memberIndex = 0;
|
||||||
|
|
||||||
public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
|
public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
|
||||||
this.parentStack = parentStack;
|
this.parentStack = parentStack;
|
||||||
@@ -196,6 +197,7 @@ public class StubClassBuilder extends AbstractClassBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN, LightElementOriginKt.toLightMemberOrigin(origin));
|
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN, LightElementOriginKt.toLightMemberOrigin(origin));
|
||||||
|
last.putUserData(MemberIndex.KEY, new MemberIndex(memberIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.PsiManager
|
||||||
|
import org.jetbrains.kotlin.asJava.builder.LightClassData
|
||||||
|
|
||||||
|
abstract class KtLazyLightClass(manager: PsiManager) : KtLightClassBase(manager) {
|
||||||
|
abstract val lightClassData: LightClassData
|
||||||
|
|
||||||
|
|
||||||
|
override fun getOwnFields() = lightClassData.getOwnFields(this)
|
||||||
|
override fun getOwnMethods() = lightClassData.getOwnMethods(this)
|
||||||
|
override fun getSuperTypes() = lightClassData.supertypes
|
||||||
|
|
||||||
|
}
|
||||||
+6
-2
@@ -51,7 +51,7 @@ class KtLightClassForFacade private constructor(
|
|||||||
private val facadeClassFqName: FqName,
|
private val facadeClassFqName: FqName,
|
||||||
private val lightClassDataCache: CachedValue<LightClassDataHolder>,
|
private val lightClassDataCache: CachedValue<LightClassDataHolder>,
|
||||||
files: Collection<KtFile>
|
files: Collection<KtFile>
|
||||||
) : KtLightClassBase(manager) {
|
) : KtLazyLightClass(manager) {
|
||||||
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
||||||
|
|
||||||
class FacadeStubCache(private val project: Project) {
|
class FacadeStubCache(private val project: Project) {
|
||||||
@@ -194,8 +194,12 @@ class KtLightClassForFacade private constructor(
|
|||||||
|
|
||||||
override fun copy() = KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files)
|
override fun copy() = KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files)
|
||||||
|
|
||||||
|
override val lightClassData by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
|
lightClassDataCache.value.findDataForFacade(facadeClassFqName)
|
||||||
|
}
|
||||||
|
|
||||||
override val clsDelegate: PsiClass
|
override val clsDelegate: PsiClass
|
||||||
get() = lightClassDataCache.value.findData(facadeClassFqName).clsDelegate
|
get() = lightClassData.clsDelegate
|
||||||
|
|
||||||
override fun getNavigationElement() = files.iterator().next()
|
override fun getNavigationElement() = files.iterator().next()
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -17,15 +17,12 @@
|
|||||||
package org.jetbrains.kotlin.asJava.classes
|
package org.jetbrains.kotlin.asJava.classes
|
||||||
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.DebugUtil
|
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassData
|
import org.jetbrains.kotlin.asJava.builder.LightClassData
|
||||||
import org.jetbrains.kotlin.asJava.builder.findDelegate
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
|
||||||
class KtLightClassForInterfaceDefaultImpls(
|
class KtLightClassForInterfaceDefaultImpls(classOrObject: KtClassOrObject)
|
||||||
classOrObject: KtClassOrObject)
|
|
||||||
: KtLightClassForSourceDeclaration(classOrObject) {
|
: KtLightClassForSourceDeclaration(classOrObject) {
|
||||||
override fun getQualifiedName(): String? = containingClass?.qualifiedName?.let { it + ".${JvmAbi.DEFAULT_IMPLS_CLASS_NAME}" }
|
override fun getQualifiedName(): String? = containingClass?.qualifiedName?.let { it + ".${JvmAbi.DEFAULT_IMPLS_CLASS_NAME}" }
|
||||||
|
|
||||||
@@ -37,10 +34,7 @@ class KtLightClassForInterfaceDefaultImpls(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun findLightClassData(): LightClassData {
|
override fun findLightClassData(): LightClassData {
|
||||||
return getLightClassDataHolder().findData {
|
return getLightClassDataHolder().findDataForDefaultImpls(classOrObject)
|
||||||
it.findDelegate(classOrObject).findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false)
|
|
||||||
?: throw IllegalStateException("Couldn't get delegate for $this\n in ${DebugUtil.stubTreeToString(it)}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
||||||
|
|||||||
+3
-3
@@ -59,7 +59,7 @@ import java.util.*
|
|||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtClassOrObject)
|
abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtClassOrObject)
|
||||||
: KtLightClassBase(classOrObject.manager), StubBasedPsiElement<KotlinClassOrObjectStub<out KtClassOrObject>> {
|
: KtLazyLightClass(classOrObject.manager), StubBasedPsiElement<KotlinClassOrObjectStub<out KtClassOrObject>> {
|
||||||
private val lightIdentifier = KtLightIdentifier(this, classOrObject)
|
private val lightIdentifier = KtLightIdentifier(this, classOrObject)
|
||||||
|
|
||||||
private val _extendsList by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
private val _extendsList by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
@@ -80,9 +80,9 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
|||||||
|
|
||||||
override val clsDelegate: PsiClass get() = lightClassData.clsDelegate
|
override val clsDelegate: PsiClass get() = lightClassData.clsDelegate
|
||||||
|
|
||||||
private val lightClassData: LightClassData by lazy(LazyThreadSafetyMode.PUBLICATION) { findLightClassData() }
|
override val lightClassData: LightClassData by lazy(LazyThreadSafetyMode.PUBLICATION) { findLightClassData() }
|
||||||
|
|
||||||
open protected fun findLightClassData() = getLightClassDataHolder().findData(classOrObject)
|
open protected fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject)
|
||||||
|
|
||||||
private fun getJavaFileStub(): PsiJavaFileStub = getLightClassDataHolder().javaFileStub
|
private fun getJavaFileStub(): PsiJavaFileStub = getLightClassDataHolder().javaFileStub
|
||||||
|
|
||||||
|
|||||||
+39
-19
@@ -36,13 +36,16 @@ import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
|||||||
import java.lang.UnsupportedOperationException
|
import java.lang.UnsupportedOperationException
|
||||||
|
|
||||||
// Copied from com.intellij.psi.impl.light.LightField
|
// Copied from com.intellij.psi.impl.light.LightField
|
||||||
sealed class KtLightFieldImpl(
|
sealed class KtLightFieldImpl<T: PsiField>(
|
||||||
override val lightMemberOrigin: LightMemberOrigin?,
|
override val lightMemberOrigin: LightMemberOrigin?,
|
||||||
override val clsDelegate: PsiField,
|
computeRealDelegate: () -> T,
|
||||||
private val containingClass: KtLightClass
|
private val containingClass: KtLightClass,
|
||||||
) : LightElement(clsDelegate.manager, KotlinLanguage.INSTANCE), KtLightField {
|
private val dummyDelegate: PsiField?
|
||||||
|
) : LightElement(containingClass.manager, KotlinLanguage.INSTANCE), KtLightField {
|
||||||
private val lightIdentifier by lazy(LazyThreadSafetyMode.PUBLICATION) { KtLightIdentifier(this, kotlinOrigin as? KtNamedDeclaration) }
|
private val lightIdentifier by lazy(LazyThreadSafetyMode.PUBLICATION) { KtLightIdentifier(this, kotlinOrigin as? KtNamedDeclaration) }
|
||||||
|
|
||||||
|
override val clsDelegate: T by lazy(LazyThreadSafetyMode.PUBLICATION, computeRealDelegate)
|
||||||
|
|
||||||
@Throws(IncorrectOperationException::class)
|
@Throws(IncorrectOperationException::class)
|
||||||
override fun setInitializer(initializer: PsiExpression?) = throw IncorrectOperationException("Not supported")
|
override fun setInitializer(initializer: PsiExpression?) = throw IncorrectOperationException("Not supported")
|
||||||
|
|
||||||
@@ -50,7 +53,7 @@ sealed class KtLightFieldImpl(
|
|||||||
|
|
||||||
override fun getPresentation(): ItemPresentation? = (kotlinOrigin ?: this).let { ItemPresentationProviders.getItemPresentation(it) }
|
override fun getPresentation(): ItemPresentation? = (kotlinOrigin ?: this).let { ItemPresentationProviders.getItemPresentation(it) }
|
||||||
|
|
||||||
override fun getName() = clsDelegate.name
|
override fun getName() = dummyDelegate?.name ?: clsDelegate.name
|
||||||
|
|
||||||
override fun getNameIdentifier() = lightIdentifier
|
override fun getNameIdentifier() = lightIdentifier
|
||||||
|
|
||||||
@@ -134,41 +137,58 @@ sealed class KtLightFieldImpl(
|
|||||||
|
|
||||||
class KtLightEnumConstant(
|
class KtLightEnumConstant(
|
||||||
origin: LightMemberOrigin?,
|
origin: LightMemberOrigin?,
|
||||||
override val clsDelegate: PsiEnumConstant,
|
computeDelegate: () -> PsiEnumConstant,
|
||||||
containingClass: KtLightClass,
|
containingClass: KtLightClass,
|
||||||
private val initializingClass: PsiEnumConstantInitializer?
|
dummyDelegate: PsiField?
|
||||||
) : KtLightFieldImpl(origin, clsDelegate, containingClass), PsiEnumConstant {
|
) : KtLightFieldImpl<PsiEnumConstant>(origin, computeDelegate , containingClass, dummyDelegate), PsiEnumConstant {
|
||||||
|
private val initializingClass by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
|
val kotlinEnumEntry = (lightMemberOrigin as? LightMemberOriginForDeclaration)?.originalElement as? KtEnumEntry
|
||||||
|
if (kotlinEnumEntry != null && kotlinEnumEntry.declarations.isNotEmpty()) {
|
||||||
|
KtLightClassForEnumEntry(kotlinEnumEntry, clsDelegate)
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: we don't use "delegation by" because the compiler would generate method calls to ALL of PsiEnumConstant members,
|
// 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
|
// but we need only members whose implementations are not present in KotlinLightField
|
||||||
override fun getArgumentList() = clsDelegate.argumentList
|
override fun getArgumentList() = clsDelegate.argumentList
|
||||||
|
|
||||||
override fun getInitializingClass(): PsiEnumConstantInitializer? = initializingClass
|
override fun getInitializingClass(): PsiEnumConstantInitializer? = initializingClass
|
||||||
override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer =
|
override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer {
|
||||||
initializingClass ?: throw UnsupportedOperationException("Can't create enum constant body: ${clsDelegate.name}")
|
return initializingClass ?: throw UnsupportedOperationException("Can't create enum constant body: ${clsDelegate.name}")
|
||||||
|
}
|
||||||
|
|
||||||
override fun resolveConstructor() = clsDelegate.resolveConstructor()
|
override fun resolveConstructor() = clsDelegate.resolveConstructor()
|
||||||
override fun resolveMethod() = clsDelegate.resolveMethod()
|
override fun resolveMethod() = clsDelegate.resolveMethod()
|
||||||
override fun resolveMethodGenerics() = clsDelegate.resolveMethodGenerics()
|
override fun resolveMethodGenerics() = clsDelegate.resolveMethodGenerics()
|
||||||
}
|
}
|
||||||
|
|
||||||
class KtLightFieldForDeclaration(origin: LightMemberOrigin?, delegate: PsiField, containingClass: KtLightClass) :
|
class KtLightFieldForDeclaration(origin: LightMemberOrigin?, computeDelegate: () -> PsiField, containingClass: KtLightClass, dummyDelegate: PsiField?) :
|
||||||
KtLightFieldImpl(origin, delegate, containingClass)
|
KtLightFieldImpl<PsiField>(origin, computeDelegate, containingClass, dummyDelegate)
|
||||||
|
|
||||||
companion object Factory {
|
companion object Factory {
|
||||||
fun create(origin: LightMemberOrigin?, delegate: PsiField, containingClass: KtLightClass): KtLightField {
|
fun create(origin: LightMemberOrigin?, delegate: PsiField, containingClass: KtLightClass): KtLightField {
|
||||||
when (delegate) {
|
when (delegate) {
|
||||||
is PsiEnumConstant -> {
|
is PsiEnumConstant -> {
|
||||||
val kotlinEnumEntry = (origin as? LightMemberOriginForDeclaration)?.originalElement as? KtEnumEntry
|
return KtLightEnumConstant(origin, { delegate }, containingClass, null)
|
||||||
val initializingClass = if (kotlinEnumEntry != null && kotlinEnumEntry.declarations.isNotEmpty()) {
|
|
||||||
KtLightClassForEnumEntry(kotlinEnumEntry, delegate)
|
|
||||||
}
|
|
||||||
else null
|
|
||||||
return KtLightEnumConstant(origin, delegate, containingClass, initializingClass)
|
|
||||||
}
|
}
|
||||||
else -> return KtLightFieldForDeclaration(origin, delegate, containingClass)
|
else -> return KtLightFieldForDeclaration(origin, { delegate }, containingClass, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun lazy(
|
||||||
|
dummyDelegate: PsiField,
|
||||||
|
origin: LightMemberOriginForDeclaration,
|
||||||
|
containingClass: KtLightClass,
|
||||||
|
computeRealDelegate: () -> PsiField
|
||||||
|
): KtLightField {
|
||||||
|
if (dummyDelegate is PsiEnumConstant) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return KtLightEnumConstant(origin, computeRealDelegate as () -> PsiEnumConstant, containingClass, dummyDelegate)
|
||||||
|
}
|
||||||
|
return KtLightFieldForDeclaration(origin, computeRealDelegate, containingClass, dummyDelegate)
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun fromClsField(field: PsiField, containingClass: KtLightClass): KtLightField {
|
fun fromClsField(field: PsiField, containingClass: KtLightClass): KtLightField {
|
||||||
val origin = ClsWrapperStubPsiFactory.getMemberOrigin(field)
|
val origin = ClsWrapperStubPsiFactory.getMemberOrigin(field)
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import com.intellij.navigation.ItemPresentation
|
|||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
|
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
|
||||||
import com.intellij.psi.impl.light.LightMethod
|
import com.intellij.psi.impl.light.LightElement
|
||||||
import com.intellij.psi.impl.light.LightModifierList
|
import com.intellij.psi.javadoc.PsiDocComment
|
||||||
import com.intellij.psi.scope.PsiScopeProcessor
|
import com.intellij.psi.scope.PsiScopeProcessor
|
||||||
import com.intellij.psi.util.*
|
import com.intellij.psi.util.*
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
@@ -35,22 +35,26 @@ import org.jetbrains.kotlin.asJava.propertyNameByAccessor
|
|||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
||||||
|
|
||||||
interface KtLightMethod : PsiMethod, KtLightDeclaration<KtDeclaration, PsiMethod> {
|
interface KtLightMethod : PsiAnnotationMethod, KtLightDeclaration<KtDeclaration, PsiMethod> {
|
||||||
val lightMethodOrigin: LightMemberOrigin?
|
val lightMethodOrigin: LightMemberOrigin?
|
||||||
val isDelegated: Boolean
|
val isDelegated: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class KtLightMethodImpl(
|
class KtLightMethodImpl private constructor(
|
||||||
override val clsDelegate: PsiMethod,
|
computeRealDelegate: () -> PsiMethod,
|
||||||
override val lightMethodOrigin: LightMemberOrigin?,
|
override val lightMethodOrigin: LightMemberOrigin?,
|
||||||
containingClass: KtLightClass
|
private val containingClass: KtLightClass,
|
||||||
) : LightMethod(clsDelegate.manager, clsDelegate, containingClass), KtLightMethod {
|
private val dummyDelegate: PsiMethod? = null
|
||||||
|
) : LightElement(containingClass.manager, containingClass.language), KtLightMethod {
|
||||||
override val kotlinOrigin: KtDeclaration? get() = lightMethodOrigin?.originalElement as? KtDeclaration
|
override val kotlinOrigin: KtDeclaration? get() = lightMethodOrigin?.originalElement as? KtDeclaration
|
||||||
|
|
||||||
|
override val clsDelegate by lazy(LazyThreadSafetyMode.PUBLICATION, computeRealDelegate)
|
||||||
|
|
||||||
private val lightIdentifier by lazy(LazyThreadSafetyMode.PUBLICATION) { KtLightIdentifier(this, kotlinOrigin as? KtNamedDeclaration) }
|
private val lightIdentifier by lazy(LazyThreadSafetyMode.PUBLICATION) { KtLightIdentifier(this, kotlinOrigin as? KtNamedDeclaration) }
|
||||||
private val returnTypeElem by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
private val returnTypeElem by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
val delegateTypeElement = clsDelegate.returnTypeElement as? ClsTypeElementImpl
|
val delegateTypeElement = clsDelegate.returnTypeElement as? ClsTypeElementImpl
|
||||||
@@ -59,7 +63,7 @@ sealed class KtLightMethodImpl(
|
|||||||
|
|
||||||
private val calculatingReturnType = ThreadLocal<Boolean>()
|
private val calculatingReturnType = ThreadLocal<Boolean>()
|
||||||
|
|
||||||
override fun getContainingClass(): KtLightClass = super.getContainingClass() as KtLightClass
|
override fun getContainingClass(): KtLightClass = containingClass
|
||||||
|
|
||||||
private val paramsList: CachedValue<PsiParameterList> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
private val paramsList: CachedValue<PsiParameterList> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
val cacheManager = CachedValuesManager.getManager(clsDelegate.project)
|
val cacheManager = CachedValuesManager.getManager(clsDelegate.project)
|
||||||
@@ -95,7 +99,7 @@ sealed class KtLightMethodImpl(
|
|||||||
|
|
||||||
override fun getNavigationElement(): PsiElement = kotlinOrigin?.navigationElement ?: super.getNavigationElement()
|
override fun getNavigationElement(): PsiElement = kotlinOrigin?.navigationElement ?: super.getNavigationElement()
|
||||||
override fun getPresentation(): ItemPresentation? = kotlinOrigin?.presentation ?: super.getPresentation()
|
override fun getPresentation(): ItemPresentation? = kotlinOrigin?.presentation ?: super.getPresentation()
|
||||||
override fun getParent(): PsiElement? = containingClass
|
override fun getParent(): PsiElement = containingClass
|
||||||
override fun getText() = kotlinOrigin?.text ?: ""
|
override fun getText() = kotlinOrigin?.text ?: ""
|
||||||
override fun getTextRange() = kotlinOrigin?.textRange ?: TextRange.EMPTY_RANGE
|
override fun getTextRange() = kotlinOrigin?.textRange ?: TextRange.EMPTY_RANGE
|
||||||
|
|
||||||
@@ -198,21 +202,11 @@ sealed class KtLightMethodImpl(
|
|||||||
containingClass == other.containingClass &&
|
containingClass == other.containingClass &&
|
||||||
clsDelegate == other.clsDelegate
|
clsDelegate == other.clsDelegate
|
||||||
|
|
||||||
override fun hashCode(): Int = ((name.hashCode() * 31 + (lightMethodOrigin?.hashCode() ?: 0)) * 31 + containingClass.hashCode()) * 31 + clsDelegate.hashCode()
|
override fun hashCode(): Int = ((getName().hashCode() * 31 + (lightMethodOrigin?.hashCode() ?: 0)) * 31 + containingClass.hashCode()) * 31 + clsDelegate.hashCode()
|
||||||
|
|
||||||
override fun toString(): String = "${this::class.java.simpleName}:$name"
|
override fun toString(): String = "${this::class.java.simpleName}:$name"
|
||||||
|
|
||||||
private class KtLightMethodForDeclaration(
|
override fun getDefaultValue() = (clsDelegate as? PsiAnnotationMethod)?.defaultValue
|
||||||
delegate: PsiMethod, origin: LightMemberOrigin?, containingClass: KtLightClass
|
|
||||||
) : KtLightMethodImpl(delegate, origin, containingClass)
|
|
||||||
|
|
||||||
class KtLightAnnotationMethod(
|
|
||||||
override val clsDelegate: PsiAnnotationMethod,
|
|
||||||
origin: LightMemberOrigin?,
|
|
||||||
containingClass: KtLightClass
|
|
||||||
) : KtLightMethodImpl(clsDelegate, origin, containingClass), PsiAnnotationMethod {
|
|
||||||
override fun getDefaultValue() = clsDelegate.defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// override getReturnType() so return type resolves to type parameters of this method not delegate's
|
// override getReturnType() so return type resolves to type parameters of this method not delegate's
|
||||||
// which is relied upon by java type inference
|
// which is relied upon by java type inference
|
||||||
@@ -229,27 +223,72 @@ sealed class KtLightMethodImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object Factory {
|
companion object Factory {
|
||||||
|
private fun adjustMethodOrigin(origin: LightMemberOriginForDeclaration?): LightMemberOriginForDeclaration? {
|
||||||
|
val originalElement = origin?.originalElement
|
||||||
|
if (originalElement is KtPropertyAccessor) {
|
||||||
|
return origin.copy(originalElement.getStrictParentOfType<KtProperty>()!!, origin.originKind)
|
||||||
|
}
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
delegate: PsiMethod, origin: LightMemberOrigin?, containingClass: KtLightClass
|
delegate: PsiMethod, origin: LightMemberOrigin?, containingClass: KtLightClass
|
||||||
): KtLightMethodImpl {
|
): KtLightMethodImpl {
|
||||||
return when (delegate) {
|
return KtLightMethodImpl({ delegate}, origin, containingClass)
|
||||||
is PsiAnnotationMethod -> KtLightAnnotationMethod(delegate, origin, containingClass)
|
|
||||||
else -> KtLightMethodForDeclaration(delegate, origin, containingClass)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun fromClsMethod(method: PsiMethod, containingClass: KtLightClass): KtLightMethodImpl {
|
fun fromClsMethod(method: PsiMethod, containingClass: KtLightClass): KtLightMethodImpl {
|
||||||
var origin = ClsWrapperStubPsiFactory.getMemberOrigin(method)
|
val origin = ClsWrapperStubPsiFactory.getMemberOrigin(method)
|
||||||
val originalElement = if (origin != null) origin.originalElement else null
|
return KtLightMethodImpl.create(method, adjustMethodOrigin(origin), containingClass)
|
||||||
if (originalElement is KtPropertyAccessor) {
|
}
|
||||||
|
|
||||||
origin = origin!!.copy(PsiTreeUtil.getParentOfType(originalElement, KtProperty::class.java)!!, origin.originKind)
|
@JvmStatic
|
||||||
}
|
fun lazy(
|
||||||
|
dummyDelegate: PsiMethod?,
|
||||||
return KtLightMethodImpl.create(method, origin, containingClass)
|
containingClass: KtLightClass,
|
||||||
|
origin: LightMemberOriginForDeclaration?,
|
||||||
|
computeRealDelegate: () -> PsiMethod
|
||||||
|
): KtLightMethodImpl {
|
||||||
|
return KtLightMethodImpl(computeRealDelegate, adjustMethodOrigin(origin), containingClass, dummyDelegate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getName() = dummyDelegate?.name ?: clsDelegate.name
|
||||||
|
|
||||||
|
override fun hasModifierProperty(name: String) = clsDelegate.hasModifierProperty(name)
|
||||||
|
|
||||||
|
override fun getThrowsList() = clsDelegate.throwsList
|
||||||
|
|
||||||
|
override fun hasTypeParameters() = clsDelegate.hasTypeParameters()
|
||||||
|
|
||||||
|
override fun isVarArgs() = clsDelegate.isVarArgs
|
||||||
|
|
||||||
|
override fun isConstructor() = clsDelegate.isConstructor
|
||||||
|
|
||||||
|
override fun getHierarchicalMethodSignature() = clsDelegate.hierarchicalMethodSignature
|
||||||
|
|
||||||
|
override fun getDocComment() = clsDelegate.docComment
|
||||||
|
|
||||||
|
override fun findSuperMethodSignaturesIncludingStatic(checkAccess: Boolean) = clsDelegate.findSuperMethodSignaturesIncludingStatic(checkAccess)
|
||||||
|
|
||||||
|
override fun getBody() = null
|
||||||
|
|
||||||
|
override fun isDeprecated() = clsDelegate.isDeprecated
|
||||||
|
|
||||||
|
override fun findDeepestSuperMethod() = clsDelegate.findDeepestSuperMethod()
|
||||||
|
|
||||||
|
override fun findDeepestSuperMethods() = clsDelegate.findDeepestSuperMethods()
|
||||||
|
|
||||||
|
override fun findSuperMethods() = clsDelegate.findSuperMethods()
|
||||||
|
|
||||||
|
override fun findSuperMethods(checkAccess: Boolean) = clsDelegate.findSuperMethods(checkAccess)
|
||||||
|
|
||||||
|
override fun findSuperMethods(parentClass: PsiClass?) = clsDelegate.findSuperMethods(parentClass)
|
||||||
|
|
||||||
|
override fun getContainingFile() = parent.containingFile
|
||||||
|
|
||||||
|
override fun isValid() = containingClass.isValid
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtLightMethod.isTraitFakeOverride(): Boolean {
|
fun KtLightMethod.isTraitFakeOverride(): Boolean {
|
||||||
|
|||||||
+24
-113
@@ -28,34 +28,27 @@ import com.intellij.psi.impl.compiled.ClsFileImpl
|
|||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||||
import org.jetbrains.kotlin.asJava.builder.*
|
import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory
|
||||||
|
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||||
import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage
|
import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.ClsJavaStubByVirtualFileCache
|
import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.*
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.KtLightClassForDecompiledDeclaration
|
|
||||||
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
|
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
|
||||||
import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
|
import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
|
||||||
import org.jetbrains.kotlin.idea.project.ResolveElementCache
|
|
||||||
import org.jetbrains.kotlin.idea.stubindex.*
|
import org.jetbrains.kotlin.idea.stubindex.*
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles
|
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException
|
import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.utils.sure
|
import org.jetbrains.kotlin.utils.sure
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -64,72 +57,36 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
|||||||
private val scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
|
private val scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
|
||||||
private val psiManager: PsiManager = PsiManager.getInstance(project)
|
private val psiManager: PsiManager = PsiManager.getInstance(project)
|
||||||
|
|
||||||
override fun createLightClassDataHolderForClassOrObject(classOrObject: KtClassOrObject, build: (LightClassConstructionContext) -> LightClassBuilderResult): LightClassDataHolder {
|
override fun createLightClassDataHolderForClassOrObject(
|
||||||
val (stub, bindingContext, diagnostics) = build(getContextForClassOrObject(classOrObject))
|
classOrObject: KtClassOrObject, builder: LightClassBuilder
|
||||||
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder
|
): LightClassDataHolder {
|
||||||
|
return if (classOrObject.isLocal) {
|
||||||
return LightClassDataHolderImpl(
|
LazyLightClassDataHolder(
|
||||||
stub,
|
builder,
|
||||||
diagnostics
|
exactContextProvider = { IDELightClassContexts.contextForLocalClassOrObject(classOrObject) },
|
||||||
)
|
dummyContextProvider = null
|
||||||
}
|
)
|
||||||
|
|
||||||
fun getContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
|
|
||||||
if (classOrObject.isLocal) {
|
|
||||||
return getContextForLocalClassOrObject(classOrObject)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return getContextForNonLocalClassOrObject(classOrObject)
|
LazyLightClassDataHolder(
|
||||||
|
builder,
|
||||||
|
exactContextProvider = { IDELightClassContexts.contextForNonLocalClassOrObject(classOrObject) },
|
||||||
|
dummyContextProvider = { IDELightClassContexts.lightContextForClassOrObject(classOrObject) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContextForNonLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
|
|
||||||
val resolutionFacade = classOrObject.getResolutionFacade()
|
|
||||||
val bindingContext = if (classOrObject is KtClass && classOrObject.isAnnotation()) {
|
|
||||||
// need to make sure default values for parameters are resolved
|
|
||||||
// because java resolve depends on whether there is a default value for an annotation attribute
|
|
||||||
resolutionFacade.getFrontendService(ResolveElementCache::class.java)
|
|
||||||
.resolvePrimaryConstructorParametersDefaultValues(classOrObject)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
resolutionFacade.analyze(classOrObject)
|
|
||||||
}
|
|
||||||
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject).sure {
|
|
||||||
"Class descriptor was not found for ${classOrObject.getElementTextWithContext()}"
|
|
||||||
}
|
|
||||||
ForceResolveUtil.forceResolveAllContents(classDescriptor)
|
|
||||||
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getContextForLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
|
override fun createLightClassDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder {
|
||||||
val resolutionFacade = classOrObject.getResolutionFacade()
|
|
||||||
val bindingContext = resolutionFacade.analyze(classOrObject)
|
|
||||||
|
|
||||||
val descriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
|
|
||||||
|
|
||||||
if (descriptor == null) {
|
|
||||||
LOG.warn("No class descriptor in context for class: " + classOrObject.getElementTextWithContext())
|
|
||||||
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
ForceResolveUtil.forceResolveAllContents<ClassDescriptor>(descriptor)
|
|
||||||
|
|
||||||
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createLightClassDataHolderForFacade(files: Collection<KtFile>, build: (LightClassConstructionContext) -> LightClassBuilderResult): LightClassDataHolder {
|
|
||||||
val (stub, _, diagnostics) = build(getContextForFacade(files))
|
|
||||||
return LightClassDataHolderImpl(stub, diagnostics)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getContextForFacade(files: Collection<KtFile>): LightClassConstructionContext {
|
|
||||||
assert(!files.isEmpty()) { "No files in facade" }
|
assert(!files.isEmpty()) { "No files in facade" }
|
||||||
|
|
||||||
val sortedFiles = files.sortedWith(scopeFileComparator)
|
val sortedFiles = files.sortedWith(scopeFileComparator)
|
||||||
val file = sortedFiles.first()
|
|
||||||
val resolveSession = file.getResolutionFacade().getFrontendService(ResolveSession::class.java)
|
return LazyLightClassDataHolder(
|
||||||
forceResolvePackageDeclarations(files, resolveSession)
|
builder,
|
||||||
return LightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor)
|
exactContextProvider = { IDELightClassContexts.contextForFacade(sortedFiles) },
|
||||||
|
dummyContextProvider = { IDELightClassContexts.lightContextForFacade(sortedFiles) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
||||||
@@ -267,48 +224,6 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forceResolvePackageDeclarations(files: Collection<KtFile>, session: ResolveSession) {
|
|
||||||
for (file in files) {
|
|
||||||
if (file.isScript) continue
|
|
||||||
|
|
||||||
val packageFqName = file.packageFqName
|
|
||||||
|
|
||||||
// make sure we create a package descriptor
|
|
||||||
val packageDescriptor = session.moduleDescriptor.getPackage(packageFqName)
|
|
||||||
if (packageDescriptor.isEmpty()) {
|
|
||||||
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.name + "\n" + file.text)
|
|
||||||
session.forceResolveAll()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for (declaration in file.declarations) {
|
|
||||||
if (declaration is KtFunction) {
|
|
||||||
val name = declaration.nameAsSafeName
|
|
||||||
val functions = packageDescriptor.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
|
|
||||||
for (descriptor in functions) {
|
|
||||||
ForceResolveUtil.forceResolveAllContents(descriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (declaration is KtProperty) {
|
|
||||||
val name = declaration.nameAsSafeName
|
|
||||||
val properties = packageDescriptor.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
|
|
||||||
for (descriptor in properties) {
|
|
||||||
ForceResolveUtil.forceResolveAllContents(descriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (declaration is KtClassOrObject || declaration is KtTypeAlias || declaration is KtDestructuringDeclaration) {
|
|
||||||
// Do nothing: we are not interested in classes or type aliases,
|
|
||||||
// and all destructuring declarations are erroneous at top level
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.name + "\n" + file.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ForceResolveUtil.forceResolveAllContents(session.getFileAnnotations(file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLightClassForDecompiledClassOrObject(decompiledClassOrObject: KtClassOrObject): KtLightClassForDecompiledDeclaration? {
|
private fun getLightClassForDecompiledClassOrObject(decompiledClassOrObject: KtClassOrObject): KtLightClassForDecompiledDeclaration? {
|
||||||
if (decompiledClassOrObject is KtEnumEntry) {
|
if (decompiledClassOrObject is KtEnumEntry) {
|
||||||
return null
|
return null
|
||||||
@@ -386,10 +301,6 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
|||||||
javaFileStub.psi = fakeFile
|
javaFileStub.psi = fakeFile
|
||||||
return fakeFile.classes.single() as ClsClassImpl
|
return fakeFile.classes.single() as ClsClassImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val LOG = Logger.getInstance(IDELightClassGenerationSupport::class.java)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerationSupport) : KtFileClassProvider {
|
class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerationSupport) : KtFileClassProvider {
|
||||||
|
|||||||
+324
@@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.idea.caches.resolve.lightClasses
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
|
||||||
|
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
||||||
|
import org.jetbrains.kotlin.config.JvmTarget
|
||||||
|
import org.jetbrains.kotlin.container.get
|
||||||
|
import org.jetbrains.kotlin.container.useImpl
|
||||||
|
import org.jetbrains.kotlin.container.useInstance
|
||||||
|
import org.jetbrains.kotlin.context.LazyResolveToken
|
||||||
|
import org.jetbrains.kotlin.context.ModuleContext
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.frontend.di.configureModule
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
|
||||||
|
import org.jetbrains.kotlin.idea.project.ResolveElementCache
|
||||||
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||||
|
import org.jetbrains.kotlin.resolve.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.WrappedTypeFactory
|
||||||
|
import org.jetbrains.kotlin.utils.sure
|
||||||
|
|
||||||
|
object IDELightClassContexts {
|
||||||
|
|
||||||
|
private val LOG = Logger.getInstance(this::class.java)
|
||||||
|
|
||||||
|
fun contextForNonLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
|
||||||
|
val resolutionFacade = classOrObject.getResolutionFacade()
|
||||||
|
val bindingContext = if (classOrObject is KtClass && classOrObject.isAnnotation()) {
|
||||||
|
// need to make sure default values for parameters are resolved
|
||||||
|
// because java resolve depends on whether there is a default value for an annotation attribute
|
||||||
|
resolutionFacade.getFrontendService(ResolveElementCache::class.java)
|
||||||
|
.resolvePrimaryConstructorParametersDefaultValues(classOrObject)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolutionFacade.analyze(classOrObject)
|
||||||
|
}
|
||||||
|
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject).sure {
|
||||||
|
"Class descriptor was not found for ${classOrObject.getElementTextWithContext()}"
|
||||||
|
}
|
||||||
|
ForceResolveUtil.forceResolveAllContents(classDescriptor)
|
||||||
|
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun contextForLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
|
||||||
|
val resolutionFacade = classOrObject.getResolutionFacade()
|
||||||
|
val bindingContext = resolutionFacade.analyze(classOrObject)
|
||||||
|
|
||||||
|
val descriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
|
||||||
|
|
||||||
|
if (descriptor == null) {
|
||||||
|
LOG.warn("No class descriptor in context for class: " + classOrObject.getElementTextWithContext())
|
||||||
|
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
ForceResolveUtil.forceResolveAllContents(descriptor)
|
||||||
|
|
||||||
|
return LightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun contextForFacade(files: List<KtFile>): LightClassConstructionContext {
|
||||||
|
val resolveSession = files.first().getResolutionFacade().getFrontendService(ResolveSession::class.java)
|
||||||
|
|
||||||
|
forceResolvePackageDeclarations(files, resolveSession)
|
||||||
|
|
||||||
|
return LightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
|
||||||
|
val resolveSession = setupAdHocResolve(classOrObject.project, classOrObject.getResolutionFacade().moduleDescriptor, listOf(classOrObject.containingKtFile))
|
||||||
|
|
||||||
|
ForceResolveUtil.forceResolveAllContents(resolveSession.resolveToDescriptor(classOrObject))
|
||||||
|
|
||||||
|
return LightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lightContextForFacade(files: List<KtFile>): LightClassConstructionContext {
|
||||||
|
val representativeFile = files.first()
|
||||||
|
val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files)
|
||||||
|
|
||||||
|
forceResolvePackageDeclarations(files, resolveSession)
|
||||||
|
|
||||||
|
return LightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forceResolvePackageDeclarations(files: Collection<KtFile>, session: ResolveSession) {
|
||||||
|
for (file in files) {
|
||||||
|
if (file.isScript) continue
|
||||||
|
|
||||||
|
val packageFqName = file.packageFqName
|
||||||
|
|
||||||
|
// make sure we create a package descriptor
|
||||||
|
val packageDescriptor = session.moduleDescriptor.getPackage(packageFqName)
|
||||||
|
if (packageDescriptor.isEmpty()) {
|
||||||
|
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.name + "\n" + file.text)
|
||||||
|
session.forceResolveAll()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (declaration in file.declarations) {
|
||||||
|
if (declaration is KtFunction) {
|
||||||
|
val name = declaration.nameAsSafeName
|
||||||
|
val functions = packageDescriptor.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
|
||||||
|
for (descriptor in functions) {
|
||||||
|
ForceResolveUtil.forceResolveAllContents(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (declaration is KtProperty) {
|
||||||
|
val name = declaration.nameAsSafeName
|
||||||
|
val properties = packageDescriptor.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
|
||||||
|
for (descriptor in properties) {
|
||||||
|
ForceResolveUtil.forceResolveAllContents(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (declaration is KtClassOrObject || declaration is KtTypeAlias || declaration is KtDestructuringDeclaration) {
|
||||||
|
// Do nothing: we are not interested in classes or type aliases,
|
||||||
|
// and all destructuring declarations are erroneous at top level
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.name + "\n" + file.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ForceResolveUtil.forceResolveAllContents(session.getFileAnnotations(file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun setupAdHocResolve(project: Project, realWorldModule: ModuleDescriptor, files: List<KtFile>): ResolveSession {
|
||||||
|
val trace = BindingTraceContext()
|
||||||
|
val sm = LockBasedStorageManager.NO_LOCKS
|
||||||
|
val moduleDescriptor = ModuleDescriptorImpl(realWorldModule.name, sm, realWorldModule.builtIns)
|
||||||
|
|
||||||
|
setupDependencies(moduleDescriptor, realWorldModule)
|
||||||
|
|
||||||
|
val moduleInfo = files.first().getModuleInfo()
|
||||||
|
val container = createContainer("LightClassStub", JvmPlatform) {
|
||||||
|
val jvmTarget = LanguageSettingsProvider.getInstance(project).getTargetPlatform(moduleInfo) as? JvmTarget
|
||||||
|
configureModule(
|
||||||
|
ModuleContext(moduleDescriptor, project), JvmPlatform,
|
||||||
|
jvmTarget ?: JvmTarget.DEFAULT, trace
|
||||||
|
)
|
||||||
|
|
||||||
|
useInstance(GlobalSearchScope.EMPTY_SCOPE)
|
||||||
|
useInstance(LookupTracker.DO_NOTHING)
|
||||||
|
useImpl<FileScopeProviderImpl>()
|
||||||
|
useInstance(LanguageSettingsProvider.getInstance(project).getLanguageVersionSettings(moduleInfo, project))
|
||||||
|
useInstance(FileBasedDeclarationProviderFactory(sm, files))
|
||||||
|
|
||||||
|
useImpl<AdHocAnnotationResolver>()
|
||||||
|
|
||||||
|
useInstance(object : WrappedTypeFactory(sm) {
|
||||||
|
override fun createLazyWrappedType(computation: () -> KotlinType): KotlinType = errorType()
|
||||||
|
|
||||||
|
override fun createDeferredType(trace: BindingTrace, computation: () -> KotlinType) = errorType()
|
||||||
|
|
||||||
|
override fun createRecursionIntolerantDeferredType(trace: BindingTrace, computation: () -> KotlinType) = errorType()
|
||||||
|
|
||||||
|
private fun errorType() = ErrorUtils.createErrorType("Error type in ad hoc resolve for lighter classes")
|
||||||
|
})
|
||||||
|
|
||||||
|
IdeaEnvironment.configure(this)
|
||||||
|
useImpl<LazyResolveToken>()
|
||||||
|
|
||||||
|
useImpl<ResolveSession>()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val resolveSession = container.get<ResolveSession>()
|
||||||
|
moduleDescriptor.initialize(CompositePackageFragmentProvider(listOf(resolveSession.packageFragmentProvider)))
|
||||||
|
return resolveSession
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupDependencies(moduleDescriptor: ModuleDescriptorImpl, realWorldModule: ModuleDescriptor) {
|
||||||
|
val jvmFieldClass = realWorldModule.getPackage(FqName("kotlin.jvm")).memberScope
|
||||||
|
.getContributedClassifier(Name.identifier("JvmField"), NoLookupLocation.FROM_IDE)
|
||||||
|
|
||||||
|
if (jvmFieldClass != null) {
|
||||||
|
moduleDescriptor.setDependencies(moduleDescriptor, jvmFieldClass.module as ModuleDescriptorImpl, moduleDescriptor.builtIns.builtInsModule)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
moduleDescriptor.setDependencies(moduleDescriptor, moduleDescriptor.builtIns.builtInsModule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JvmPlatformAnnotations.kt, JvmFlagAnnotations.kt, also PsiModifier.MODIFIERS
|
||||||
|
private val annotationsThatAffectCodegen = listOf(
|
||||||
|
"JvmField", "JvmOverloads", "JvmName", "JvmStatic",
|
||||||
|
"Synchronized", "Transient", "Volatile", "Strictfp"
|
||||||
|
).map { FqName("kotlin.jvm").child(Name.identifier(it)) }
|
||||||
|
|
||||||
|
class AdHocAnnotationResolver(
|
||||||
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
|
callResolver: CallResolver,
|
||||||
|
constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||||
|
storageManager: StorageManager
|
||||||
|
) : AnnotationResolverImpl(callResolver, constantExpressionEvaluator, storageManager) {
|
||||||
|
|
||||||
|
override fun resolveAnnotationEntries(scope: LexicalScope, annotationEntries: List<KtAnnotationEntry>, trace: BindingTrace, shouldResolveArguments: Boolean): Annotations {
|
||||||
|
return super.resolveAnnotationEntries(scope, annotationEntries, trace, shouldResolveArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resolveAnnotationType(scope: LexicalScope, entryElement: KtAnnotationEntry, trace: BindingTrace): KotlinType {
|
||||||
|
return annotationClassByEntry(entryElement)?.defaultType ?: super.resolveAnnotationType(scope, entryElement, trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun annotationClassByEntry(entryElement: KtAnnotationEntry): ClassDescriptor? {
|
||||||
|
val annotationTypeReferencePsi = (entryElement.typeReference?.typeElement as? KtUserType)?.referenceExpression ?: return null
|
||||||
|
val referencedName = annotationTypeReferencePsi.getReferencedName()
|
||||||
|
for (annotationFqName in annotationsThatAffectCodegen) {
|
||||||
|
if (referencedName == annotationFqName.shortName().asString()) {
|
||||||
|
moduleDescriptor.getPackage(annotationFqName.parent()).memberScope
|
||||||
|
.getContributedClassifier(annotationFqName.shortName(), NoLookupLocation.FROM_IDE)?.let { return it as? ClassDescriptor }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resolveAnnotationCall(annotationEntry: KtAnnotationEntry, scope: LexicalScope, trace: BindingTrace): OverloadResolutionResults<FunctionDescriptor> {
|
||||||
|
val annotationConstructor = annotationClassByEntry(annotationEntry)?.constructors?.singleOrNull()
|
||||||
|
?: return super.resolveAnnotationCall(annotationEntry, scope, trace)
|
||||||
|
val valueArgumentText = valueArgumentText(annotationEntry)
|
||||||
|
?: return super.resolveAnnotationCall(annotationEntry, scope, trace)
|
||||||
|
val fakeResolvedCall = object : ResolvedCall<FunctionDescriptor> {
|
||||||
|
override fun getStatus() = ResolutionStatus.SUCCESS
|
||||||
|
override fun getCandidateDescriptor() = annotationConstructor
|
||||||
|
override fun getResultingDescriptor() = annotationConstructor
|
||||||
|
override fun getValueArguments() =
|
||||||
|
annotationConstructor.valueParameters.singleOrNull()?.let { mapOf(it to FakeResolvedValueArgument(valueArgumentText)) }.orEmpty()
|
||||||
|
|
||||||
|
override fun getCall() = notImplemented
|
||||||
|
override fun getExtensionReceiver() = notImplemented
|
||||||
|
override fun getDispatchReceiver() = notImplemented
|
||||||
|
override fun getExplicitReceiverKind() = notImplemented
|
||||||
|
|
||||||
|
override fun getValueArgumentsByIndex() = notImplemented
|
||||||
|
override fun getArgumentMapping(valueArgument: ValueArgument) = notImplemented
|
||||||
|
override fun getTypeArguments() = notImplemented
|
||||||
|
override fun getDataFlowInfoForArguments() = notImplemented
|
||||||
|
override fun getSmartCastDispatchReceiverType() = notImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
return object : OverloadResolutionResults<FunctionDescriptor> {
|
||||||
|
override fun isSingleResult() = true
|
||||||
|
override fun getResultingCall(): ResolvedCall<FunctionDescriptor> = fakeResolvedCall
|
||||||
|
override fun getResultingDescriptor() = annotationConstructor
|
||||||
|
override fun getAllCandidates() = notImplemented
|
||||||
|
override fun getResultingCalls() = notImplemented
|
||||||
|
override fun getResultCode() = notImplemented
|
||||||
|
override fun isSuccess() = notImplemented
|
||||||
|
override fun isNothing() = notImplemented
|
||||||
|
override fun isAmbiguity() = notImplemented
|
||||||
|
override fun isIncomplete() = notImplemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun valueArgumentText(annotationEntry: KtAnnotationEntry) =
|
||||||
|
((annotationEntry.valueArguments.singleOrNull()?.getArgumentExpression() as? KtStringTemplateExpression)?.entries?.singleOrNull() as? KtLiteralStringTemplateEntry)?.text
|
||||||
|
|
||||||
|
override fun getAnnotationArgumentValue(trace: BindingTrace, valueParameter: ValueParameterDescriptor, resolvedArgument: ResolvedValueArgument): ConstantValue<*>? {
|
||||||
|
if (resolvedArgument is FakeResolvedValueArgument) return StringValue(resolvedArgument.argumentText, moduleDescriptor.builtIns)
|
||||||
|
|
||||||
|
return super.getAnnotationArgumentValue(trace, valueParameter, resolvedArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeResolvedValueArgument(val argumentText: String) : ResolvedValueArgument {
|
||||||
|
override fun getArguments() = notImplemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val notImplemented: Nothing
|
||||||
|
get() = error("Should not be called")
|
||||||
|
}
|
||||||
|
|
||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.idea.caches.resolve.lightClasses
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiClassType
|
||||||
|
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||||
|
import org.jetbrains.kotlin.asJava.builder.*
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl
|
||||||
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
|
||||||
|
typealias LightClassBuilder = (LightClassConstructionContext) -> LightClassBuilderResult
|
||||||
|
typealias LightClassContextProvider = () -> LightClassConstructionContext
|
||||||
|
|
||||||
|
class LazyLightClassDataHolder(
|
||||||
|
builder: LightClassBuilder,
|
||||||
|
exactContextProvider: LightClassContextProvider,
|
||||||
|
dummyContextProvider: LightClassContextProvider?
|
||||||
|
) : LightClassDataHolder {
|
||||||
|
|
||||||
|
private val exactResultLazyValue = lazy(LazyThreadSafetyMode.PUBLICATION) { builder(exactContextProvider()) }
|
||||||
|
|
||||||
|
private val exactResult: LightClassBuilderResult by exactResultLazyValue
|
||||||
|
|
||||||
|
private val lazyInexactResult by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
|
dummyContextProvider?.let { builder.invoke(it()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val inexactResult: LightClassBuilderResult?
|
||||||
|
get() = if (exactResultLazyValue.isInitialized()) null else lazyInexactResult
|
||||||
|
|
||||||
|
override val javaFileStub get() = exactResult.stub
|
||||||
|
override val extraDiagnostics get() = exactResult.diagnostics
|
||||||
|
|
||||||
|
// for facade or defaultImpls
|
||||||
|
override fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData =
|
||||||
|
LazyLightClassData(relyOnDummySupertypes = true) { lightClassBuilderResult ->
|
||||||
|
findDelegate(lightClassBuilderResult.stub)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
|
||||||
|
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
|
||||||
|
lightClassBuilderResult.stub.findDelegate(classOrObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class LazyLightClassData(
|
||||||
|
private val relyOnDummySupertypes: Boolean,
|
||||||
|
findDelegate: (LightClassBuilderResult) -> PsiClass
|
||||||
|
) : LightClassData {
|
||||||
|
override val clsDelegate: PsiClass by lazy(LazyThreadSafetyMode.PUBLICATION) { findDelegate(exactResult) }
|
||||||
|
|
||||||
|
private val dummyDelegate: PsiClass? by lazy(LazyThreadSafetyMode.PUBLICATION) { inexactResult?.let(findDelegate) }
|
||||||
|
|
||||||
|
override fun getOwnFields(containingClass: KtLightClass): List<KtLightField> {
|
||||||
|
if (dummyDelegate == null) return clsDelegate.fields.map { KtLightFieldImpl.fromClsField(it, containingClass) }
|
||||||
|
|
||||||
|
return dummyDelegate!!.fields.map { dummyField ->
|
||||||
|
val memberOrigin = ClsWrapperStubPsiFactory.getMemberOrigin(dummyField)!!
|
||||||
|
val fieldName = dummyField.name!!
|
||||||
|
KtLightFieldImpl.lazy(dummyField, memberOrigin, containingClass) {
|
||||||
|
clsDelegate.findFieldByName(fieldName, false)!!.apply {
|
||||||
|
assert(this.memberIndex!! == dummyField.memberIndex!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOwnMethods(containingClass: KtLightClass): List<KtLightMethod> {
|
||||||
|
if (dummyDelegate == null) return clsDelegate.methods.map { KtLightMethodImpl.fromClsMethod(it, containingClass) }
|
||||||
|
|
||||||
|
return dummyDelegate!!.methods.map { dummyMethod ->
|
||||||
|
val methodName = dummyMethod.name
|
||||||
|
KtLightMethodImpl.lazy(dummyMethod, containingClass, ClsWrapperStubPsiFactory.getMemberOrigin(dummyMethod)) {
|
||||||
|
val dummyIndex = dummyMethod.memberIndex!!
|
||||||
|
clsDelegate.findMethodsByName(methodName, false).filter {
|
||||||
|
delegateCandidate -> delegateCandidate.memberIndex == dummyIndex
|
||||||
|
}.single().apply {
|
||||||
|
assert(this.parameterList.parametersCount == dummyMethod.parameterList.parametersCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val supertypes: Array<PsiClassType>
|
||||||
|
get() = if (relyOnDummySupertypes && dummyDelegate != null) dummyDelegate!!.superTypes else clsDelegate.superTypes
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,10 @@ import com.intellij.psi.PsiCodeBlock
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner
|
import com.intellij.psi.PsiNameIdentifierOwner
|
||||||
import org.jetbrains.kotlin.asJava.elements.*
|
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.isGetter
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.isSetter
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
@@ -30,9 +33,15 @@ import org.jetbrains.uast.kotlin.*
|
|||||||
open class KotlinUMethod(
|
open class KotlinUMethod(
|
||||||
psi: KtLightMethod,
|
psi: KtLightMethod,
|
||||||
override val uastParent: UElement?
|
override val uastParent: UElement?
|
||||||
) : UMethod, JavaUElementWithComments, PsiMethod by psi {
|
) : UAnnotationMethod, JavaUElementWithComments, PsiMethod by psi {
|
||||||
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
|
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
|
||||||
|
|
||||||
|
override val uastDefaultValue by lz {
|
||||||
|
val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null
|
||||||
|
val defaultValue = annotationParameter.defaultValue ?: return@lz null
|
||||||
|
getLanguagePlugin().convertElement(defaultValue, this) as? UExpression
|
||||||
|
}
|
||||||
|
|
||||||
private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin
|
private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin
|
||||||
|
|
||||||
override val annotations by lz {
|
override val annotations by lz {
|
||||||
@@ -73,20 +82,6 @@ open class KotlinUMethod(
|
|||||||
override fun hashCode() = psi.hashCode()
|
override fun hashCode() = psi.hashCode()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun create(psi: KtLightMethod, containingElement: UElement?) = when (psi) {
|
fun create(psi: KtLightMethod, containingElement: UElement?) = KotlinUMethod(psi, containingElement)
|
||||||
is KtLightMethodImpl.KtLightAnnotationMethod -> KotlinUAnnotationMethod(psi, containingElement)
|
|
||||||
else -> KotlinUMethod(psi, containingElement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUAnnotationMethod(
|
|
||||||
override val psi: KtLightMethodImpl.KtLightAnnotationMethod,
|
|
||||||
containingElement: UElement?
|
|
||||||
) : KotlinUMethod(psi, containingElement), UAnnotationMethod {
|
|
||||||
override val uastDefaultValue by lz {
|
|
||||||
val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null
|
|
||||||
val defaultValue = annotationParameter.defaultValue ?: return@lz null
|
|
||||||
getLanguagePlugin().convertElement(defaultValue, this) as? UExpression
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -6,4 +6,4 @@ class Foo {
|
|||||||
val x = Foo::bar
|
val x = Foo::bar
|
||||||
|
|
||||||
// REF:Foo::bar
|
// REF:Foo::bar
|
||||||
// RESULT:KtLightAnnotationMethod:bar
|
// RESULT:KtLightMethodImpl:bar
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ UFile (package = ) [public abstract interface Callback {...]
|
|||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:UnsupportedOperationException
|
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:UnsupportedOperationException
|
||||||
UIdentifier (Identifier (UnsupportedOperationException)) [UIdentifier (Identifier (UnsupportedOperationException))]
|
UIdentifier (Identifier (UnsupportedOperationException)) [UIdentifier (Identifier (UnsupportedOperationException))]
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:UnsupportedOperationException
|
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:UnsupportedOperationException
|
||||||
UMethod (name = Model) [public fun Model() {...}]
|
UAnnotationMethod (name = Model) [public fun Model() {...}]
|
||||||
UBlockExpression [{...}]
|
UBlockExpression [{...}]
|
||||||
UBlockExpression [{...}] : PsiType:Unit
|
UBlockExpression [{...}] : PsiType:Unit
|
||||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 2)) [crashMe(Callback.java, { ...})] : PsiType:Unit
|
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 2)) [crashMe(Callback.java, { ...})] : PsiType:Unit
|
||||||
|
|||||||
Reference in New Issue
Block a user