181: Uast: KotlinUIdentifier introduced to store proper sourcePsi (KT-21688)
This commit is contained in:
committed by
Nikolay Krasko
parent
c3decbb62c
commit
9efa79f352
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* 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.uast.kotlin
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
|
||||
|
||||
abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUElement(givenParent), UClass, JvmDeclarationUElement {
|
||||
|
||||
override val uastDeclarations by lz {
|
||||
mutableListOf<UDeclaration>().apply {
|
||||
addAll(fields)
|
||||
addAll(initializers)
|
||||
addAll(methods)
|
||||
addAll(innerClasses)
|
||||
}
|
||||
}
|
||||
|
||||
override val uastSuperTypes: List<UTypeReferenceExpression>
|
||||
get() {
|
||||
val ktClass = (psi as? KtLightClass)?.kotlinOrigin ?: return emptyList()
|
||||
return ktClass.superTypeListEntries.mapNotNull { it.typeReference }.map {
|
||||
LazyKotlinUTypeReferenceExpression(it, this)
|
||||
}
|
||||
}
|
||||
|
||||
override val annotations: List<UAnnotation> by lz {
|
||||
(sourcePsi as? KtModifierListOwner)?.annotationEntries.orEmpty().map { KotlinUAnnotation(it, this) }
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = other is AbstractKotlinUClass && psi == other.psi
|
||||
override fun hashCode() = psi.hashCode()
|
||||
|
||||
}
|
||||
|
||||
open class KotlinUClass private constructor(
|
||||
psi: KtLightClass,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
|
||||
val ktClass = psi.kotlinOrigin
|
||||
|
||||
override val javaPsi: KtLightClass = psi
|
||||
|
||||
override val sourcePsi: KtClassOrObject? = ktClass
|
||||
|
||||
override val psi = unwrap<UClass, PsiClass>(psi)
|
||||
|
||||
override fun getSourceElement() = sourcePsi ?: this
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, ktClass)
|
||||
|
||||
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override val uastAnchor: UElement
|
||||
get() = KotlinUIdentifier(nameIdentifier, ktClass?.nameIdentifier, this)
|
||||
|
||||
override fun getInnerClasses(): Array<UClass> {
|
||||
// filter DefaultImpls to avoid processing same methods from original interface multiple times
|
||||
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
|
||||
return psi.innerClasses.filter {
|
||||
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass()
|
||||
}.mapNotNull {
|
||||
getLanguagePlugin().convertOpt<UClass>(it, this)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
override fun getSuperClass(): UClass? = super.getSuperClass()
|
||||
override fun getFields(): Array<UField> = super.getFields()
|
||||
override fun getInitializers(): Array<UClassInitializer> = super.getInitializers()
|
||||
|
||||
override fun getMethods(): Array<UMethod> {
|
||||
val hasPrimaryConstructor = ktClass?.hasPrimaryConstructor() ?: false
|
||||
var secondaryConstructorsCount = 0
|
||||
|
||||
fun createUMethod(psiMethod: PsiMethod): UMethod {
|
||||
return if (psiMethod is KtLightMethod &&
|
||||
psiMethod.isConstructor) {
|
||||
if (!hasPrimaryConstructor && secondaryConstructorsCount++ == 0)
|
||||
KotlinSecondaryConstructorWithInitializersUMethod(ktClass, psiMethod, this)
|
||||
else
|
||||
KotlinConstructorUMethod(ktClass, psiMethod, this)
|
||||
} else {
|
||||
getLanguagePlugin().convertOpt(psiMethod, this) ?: reportConvertFailure(psiMethod)
|
||||
}
|
||||
}
|
||||
|
||||
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
||||
|
||||
return psi.methods.asSequence()
|
||||
.filterNot(::isDelegatedMethod)
|
||||
.map(::createUMethod)
|
||||
.toList()
|
||||
.toTypedArray()
|
||||
}
|
||||
|
||||
private fun PsiClass.isEnumEntryLightClass() = (this as? KtLightClass)?.kotlinOrigin is KtEnumEntry
|
||||
|
||||
companion object {
|
||||
fun create(psi: KtLightClass, containingElement: UElement?): UClass = when (psi) {
|
||||
is PsiAnonymousClass -> KotlinUAnonymousClass(psi, containingElement)
|
||||
is KtLightClassForScript -> KotlinScriptUClass(psi, containingElement)
|
||||
else -> KotlinUClass(psi, containingElement)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class KotlinConstructorUMethod(
|
||||
private val ktClass: KtClassOrObject?,
|
||||
override val psi: KtLightMethod,
|
||||
givenParent: UElement?
|
||||
) : KotlinUMethod(psi, givenParent) {
|
||||
|
||||
val isPrimary: Boolean
|
||||
get() = psi.kotlinOrigin.let { it is KtPrimaryConstructor || it is KtClassOrObject }
|
||||
|
||||
override val uastBody: UExpression? by lz {
|
||||
val delegationCall: KtCallElement? = psi.kotlinOrigin.let {
|
||||
when {
|
||||
isPrimary -> ktClass?.superTypeListEntries?.firstIsInstanceOrNull<KtSuperTypeCallEntry>()
|
||||
it is KtSecondaryConstructor -> it.getDelegationCall()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
val bodyExpressions = getBodyExpressions()
|
||||
if (delegationCall == null && bodyExpressions.isEmpty()) return@lz null
|
||||
KotlinUBlockExpression.KotlinLazyUBlockExpression(this) { uastParent ->
|
||||
SmartList<UExpression>().apply {
|
||||
delegationCall?.let {
|
||||
add(KotlinUFunctionCallExpression(it, uastParent))
|
||||
}
|
||||
bodyExpressions.forEach {
|
||||
add(KotlinConverter.convertOrEmpty(it, uastParent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val javaPsi = psi
|
||||
|
||||
override val sourcePsi = psi.kotlinOrigin
|
||||
|
||||
open protected fun getBodyExpressions(): List<KtExpression> {
|
||||
if (isPrimary) return getInitializers()
|
||||
val bodyExpression = (psi.kotlinOrigin as? KtFunction)?.bodyExpression ?: return emptyList()
|
||||
if (bodyExpression is KtBlockExpression) return bodyExpression.statements
|
||||
return listOf(bodyExpression)
|
||||
}
|
||||
|
||||
protected fun getInitializers() = ktClass?.getAnonymousInitializers()?.mapNotNull { it.body } ?: emptyList()
|
||||
|
||||
}
|
||||
|
||||
// This class was created as a workaround for KT-21617 to be the only constructor which includes `init` block
|
||||
// when there is no primary constructors in the class.
|
||||
// It is expected to have only one constructor of this type in a UClass.
|
||||
class KotlinSecondaryConstructorWithInitializersUMethod(
|
||||
ktClass: KtClassOrObject?,
|
||||
psi: KtLightMethod,
|
||||
givenParent: UElement?
|
||||
) : KotlinConstructorUMethod(ktClass, psi, givenParent) {
|
||||
override fun getBodyExpressions(): List<KtExpression> = getInitializers() + super.getBodyExpressions()
|
||||
}
|
||||
|
||||
class KotlinUAnonymousClass(
|
||||
psi: PsiAnonymousClass,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), UAnonymousClass, PsiAnonymousClass by psi {
|
||||
|
||||
override val psi: PsiAnonymousClass = unwrap<UAnonymousClass, PsiAnonymousClass>(psi)
|
||||
|
||||
override val javaPsi: PsiAnonymousClass = psi
|
||||
|
||||
override val sourcePsi: KtClassOrObject? = (psi as? KtLightClass)?.kotlinOrigin
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUClass>.getOriginalElement()
|
||||
|
||||
override fun getSuperClass(): UClass? = super<AbstractKotlinUClass>.getSuperClass()
|
||||
override fun getFields(): Array<UField> = super<AbstractKotlinUClass>.getFields()
|
||||
override fun getMethods(): Array<UMethod> = super<AbstractKotlinUClass>.getMethods()
|
||||
override fun getInitializers(): Array<UClassInitializer> = super<AbstractKotlinUClass>.getInitializers()
|
||||
override fun getInnerClasses(): Array<UClass> = super<AbstractKotlinUClass>.getInnerClasses()
|
||||
|
||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override val uastAnchor: UElement?
|
||||
get() {
|
||||
val ktClassOrObject = (psi.originalElement as? KtLightClass)?.kotlinOrigin as? KtObjectDeclaration ?: return null
|
||||
return KotlinUIdentifier(ktClassOrObject.getObjectKeyword(), this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class KotlinScriptUClass(
|
||||
psi: KtLightClassForScript,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, psi.kotlinOrigin)
|
||||
|
||||
override val uastAnchor: UElement
|
||||
get() = KotlinUIdentifier(nameIdentifier, sourcePsi?.nameIdentifier, this)
|
||||
|
||||
override val javaPsi: PsiClass = psi
|
||||
|
||||
override val sourcePsi: KtClassOrObject? = psi.kotlinOrigin
|
||||
|
||||
override val psi = unwrap<UClass, KtLightClassForScript>(psi)
|
||||
|
||||
override fun getSuperClass(): UClass? = super.getSuperClass()
|
||||
|
||||
override fun getFields(): Array<UField> = super.getFields()
|
||||
|
||||
override fun getInitializers(): Array<UClassInitializer> = super.getInitializers()
|
||||
|
||||
override fun getInnerClasses(): Array<UClass> =
|
||||
psi.innerClasses.mapNotNull { getLanguagePlugin().convertOpt<UClass>(it, this) }.toTypedArray()
|
||||
|
||||
override fun getMethods(): Array<UMethod> = psi.methods.map(this::createUMethod).toTypedArray()
|
||||
|
||||
private fun createUMethod(method: PsiMethod): UMethod {
|
||||
return if (method.isConstructor) {
|
||||
KotlinScriptConstructorUMethod(psi.script, method as KtLightMethod, this)
|
||||
}
|
||||
else {
|
||||
getLanguagePlugin().convertOpt(method, this) ?: reportConvertFailure(method)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = psi.originalElement
|
||||
|
||||
class KotlinScriptConstructorUMethod(
|
||||
script: KtScript,
|
||||
override val psi: KtLightMethod,
|
||||
givenParent: UElement?
|
||||
) : KotlinUMethod(psi, givenParent) {
|
||||
override val uastBody: UExpression? by lz {
|
||||
val initializers = script.declarations.filterIsInstance<KtScriptInitializer>()
|
||||
KotlinUBlockExpression.create(initializers, this)
|
||||
}
|
||||
override val javaPsi = psi
|
||||
override val sourcePsi = psi.kotlinOrigin
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportConvertFailure(psiMethod: PsiMethod): Nothing {
|
||||
val isValid = psiMethod.isValid
|
||||
val report = KotlinExceptionWithAttachments(
|
||||
"cant convert $psiMethod of ${psiMethod.javaClass} to UMethod"
|
||||
+ if (!isValid) " (method is not valid)" else ""
|
||||
)
|
||||
|
||||
if (isValid) {
|
||||
report.withAttachment("method", psiMethod.text)
|
||||
psiMethod.containingFile?.let {
|
||||
report.withAttachment("file", it.text)
|
||||
}
|
||||
}
|
||||
|
||||
throw report
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.uast.kotlin.declarations
|
||||
|
||||
import com.intellij.psi.*
|
||||
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.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.java.internal.JavaUElementWithComments
|
||||
import org.jetbrains.uast.kotlin.*
|
||||
|
||||
open class KotlinUMethod(
|
||||
psi: KtLightMethod,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUElement(givenParent), UAnnotationMethod, JavaUElementWithComments, PsiMethod by psi {
|
||||
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
|
||||
|
||||
override val javaPsi = psi
|
||||
|
||||
override val sourcePsi = psi.kotlinOrigin
|
||||
|
||||
override fun getSourceElement() = sourcePsi ?: this
|
||||
|
||||
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
|
||||
|
||||
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
||||
|
||||
override val annotations by lz {
|
||||
psi.annotations
|
||||
.mapNotNull { (it as? KtLightElement<*, *>)?.kotlinOrigin as? KtAnnotationEntry }
|
||||
.map { KotlinUAnnotation(it, this) }
|
||||
}
|
||||
|
||||
private val receiver by lz { (sourcePsi as? KtCallableDeclaration)?.receiverTypeReference }
|
||||
|
||||
override val uastParameters by lz {
|
||||
val lightParams = psi.parameterList.parameters
|
||||
val receiver = receiver ?: return@lz lightParams.map {
|
||||
KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this)
|
||||
}
|
||||
val receiverLight = lightParams.firstOrNull() ?: return@lz emptyList<UParameter>()
|
||||
val uParameters = SmartList<UParameter>(KotlinReceiverUParameter(receiverLight, receiver, this))
|
||||
lightParams.drop(1).mapTo(uParameters) { KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) }
|
||||
uParameters
|
||||
}
|
||||
|
||||
override val uastAnchor: UElement
|
||||
get() = KotlinUIdentifier(
|
||||
nameIdentifier,
|
||||
(sourcePsi as? PsiNameIdentifierOwner)?.nameIdentifier ?: sourcePsi?.navigationElement,
|
||||
this
|
||||
)
|
||||
|
||||
|
||||
override val uastBody by lz {
|
||||
val bodyExpression = when (kotlinOrigin) {
|
||||
is KtFunction -> kotlinOrigin.bodyExpression
|
||||
is KtProperty -> when {
|
||||
psi.isGetter -> kotlinOrigin.getter?.bodyExpression
|
||||
psi.isSetter -> kotlinOrigin.setter?.bodyExpression
|
||||
else -> null
|
||||
}
|
||||
else -> null
|
||||
} ?: return@lz null
|
||||
|
||||
when (bodyExpression) {
|
||||
!is KtBlockExpression -> {
|
||||
KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block ->
|
||||
val implicitReturn = KotlinUImplicitReturnExpression(block)
|
||||
val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression
|
||||
?: return@KotlinLazyUBlockExpression emptyList()
|
||||
listOf(implicitReturn.apply { returnExpression = uBody })
|
||||
})
|
||||
|
||||
}
|
||||
else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression
|
||||
}
|
||||
}
|
||||
|
||||
override val isOverride: Boolean
|
||||
get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false
|
||||
|
||||
override fun getBody(): PsiCodeBlock? = super.getBody()
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
||||
|
||||
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
|
||||
|
||||
companion object {
|
||||
fun create(psi: KtLightMethod, containingElement: UElement?) =
|
||||
if (psi.kotlinOrigin is KtConstructor<*>) {
|
||||
KotlinConstructorUMethod(
|
||||
psi.kotlinOrigin?.containingClassOrObject,
|
||||
psi, containingElement
|
||||
)
|
||||
}
|
||||
else
|
||||
KotlinUMethod(psi, containingElement)
|
||||
}
|
||||
}
|
||||
+442
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* 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.uast.kotlin
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.internal.acceptList
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
|
||||
import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
||||
import org.jetbrains.uast.visitor.UastVisitor
|
||||
|
||||
abstract class AbstractKotlinUVariable(givenParent: UElement?)
|
||||
: KotlinAbstractUElement(givenParent), PsiVariable, UVariable, KotlinUElementWithComments {
|
||||
|
||||
override val uastInitializer: UExpression?
|
||||
get() {
|
||||
val psi = psi
|
||||
val initializerExpression = when (psi) {
|
||||
is UastKotlinPsiVariable -> psi.ktInitializer
|
||||
is UastKotlinPsiParameter -> psi.ktDefaultValue
|
||||
is KtLightElement<*, *> -> {
|
||||
val origin = psi.kotlinOrigin
|
||||
when (origin) {
|
||||
is KtVariableDeclaration -> origin.initializer
|
||||
is KtParameter -> origin.defaultValue
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
} ?: return null
|
||||
return getLanguagePlugin().convertElement(initializerExpression, this) as? UExpression ?: UastEmptyExpression
|
||||
}
|
||||
|
||||
val delegateExpression: UExpression? by lz {
|
||||
val psi = psi
|
||||
val expression = when (psi) {
|
||||
is KtLightElement<*, *> -> (psi.kotlinOrigin as? KtProperty)?.delegateExpression
|
||||
is UastKotlinPsiVariable -> (psi.ktElement as? KtProperty)?.delegateExpression
|
||||
else -> null
|
||||
}
|
||||
|
||||
expression?.let { getLanguagePlugin().convertElement(it, this) as? UExpression }
|
||||
}
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier {
|
||||
val kotlinOrigin = (psi as? KtLightElement<*, *>)?.kotlinOrigin
|
||||
return UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
||||
}
|
||||
|
||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override val annotations by lz {
|
||||
val sourcePsi = sourcePsi ?: return@lz psi.annotations.map { WrappedUAnnotation(it, this) }
|
||||
val annotations = SmartList<UAnnotation>(KotlinNullabilityUAnnotation(sourcePsi, this))
|
||||
if (sourcePsi is KtModifierListOwner) {
|
||||
sourcePsi.annotationEntries.
|
||||
filter { acceptsAnnotationTarget(it.useSiteTarget?.getAnnotationUseSiteTarget()) }.
|
||||
mapTo(annotations) { KotlinUAnnotation(it, this) }
|
||||
}
|
||||
annotations
|
||||
}
|
||||
|
||||
|
||||
abstract protected fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean
|
||||
|
||||
override val typeReference by lz { getLanguagePlugin().convertOpt<UTypeReferenceExpression>(psi.typeElement, this) }
|
||||
|
||||
override val uastAnchor: UElement?
|
||||
get() = KotlinUIdentifier(nameIdentifier, sourcePsi, this)
|
||||
|
||||
override fun equals(other: Any?) = other is AbstractKotlinUVariable && psi == other.psi
|
||||
|
||||
class WrappedUAnnotation(psiAnnotation: PsiAnnotation, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElement {
|
||||
|
||||
override val javaPsi: PsiAnnotation = psiAnnotation
|
||||
override val psi: PsiAnnotation = javaPsi
|
||||
override val sourcePsi: PsiElement? = null
|
||||
|
||||
override val attributeValues: List<UNamedExpression> by lz {
|
||||
psi.parameterList.attributes.map { WrappedUNamedExpression(it, this) }
|
||||
}
|
||||
|
||||
class WrappedUNamedExpression(pair: PsiNameValuePair, override val uastParent: UElement?) : UNamedExpression, JvmDeclarationUElement {
|
||||
override val name: String? = pair.name
|
||||
override val psi = pair
|
||||
override val javaPsi: PsiElement? = psi
|
||||
override val sourcePsi: PsiElement? = null
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val expression: UExpression by lz { toUExpression(psi.value) }
|
||||
}
|
||||
|
||||
override val qualifiedName: String? = psi.qualifiedName
|
||||
override fun findAttributeValue(name: String?): UExpression? = psi.findAttributeValue(name)?.let { toUExpression(it) }
|
||||
override fun findDeclaredAttributeValue(name: String?): UExpression? = psi.findDeclaredAttributeValue(name)?.let { toUExpression(it) }
|
||||
override fun resolve(): PsiClass? = psi.nameReferenceElement?.resolve() as? PsiClass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun toUExpression(psi: PsiElement?): UExpression = psi.toUElementOfType<UExpression>() ?: UastEmptyExpression
|
||||
|
||||
class KotlinUVariable(
|
||||
psi: PsiVariable,
|
||||
override val sourcePsi: KtElement,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUVariable(givenParent), UVariable, PsiVariable by psi {
|
||||
|
||||
override val javaPsi = unwrap<UVariable, PsiVariable>(psi)
|
||||
|
||||
override val psi = javaPsi
|
||||
|
||||
override val typeReference by lz { getLanguagePlugin().convertOpt<UTypeReferenceExpression>(psi.typeElement, this) }
|
||||
|
||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true
|
||||
|
||||
override fun getInitializer(): PsiExpression? {
|
||||
return super<AbstractKotlinUVariable>.getInitializer()
|
||||
}
|
||||
|
||||
override fun getOriginalElement(): PsiElement? {
|
||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
||||
}
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier {
|
||||
return super.getNameIdentifier()
|
||||
}
|
||||
|
||||
override fun getContainingFile(): PsiFile {
|
||||
return super.getContainingFile()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class KotlinUParameter(
|
||||
psi: PsiParameter,
|
||||
final override val sourcePsi: KtElement?,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUVariable(givenParent), UParameter, PsiParameter by psi {
|
||||
|
||||
final override val javaPsi = unwrap<UParameter, PsiParameter>(psi)
|
||||
|
||||
override val psi = javaPsi
|
||||
|
||||
private val isLightConstructorParam by lz { psi.getParentOfType<PsiMethod>(true)?.isConstructor }
|
||||
|
||||
private val isKtConstructorParam by lz { sourcePsi?.getParentOfType<KtCallableDeclaration>(true)?.let { it is KtConstructor<*> } }
|
||||
|
||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean {
|
||||
if (sourcePsi !is KtParameter) return false
|
||||
if (isKtConstructorParam == isLightConstructorParam && target == null) return true
|
||||
when (target) {
|
||||
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> return isLightConstructorParam == true
|
||||
AnnotationUseSiteTarget.SETTER_PARAMETER -> return isLightConstructorParam != true
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInitializer(): PsiExpression? {
|
||||
return super<AbstractKotlinUVariable>.getInitializer()
|
||||
}
|
||||
|
||||
override fun getOriginalElement(): PsiElement? {
|
||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
||||
}
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier {
|
||||
return super.getNameIdentifier()
|
||||
}
|
||||
|
||||
override fun getContainingFile(): PsiFile {
|
||||
return super.getContainingFile()
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinReceiverUParameter(
|
||||
psi: PsiParameter,
|
||||
private val receiver: KtTypeReference,
|
||||
givenParent: UElement?
|
||||
) : KotlinUParameter(psi, receiver, givenParent) {
|
||||
|
||||
override val annotations: List<UAnnotation> by lz {
|
||||
receiver.annotationEntries
|
||||
.filter { it.useSiteTarget?.getAnnotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER }
|
||||
.map { KotlinUAnnotation(it, this) } +
|
||||
super.annotations
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class KotlinNullabilityUAnnotation(val annotatedElement: PsiElement, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElement {
|
||||
|
||||
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
|
||||
if (annotatedElement is KtTypeReference) {
|
||||
annotatedElement.getType()?.let { return it }
|
||||
}
|
||||
if (annotatedElement is KtCallableDeclaration) {
|
||||
annotatedElement.typeReference?.getType()?.let { return it }
|
||||
}
|
||||
if (annotatedElement is KtProperty) {
|
||||
annotatedElement.initializer?.let { it.getType(it.analyze()) }?.let { return it }
|
||||
annotatedElement.delegateExpression?.let { it.getType(it.analyze())?.arguments?.firstOrNull()?.type }?.let { return it }
|
||||
}
|
||||
annotatedElement.getParentOfType<KtProperty>(false)?.let {
|
||||
it.typeReference?.getType() ?: it.initializer?.let { it.getType(it.analyze()) }
|
||||
}?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
val nullability by lz { getTargetType(annotatedElement)?.nullability() }
|
||||
|
||||
override val attributeValues: List<UNamedExpression>
|
||||
get() = emptyList()
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
override val javaPsi: PsiAnnotation?
|
||||
get() = null
|
||||
override val sourcePsi: PsiElement?
|
||||
get() = null
|
||||
override val qualifiedName: String?
|
||||
get() = when (nullability) {
|
||||
TypeNullability.NOT_NULL -> NotNull::class.qualifiedName
|
||||
TypeNullability.NULLABLE -> Nullable::class.qualifiedName
|
||||
TypeNullability.FLEXIBLE -> null
|
||||
null -> null
|
||||
}
|
||||
|
||||
override fun findAttributeValue(name: String?): UExpression? = null
|
||||
|
||||
override fun findDeclaredAttributeValue(name: String?): UExpression? = null
|
||||
|
||||
override fun resolve(): PsiClass? = qualifiedName?.let {
|
||||
val project = annotatedElement.project
|
||||
JavaPsiFacade.getInstance(project).findClass(it, GlobalSearchScope.allScope(project))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class KotlinUField(
|
||||
psi: PsiField,
|
||||
override val sourcePsi: KtElement?,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUVariable(givenParent), UField, PsiField by psi {
|
||||
override fun getSourceElement() = sourcePsi ?: this
|
||||
|
||||
override val javaPsi = unwrap<UField, PsiField>(psi)
|
||||
|
||||
override val psi = javaPsi
|
||||
|
||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean =
|
||||
target == AnnotationUseSiteTarget.FIELD ||
|
||||
target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD ||
|
||||
(sourcePsi is KtProperty) && (target == null || target == AnnotationUseSiteTarget.PROPERTY)
|
||||
|
||||
override fun getInitializer(): PsiExpression? {
|
||||
return super<AbstractKotlinUVariable>.getInitializer()
|
||||
}
|
||||
|
||||
override fun getOriginalElement(): PsiElement? {
|
||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
||||
}
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier {
|
||||
return super.getNameIdentifier()
|
||||
}
|
||||
|
||||
override fun getContainingFile(): PsiFile {
|
||||
return super.getContainingFile()
|
||||
}
|
||||
|
||||
override fun isPhysical(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun accept(visitor: UastVisitor) {
|
||||
if (visitor.visitField(this)) return
|
||||
annotations.acceptList(visitor)
|
||||
uastInitializer?.accept(visitor)
|
||||
delegateExpression?.accept(visitor)
|
||||
visitor.afterVisitField(this)
|
||||
}
|
||||
}
|
||||
|
||||
open class KotlinULocalVariable(
|
||||
psi: PsiLocalVariable,
|
||||
override val sourcePsi: KtElement,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUVariable(givenParent), ULocalVariable, PsiLocalVariable by psi {
|
||||
|
||||
override val javaPsi = unwrap<ULocalVariable, PsiLocalVariable>(psi)
|
||||
|
||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true
|
||||
|
||||
override val psi = javaPsi
|
||||
|
||||
override fun getInitializer(): PsiExpression? {
|
||||
return super<AbstractKotlinUVariable>.getInitializer()
|
||||
}
|
||||
|
||||
override fun getOriginalElement(): PsiElement? {
|
||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
||||
}
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier {
|
||||
return super.getNameIdentifier()
|
||||
}
|
||||
|
||||
override fun getContainingFile(): PsiFile {
|
||||
return super.getContainingFile()
|
||||
}
|
||||
|
||||
override fun accept(visitor: UastVisitor) {
|
||||
if (visitor.visitLocalVariable(this)) return
|
||||
annotations.acceptList(visitor)
|
||||
uastInitializer?.accept(visitor)
|
||||
delegateExpression?.accept(visitor)
|
||||
visitor.afterVisitLocalVariable(this)
|
||||
}
|
||||
}
|
||||
|
||||
open class KotlinUAnnotatedLocalVariable(
|
||||
psi: PsiLocalVariable,
|
||||
sourcePsi: KtElement,
|
||||
uastParent: UElement?,
|
||||
computeAnnotations: (parent: UElement) -> List<UAnnotation>
|
||||
) : KotlinULocalVariable(psi, sourcePsi, uastParent) {
|
||||
|
||||
override val annotations: List<UAnnotation> by lz { computeAnnotations(this) }
|
||||
}
|
||||
|
||||
class KotlinUEnumConstant(
|
||||
psi: PsiEnumConstant,
|
||||
override val sourcePsi: KtElement?,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUVariable(givenParent), UEnumConstant, PsiEnumConstant by psi {
|
||||
|
||||
override val initializingClass: UClass? by lz {
|
||||
(psi.initializingClass as? KtLightClass)?.let { initializingClass ->
|
||||
KotlinUClass.create(initializingClass, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInitializer(): PsiExpression? = super<AbstractKotlinUVariable>.getInitializer()
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUVariable>.getOriginalElement()
|
||||
|
||||
override val javaPsi = unwrap<UEnumConstant, PsiEnumConstant>(psi)
|
||||
|
||||
override val psi = javaPsi
|
||||
|
||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true
|
||||
|
||||
override fun getContainingFile(): PsiFile {
|
||||
return super.getContainingFile()
|
||||
}
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier {
|
||||
return super.getNameIdentifier()
|
||||
}
|
||||
|
||||
override val kind: UastCallKind
|
||||
get() = UastCallKind.CONSTRUCTOR_CALL
|
||||
|
||||
override val receiver: UExpression?
|
||||
get() = null
|
||||
|
||||
override val receiverType: PsiType?
|
||||
get() = null
|
||||
|
||||
override val methodIdentifier: UIdentifier?
|
||||
get() = null
|
||||
|
||||
override val classReference: UReferenceExpression?
|
||||
get() = KotlinEnumConstantClassReference(psi, sourcePsi, this)
|
||||
|
||||
override val typeArgumentCount: Int
|
||||
get() = 0
|
||||
|
||||
override val typeArguments: List<PsiType>
|
||||
get() = emptyList()
|
||||
|
||||
override val valueArgumentCount: Int
|
||||
get() = psi.argumentList?.expressions?.size ?: 0
|
||||
|
||||
override val valueArguments by lz {
|
||||
psi.argumentList?.expressions?.map {
|
||||
getLanguagePlugin().convertElement(it, this) as? UExpression ?: UastEmptyExpression
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
override val returnType: PsiType?
|
||||
get() = psi.type
|
||||
|
||||
override fun resolve() = psi.resolveMethod()
|
||||
|
||||
override val methodName: String?
|
||||
get() = null
|
||||
|
||||
private class KotlinEnumConstantClassReference(
|
||||
override val psi: PsiEnumConstant,
|
||||
override val sourcePsi: KtElement?,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression {
|
||||
override val javaPsi: PsiElement?
|
||||
get() = psi
|
||||
|
||||
override fun resolve() = psi.containingClass
|
||||
override val resolvedName: String?
|
||||
get() = psi.containingClass?.name
|
||||
override val identifier: String
|
||||
get() = psi.containingClass?.name ?: "<error>"
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.uast.kotlin.declarations
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiIdentifier
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UIdentifier
|
||||
import org.jetbrains.uast.kotlin.unwrapFakeFileForLightClass
|
||||
|
||||
class UastLightIdentifier(lightOwner: PsiNameIdentifierOwner, ktDeclaration: KtNamedDeclaration?) :
|
||||
KtLightIdentifier(lightOwner, ktDeclaration) {
|
||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(super.getContainingFile())
|
||||
}
|
||||
|
||||
class KotlinUIdentifier private constructor(
|
||||
override val javaPsi: PsiIdentifier?,
|
||||
override val sourcePsi: PsiElement?,
|
||||
override val psi: PsiElement?,
|
||||
override val uastParent: UElement?
|
||||
) : UIdentifier(psi, uastParent) {
|
||||
|
||||
init {
|
||||
assert(sourcePsi == null || sourcePsi is LeafPsiElement || sourcePsi is KtElement, { "sourcePsi should be physical" })
|
||||
}
|
||||
|
||||
constructor(javaPsi: PsiIdentifier?, sourcePsi: PsiElement?, uastParent: UElement?) : this(javaPsi, sourcePsi, javaPsi, uastParent)
|
||||
constructor(sourcePsi: PsiElement?, uastParent: UElement?) : this(null, sourcePsi, sourcePsi, uastParent)
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
import org.jetbrains.uast.JvmDeclarationUElement
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UFile
|
||||
import org.jetbrains.uast.kotlin.KOTLIN_CACHED_UELEMENT_KEY
|
||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
||||
import org.jetbrains.uast.test.common.RenderLogTestBase
|
||||
import org.jetbrains.uast.visitor.UastVisitor
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLogTestBase {
|
||||
override fun getTestFile(testName: String, ext: String) =
|
||||
File(File(TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext)
|
||||
|
||||
override fun check(testName: String, file: UFile) {
|
||||
check(testName, file, true)
|
||||
}
|
||||
|
||||
fun check(testName: String, file: UFile, checkParentConsistency: Boolean) {
|
||||
super.check(testName, file)
|
||||
|
||||
if (checkParentConsistency) {
|
||||
checkParentConsistency(file)
|
||||
}
|
||||
|
||||
file.checkContainingFileForAllElements()
|
||||
file.checkJvmDeclarationsImplementations()
|
||||
}
|
||||
|
||||
private fun checkParentConsistency(file: UFile) {
|
||||
val parentMap = mutableMapOf<PsiElement, String>()
|
||||
|
||||
file.accept(object : UastVisitor {
|
||||
private val parentStack = Stack<UElement>()
|
||||
|
||||
override fun visitElement(node: UElement): Boolean {
|
||||
val parent = node.uastParent
|
||||
if (parent == null) {
|
||||
Assert.assertTrue("Wrong parent of $node", parentStack.empty())
|
||||
}
|
||||
else {
|
||||
Assert.assertEquals("Wrong parent of $node", parentStack.peek(), parent)
|
||||
}
|
||||
node.psi?.let {
|
||||
if (it !in parentMap) {
|
||||
parentMap[it] = parentStack.reversed().joinToString { it.asLogString() }
|
||||
}
|
||||
}
|
||||
parentStack.push(node)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun afterVisitElement(node: UElement) {
|
||||
super.afterVisitElement(node)
|
||||
parentStack.pop()
|
||||
}
|
||||
})
|
||||
|
||||
file.psi.clearUastCaches()
|
||||
|
||||
file.psi.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val uElement = KotlinUastLanguagePlugin().convertElementWithParent(element, null)
|
||||
val expectedParents = parentMap[element]
|
||||
if (expectedParents != null) {
|
||||
assertNotNull("Expected to be able to convert PSI element $element", uElement)
|
||||
val parents = generateSequence(uElement!!.uastParent) { it.uastParent }.joinToString { it.asLogString() }
|
||||
assertEquals("Inconsistent parents for ${uElement.asRenderString()}(${uElement.asLogString()})(${uElement.javaClass}) (converted from $element[${element.text}])", expectedParents, parents)
|
||||
}
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun UFile.checkContainingFileForAllElements() {
|
||||
accept(object : UastVisitor {
|
||||
override fun visitElement(node: UElement): Boolean {
|
||||
if (node is PsiElement) {
|
||||
node.containingFile.assertedCast<KtFile> { "containingFile should be KtFile for ${node.asLogString()}" }
|
||||
}
|
||||
|
||||
val anchorPsi = (node as? UDeclaration)?.uastAnchor?.psi
|
||||
if (anchorPsi != null) {
|
||||
anchorPsi.containingFile.assertedCast<KtFile> { "uastAnchor.containingFile should be KtFile for ${node.asLogString()}" }
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun UFile.checkJvmDeclarationsImplementations() {
|
||||
accept(object : UastVisitor {
|
||||
override fun visitElement(node: UElement): Boolean {
|
||||
|
||||
if (node is UDeclaration) {// visitDeclaration hasn't come yet
|
||||
node.uastAnchor?.let { visitElement(it) }
|
||||
}
|
||||
|
||||
val jvmDeclaration = node as? JvmDeclarationUElement
|
||||
?: throw AssertionError("${node.javaClass} should implement 'JvmDeclarationUElement'")
|
||||
|
||||
jvmDeclaration.sourcePsi?.let {
|
||||
assertTrue("sourcePsi should be physical but ${it.javaClass} found for [${it.text}] " +
|
||||
"for ${jvmDeclaration.javaClass}->${jvmDeclaration.uastParent?.javaClass}",it is LeafPsiElement || it is KtElement|| it is LeafPsiElement)
|
||||
}
|
||||
jvmDeclaration.javaPsi?.let {
|
||||
assertTrue("javaPsi should be light but ${it.javaClass} found for [${it.text}] " +
|
||||
"for ${jvmDeclaration.javaClass}->${jvmDeclaration.uastParent?.javaClass}", it !is KtElement)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiFile.clearUastCaches() {
|
||||
accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
super.visitElement(element)
|
||||
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, null)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user