Cleanup 201 and as41 bunch files
This commit is contained in:
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.android.parcel.isParcelize
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class ParcelableClinitClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||
override fun interceptClassBuilderFactory(
|
||||
interceptedFactory: ClassBuilderFactory,
|
||||
bindingContext: BindingContext,
|
||||
diagnostics: DiagnosticSink
|
||||
): ClassBuilderFactory {
|
||||
return ParcelableClinitClassBuilderFactory(interceptedFactory, bindingContext)
|
||||
}
|
||||
|
||||
private inner class ParcelableClinitClassBuilderFactory(
|
||||
private val delegateFactory: ClassBuilderFactory,
|
||||
val bindingContext: BindingContext
|
||||
) : ClassBuilderFactory {
|
||||
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder {
|
||||
return AndroidOnDestroyCollectorClassBuilder(origin, delegateFactory.newClassBuilder(origin), bindingContext)
|
||||
}
|
||||
|
||||
override fun getClassBuilderMode() = delegateFactory.classBuilderMode
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegateFactory.asText((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegateFactory.asBytes((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
delegateFactory.close()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AndroidOnDestroyCollectorClassBuilder(
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
internal val delegateClassBuilder: ClassBuilder,
|
||||
val bindingContext: BindingContext
|
||||
) : DelegatingClassBuilder() {
|
||||
private var currentClass: KtClassOrObject? = null
|
||||
private var currentClassName: String? = null
|
||||
private var isClinitGenerated = false
|
||||
|
||||
override fun getDelegate() = delegateClassBuilder
|
||||
|
||||
override fun defineClass(
|
||||
origin: PsiElement?,
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String,
|
||||
interfaces: Array<out String>
|
||||
) {
|
||||
if (origin is KtClassOrObject) {
|
||||
currentClass = origin
|
||||
} else {
|
||||
currentClass = null
|
||||
}
|
||||
|
||||
currentClassName = name
|
||||
isClinitGenerated = false
|
||||
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
override fun done() {
|
||||
if (!isClinitGenerated && currentClass != null && currentClassName != null) {
|
||||
val descriptor = bindingContext[BindingContext.CLASS, currentClass]
|
||||
if (descriptor != null && declarationOrigin.descriptor == descriptor && descriptor.isParcelize) {
|
||||
val baseVisitor = super.newMethod(JvmDeclarationOrigin.NO_ORIGIN, ACC_STATIC, "<clinit>", "()V", null, null)
|
||||
val visitor = ClinitAwareMethodVisitor(currentClassName!!, baseVisitor)
|
||||
|
||||
visitor.visitCode()
|
||||
visitor.visitInsn(Opcodes.RETURN)
|
||||
visitor.visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
super.done()
|
||||
}
|
||||
|
||||
override fun newMethod(
|
||||
origin: JvmDeclarationOrigin,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
if (name == "<clinit>" && currentClass != null && currentClassName != null) {
|
||||
isClinitGenerated = true
|
||||
|
||||
val descriptor = bindingContext[BindingContext.CLASS, currentClass]
|
||||
if (descriptor != null && declarationOrigin.descriptor == descriptor && descriptor.isParcelize) {
|
||||
return ClinitAwareMethodVisitor(
|
||||
currentClassName!!,
|
||||
super.newMethod(origin, access, name, desc, signature, exceptions))
|
||||
}
|
||||
}
|
||||
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
}
|
||||
|
||||
private class ClinitAwareMethodVisitor(val parcelableName: String, mv: MethodVisitor) : MethodVisitor(Opcodes.API_VERSION, mv) {
|
||||
override fun visitInsn(opcode: Int) {
|
||||
if (opcode == Opcodes.RETURN) {
|
||||
val iv = InstructionAdapter(this)
|
||||
val creatorName = "$parcelableName\$Creator"
|
||||
val creatorType = Type.getObjectType(creatorName)
|
||||
|
||||
iv.anew(creatorType)
|
||||
iv.dup()
|
||||
iv.invokespecial(creatorName, "<init>", "()V", false)
|
||||
iv.putstatic(parcelableName, "CREATOR", "Landroid/os/Parcelable\$Creator;")
|
||||
}
|
||||
|
||||
super.visitInsn(opcode)
|
||||
}
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import kotlinx.android.extensions.CacheImplementation
|
||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.CLEAR_CACHE_METHOD_NAME
|
||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.ON_DESTROY_METHOD_NAME
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
abstract class AbstractAndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||
override fun interceptClassBuilderFactory(
|
||||
interceptedFactory: ClassBuilderFactory,
|
||||
bindingContext: BindingContext,
|
||||
diagnostics: DiagnosticSink
|
||||
): ClassBuilderFactory {
|
||||
return AndroidOnDestroyClassBuilderFactory(interceptedFactory, bindingContext)
|
||||
}
|
||||
|
||||
abstract fun getGlobalCacheImpl(element: KtElement): CacheImplementation
|
||||
|
||||
private inner class AndroidOnDestroyClassBuilderFactory(
|
||||
private val delegateFactory: ClassBuilderFactory,
|
||||
val bindingContext: BindingContext
|
||||
) : ClassBuilderFactory {
|
||||
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder {
|
||||
return AndroidOnDestroyCollectorClassBuilder(delegateFactory.newClassBuilder(origin), bindingContext)
|
||||
}
|
||||
|
||||
override fun getClassBuilderMode() = delegateFactory.classBuilderMode
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegateFactory.asText((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegateFactory.asBytes((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
delegateFactory.close()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AndroidOnDestroyCollectorClassBuilder(
|
||||
internal val delegateClassBuilder: ClassBuilder,
|
||||
val bindingContext: BindingContext
|
||||
) : DelegatingClassBuilder() {
|
||||
private var currentClass: KtClass? = null
|
||||
private var currentClassName: String? = null
|
||||
|
||||
override fun getDelegate() = delegateClassBuilder
|
||||
|
||||
override fun defineClass(
|
||||
origin: PsiElement?,
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String,
|
||||
interfaces: Array<out String>
|
||||
) {
|
||||
if (origin is KtClass) {
|
||||
currentClass = origin
|
||||
currentClassName = name
|
||||
}
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
override fun newMethod(
|
||||
origin: JvmDeclarationOrigin,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
return object : MethodVisitor(Opcodes.API_VERSION, super.newMethod(origin, access, name, desc, signature, exceptions)) {
|
||||
override fun visitInsn(opcode: Int) {
|
||||
if (opcode == Opcodes.RETURN) {
|
||||
generateClearCacheMethodCall()
|
||||
}
|
||||
|
||||
super.visitInsn(opcode)
|
||||
}
|
||||
|
||||
private fun generateClearCacheMethodCall() {
|
||||
val currentClass = currentClass
|
||||
if (name != ON_DESTROY_METHOD_NAME || currentClass == null) return
|
||||
if (Type.getArgumentTypes(desc).isNotEmpty()) return
|
||||
if (Type.getReturnType(desc) != Type.VOID_TYPE) return
|
||||
|
||||
val containerType = currentClassName?.let { Type.getObjectType(it) } ?: return
|
||||
|
||||
val container = bindingContext.get(BindingContext.CLASS, currentClass) ?: return
|
||||
val entityOptions = ContainerOptionsProxy.create(container)
|
||||
if (!entityOptions.containerType.isFragment || !(entityOptions.cache ?: getGlobalCacheImpl(currentClass)).hasCache) return
|
||||
|
||||
val iv = InstructionAdapter(this)
|
||||
iv.load(0, containerType)
|
||||
iv.invokevirtual(currentClassName, CLEAR_CACHE_METHOD_NAME, "()V", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class ParcelizeClinitClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||
override fun interceptClassBuilderFactory(
|
||||
interceptedFactory: ClassBuilderFactory,
|
||||
bindingContext: BindingContext,
|
||||
diagnostics: DiagnosticSink
|
||||
): ClassBuilderFactory {
|
||||
return ParcelableClinitClassBuilderFactory(interceptedFactory, bindingContext)
|
||||
}
|
||||
|
||||
private inner class ParcelableClinitClassBuilderFactory(
|
||||
private val delegateFactory: ClassBuilderFactory,
|
||||
val bindingContext: BindingContext
|
||||
) : ClassBuilderFactory {
|
||||
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder {
|
||||
return AndroidOnDestroyCollectorClassBuilder(origin, delegateFactory.newClassBuilder(origin), bindingContext)
|
||||
}
|
||||
|
||||
override fun getClassBuilderMode() = delegateFactory.classBuilderMode
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegateFactory.asText((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegateFactory.asBytes((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
delegateFactory.close()
|
||||
}
|
||||
}
|
||||
|
||||
private class AndroidOnDestroyCollectorClassBuilder(
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val delegateClassBuilder: ClassBuilder,
|
||||
val bindingContext: BindingContext
|
||||
) : DelegatingClassBuilder() {
|
||||
private var currentClass: KtClassOrObject? = null
|
||||
private var currentClassName: String? = null
|
||||
private var isClinitGenerated = false
|
||||
|
||||
override fun getDelegate() = delegateClassBuilder
|
||||
|
||||
override fun defineClass(
|
||||
origin: PsiElement?,
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String,
|
||||
interfaces: Array<out String>
|
||||
) {
|
||||
currentClass = origin as? KtClassOrObject
|
||||
currentClassName = name
|
||||
isClinitGenerated = false
|
||||
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
override fun done() {
|
||||
if (!isClinitGenerated && currentClass != null && currentClassName != null) {
|
||||
val descriptor = bindingContext[BindingContext.CLASS, currentClass]
|
||||
if (descriptor != null && declarationOrigin.descriptor == descriptor && descriptor.isParcelize) {
|
||||
val baseVisitor = super.newMethod(JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC, "<clinit>", "()V", null, null)
|
||||
val visitor = ClinitAwareMethodVisitor(currentClassName!!, baseVisitor)
|
||||
|
||||
visitor.visitCode()
|
||||
visitor.visitInsn(Opcodes.RETURN)
|
||||
visitor.visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
super.done()
|
||||
}
|
||||
|
||||
override fun newMethod(
|
||||
origin: JvmDeclarationOrigin,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
if (name == "<clinit>" && currentClass != null && currentClassName != null) {
|
||||
isClinitGenerated = true
|
||||
|
||||
val descriptor = bindingContext[BindingContext.CLASS, currentClass]
|
||||
if (descriptor != null && declarationOrigin.descriptor == descriptor && descriptor.isParcelize) {
|
||||
return ClinitAwareMethodVisitor(
|
||||
currentClassName!!,
|
||||
super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
}
|
||||
|
||||
private class ClinitAwareMethodVisitor(val parcelableName: String, mv: MethodVisitor) : MethodVisitor(Opcodes.API_VERSION, mv) {
|
||||
override fun visitInsn(opcode: Int) {
|
||||
if (opcode == Opcodes.RETURN) {
|
||||
val iv = InstructionAdapter(this)
|
||||
val creatorName = "$parcelableName\$Creator"
|
||||
val creatorType = Type.getObjectType(creatorName)
|
||||
|
||||
iv.anew(creatorType)
|
||||
iv.dup()
|
||||
iv.invokespecial(creatorName, "<init>", "()V", false)
|
||||
iv.putstatic(parcelableName, "CREATOR", "Landroid/os/Parcelable\$Creator;")
|
||||
}
|
||||
|
||||
super.visitInsn(opcode)
|
||||
}
|
||||
}
|
||||
}
|
||||
-429
@@ -1,429 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.uast.kotlin.generate
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiClassType
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.util.resolveToKotlinType
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.generate.UParameterInfo
|
||||
import org.jetbrains.uast.generate.UastCodeGenerationPlugin
|
||||
import org.jetbrains.uast.generate.UastElementFactory
|
||||
import org.jetbrains.uast.kotlin.*
|
||||
import org.jetbrains.uast.kotlin.internal.KotlinFakeUElement
|
||||
import org.jetbrains.uast.kotlin.internal.toSourcePsiFakeAware
|
||||
|
||||
class KotlinUastCodeGenerationPlugin : UastCodeGenerationPlugin {
|
||||
override val language: Language
|
||||
get() = KotlinLanguage.INSTANCE
|
||||
|
||||
override fun getElementFactory(project: Project): UastElementFactory =
|
||||
KotlinUastElementFactory(project)
|
||||
|
||||
override fun <T : UElement> replace(oldElement: UElement, newElement: T, elementType: Class<T>): T? {
|
||||
val oldPsi = oldElement.toSourcePsiFakeAware().singleOrNull() ?: return null
|
||||
val newPsi = newElement.sourcePsi?.let {
|
||||
when {
|
||||
it is KtCallExpression && it.parent is KtQualifiedExpression -> it.parent
|
||||
else -> it
|
||||
}
|
||||
} ?: return null
|
||||
|
||||
val psiFactory = KtPsiFactory(oldPsi.project)
|
||||
val oldParentPsi = oldPsi.parent
|
||||
val (updOldPsi, updNewPsi) = when {
|
||||
oldParentPsi is KtStringTemplateExpression && oldParentPsi.entries.size == 1 ->
|
||||
oldParentPsi to newPsi
|
||||
|
||||
oldPsi is KtStringTemplateEntry && newPsi !is KtStringTemplateEntry && newPsi is KtExpression ->
|
||||
oldPsi to psiFactory.createBlockStringTemplateEntry(newPsi)
|
||||
|
||||
oldPsi is KtBlockExpression && newPsi is KtBlockExpression -> {
|
||||
if (!hasBraces(oldPsi) && hasBraces(newPsi)) {
|
||||
oldPsi to psiFactory.createLambdaExpression("none", newPsi.statements.joinToString("\n") { "println()" }).bodyExpression!!.also {
|
||||
it.statements.zip(newPsi.statements).forEach { it.first.replace(it.second) }
|
||||
}
|
||||
} else
|
||||
oldPsi to newPsi
|
||||
}
|
||||
|
||||
else ->
|
||||
oldPsi to newPsi
|
||||
}
|
||||
|
||||
return when (val replaced = updOldPsi.replace(updNewPsi)?.safeAs<KtElement>()?.let { ShortenReferences.DEFAULT.process(it) }) {
|
||||
is KtCallExpression, is KtQualifiedExpression -> replaced.cast<KtExpression>().getPossiblyQualifiedCallExpression()
|
||||
else -> replaced
|
||||
}?.toUElementOfExpectedTypes(elementType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasBraces(oldPsi: KtBlockExpression): Boolean = oldPsi.lBrace != null && oldPsi.rBrace != null
|
||||
|
||||
class KotlinUastElementFactory(project: Project) : UastElementFactory {
|
||||
private val psiFactory = KtPsiFactory(project)
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createQualifiedReference(qualifiedName: String, context: UElement?): UQualifiedReferenceExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createQualifiedReference(qualifiedName, context?.sourcePsi)
|
||||
}
|
||||
|
||||
/*override*/ fun createQualifiedReference(qualifiedName: String, context: PsiElement?): UQualifiedReferenceExpression? {
|
||||
return psiFactory.createExpression(qualifiedName).let {
|
||||
when (it) {
|
||||
is KtDotQualifiedExpression -> KotlinUQualifiedReferenceExpression(it, null)
|
||||
is KtSafeQualifiedExpression -> KotlinUSafeQualifiedExpression(it, null)
|
||||
else -> null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun createCallExpression(
|
||||
receiver: UExpression?,
|
||||
methodName: String,
|
||||
parameters: List<UExpression>,
|
||||
expectedReturnType: PsiType?,
|
||||
kind: UastCallKind,
|
||||
context: PsiElement?
|
||||
): UCallExpression? {
|
||||
if (kind != UastCallKind.METHOD_CALL) return null
|
||||
|
||||
val typeParams = (context as? KtElement)?.let { kontext ->
|
||||
val resolutionFacade = kontext.getResolutionFacade()
|
||||
(expectedReturnType as? PsiClassType)?.parameters?.map { it.resolveToKotlinType(resolutionFacade) }
|
||||
}
|
||||
|
||||
val name = methodName.quoteIfNeeded()
|
||||
val methodCall = psiFactory.createExpression(
|
||||
buildString {
|
||||
if (receiver != null)
|
||||
append("a.")
|
||||
append(name)
|
||||
if (typeParams != null) {
|
||||
append(typeParams.joinToString(", ", "<", ">") { type ->
|
||||
type.fqName?.asString() ?: ""
|
||||
})
|
||||
}
|
||||
append("()")
|
||||
}
|
||||
).getPossiblyQualifiedCallExpression() ?: return null
|
||||
|
||||
if (receiver != null) {
|
||||
methodCall.parent.safeAs<KtDotQualifiedExpression>()?.receiverExpression?.replace(wrapULiteral(receiver).sourcePsi!!)
|
||||
}
|
||||
|
||||
val valueArgumentList = methodCall.valueArgumentList
|
||||
for (parameter in parameters) {
|
||||
valueArgumentList?.addArgument(psiFactory.createArgument(wrapULiteral(parameter).sourcePsi as KtExpression))
|
||||
}
|
||||
|
||||
return KotlinUFunctionCallExpression(methodCall, null)
|
||||
|
||||
}
|
||||
|
||||
override fun createStringLiteralExpression(text: String, context: PsiElement?): ULiteralExpression? {
|
||||
return KotlinStringULiteralExpression(psiFactory.createExpression(StringUtil.wrapWithDoubleQuote(text)), null)
|
||||
}
|
||||
|
||||
/*override*/ fun createNullLiteral(context: PsiElement?): ULiteralExpression {
|
||||
return psiFactory.createExpression("null").toUElementOfType<ULiteralExpression>()!!
|
||||
}
|
||||
|
||||
/*override*/ fun createIntLiteral(value: Int, context: PsiElement?): ULiteralExpression {
|
||||
return psiFactory.createExpression(value.toString()).toUElementOfType<ULiteralExpression>()!!
|
||||
}
|
||||
|
||||
private fun KtExpression.ensureBlockExpressionBraces(): KtExpression {
|
||||
if (this !is KtBlockExpression || hasBraces(this)) return this
|
||||
val blockExpression = psiFactory.createBlock(this.statements.joinToString("\n") { "println()" })
|
||||
for ((placeholder, statement) in blockExpression.statements.zip(this.statements)) {
|
||||
placeholder.replace(statement)
|
||||
}
|
||||
return blockExpression
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createIfExpression(condition: UExpression, thenBranch: UExpression, elseBranch: UExpression?): UIfExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createIfExpression(condition, thenBranch, elseBranch, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createIfExpression(
|
||||
condition: UExpression,
|
||||
thenBranch: UExpression,
|
||||
elseBranch: UExpression?,
|
||||
context: PsiElement?
|
||||
): UIfExpression? {
|
||||
val conditionPsi = condition.sourcePsi as? KtExpression ?: return null
|
||||
val thenBranchPsi = thenBranch.sourcePsi as? KtExpression ?: return null
|
||||
val elseBranchPsi = elseBranch?.sourcePsi as? KtExpression
|
||||
|
||||
return KotlinUIfExpression(psiFactory.createIf(conditionPsi, thenBranchPsi.ensureBlockExpressionBraces(), elseBranchPsi?.ensureBlockExpressionBraces()), null)
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createParenthesizedExpression(expression: UExpression): UParenthesizedExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createParenthesizedExpression(expression, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createParenthesizedExpression(expression: UExpression, context: PsiElement?): UParenthesizedExpression? {
|
||||
val source = expression.sourcePsi ?: return null
|
||||
val parenthesized = psiFactory.createExpression("(${source.text})") as? KtParenthesizedExpression ?: return null
|
||||
return KotlinUParenthesizedExpression(parenthesized, null)
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createSimpleReference(name: String): USimpleNameReferenceExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createSimpleReference(name, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createSimpleReference(name: String, context: PsiElement?): USimpleNameReferenceExpression? {
|
||||
return KotlinUSimpleReferenceExpression(psiFactory.createSimpleName(name), null)
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createSimpleReference(variable: UVariable): USimpleNameReferenceExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createSimpleReference(variable, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createSimpleReference(variable: UVariable, context: PsiElement?): USimpleNameReferenceExpression? {
|
||||
return createSimpleReference(variable.name ?: return null, context)
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createReturnExpresion(expression: UExpression?, inLambda: Boolean): UReturnExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createReturnExpresion(expression, inLambda, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createReturnExpresion(expression: UExpression?, inLambda: Boolean, context: PsiElement?): UReturnExpression? {
|
||||
val label = if (inLambda && context != null) getParentLambdaLabelName(context)?.let { "@$it" } ?: "" else ""
|
||||
val returnExpression = psiFactory.createExpression("return$label 1") as KtReturnExpression
|
||||
val sourcePsi = expression?.sourcePsi
|
||||
if (sourcePsi != null) {
|
||||
returnExpression.returnedExpression!!.replace(sourcePsi)
|
||||
} else {
|
||||
returnExpression.returnedExpression?.delete()
|
||||
}
|
||||
return KotlinUReturnExpression(returnExpression, null)
|
||||
}
|
||||
|
||||
private fun getParentLambdaLabelName(context: PsiElement): String? {
|
||||
val lambdaExpression = context.getParentOfType<KtLambdaExpression>(false) ?: return null
|
||||
lambdaExpression.parent.safeAs<KtLabeledExpression>()?.let { return it.getLabelName() }
|
||||
val callExpression = lambdaExpression.getStrictParentOfType<KtCallExpression>() ?: return null
|
||||
callExpression.valueArguments.find {
|
||||
it.getArgumentExpression()?.unpackFunctionLiteral(allowParentheses = false) === lambdaExpression
|
||||
} ?: return null
|
||||
return callExpression.getCallNameExpression()?.text
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createBinaryExpression(
|
||||
leftOperand: UExpression,
|
||||
rightOperand: UExpression,
|
||||
operator: UastBinaryOperator
|
||||
): UBinaryExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createBinaryExpression(leftOperand, rightOperand, operator, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createBinaryExpression(
|
||||
leftOperand: UExpression,
|
||||
rightOperand: UExpression,
|
||||
operator: UastBinaryOperator,
|
||||
context: PsiElement?
|
||||
): UBinaryExpression? {
|
||||
val binaryExpression = joinBinaryExpression(leftOperand, rightOperand, operator) ?: return null
|
||||
return KotlinUBinaryExpression(binaryExpression, null)
|
||||
}
|
||||
|
||||
private fun joinBinaryExpression(
|
||||
leftOperand: UExpression,
|
||||
rightOperand: UExpression,
|
||||
operator: UastBinaryOperator
|
||||
): KtBinaryExpression? {
|
||||
val leftPsi = leftOperand.sourcePsi ?: return null
|
||||
val rightPsi = rightOperand.sourcePsi ?: return null
|
||||
|
||||
val binaryExpression = psiFactory.createExpression("a ${operator.text} b") as? KtBinaryExpression ?: return null
|
||||
binaryExpression.left?.replace(leftPsi)
|
||||
binaryExpression.right?.replace(rightPsi)
|
||||
return binaryExpression
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createFlatBinaryExpression(
|
||||
leftOperand: UExpression,
|
||||
rightOperand: UExpression,
|
||||
operator: UastBinaryOperator
|
||||
): UPolyadicExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createFlatBinaryExpression(leftOperand, rightOperand, operator, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createFlatBinaryExpression(
|
||||
leftOperand: UExpression,
|
||||
rightOperand: UExpression,
|
||||
operator: UastBinaryOperator,
|
||||
context: PsiElement?
|
||||
): UPolyadicExpression? {
|
||||
|
||||
fun unwrapParentheses(exp: KtExpression?) {
|
||||
if (exp !is KtParenthesizedExpression) return
|
||||
if (!KtPsiUtil.areParenthesesUseless(exp)) return
|
||||
exp.expression?.let { exp.replace(it) }
|
||||
}
|
||||
|
||||
val binaryExpression = joinBinaryExpression(leftOperand, rightOperand, operator) ?: return null
|
||||
unwrapParentheses(binaryExpression.left)
|
||||
unwrapParentheses(binaryExpression.right)
|
||||
|
||||
return psiFactory.createExpression(binaryExpression.text).toUElementOfType()!!
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createBlockExpression(expressions: List<UExpression>): UBlockExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createBlockExpression(expressions, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createBlockExpression(expressions: List<UExpression>, context: PsiElement?): UBlockExpression? {
|
||||
val sourceExpressions = expressions.flatMap { it.toSourcePsiFakeAware() }
|
||||
val block = psiFactory.createBlock(
|
||||
sourceExpressions.joinToString(separator = "\n") { "println()" }
|
||||
)
|
||||
for ((placeholder, psiElement) in block.statements.zip(sourceExpressions)) {
|
||||
placeholder.replace(psiElement)
|
||||
}
|
||||
return KotlinUBlockExpression(block, null)
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createDeclarationExpression(declarations: List<UDeclaration>): UDeclarationsExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createDeclarationExpression(declarations, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createDeclarationExpression(declarations: List<UDeclaration>, context: PsiElement?): UDeclarationsExpression? {
|
||||
return object : KotlinUDeclarationsExpression(null), KotlinFakeUElement {
|
||||
override var declarations: List<UDeclaration> = declarations
|
||||
override fun unwrapToSourcePsi(): List<PsiElement> = declarations.flatMap { it.toSourcePsiFakeAware() }
|
||||
}
|
||||
}
|
||||
|
||||
/*override*/ fun createLambdaExpression(
|
||||
parameters: List<UParameterInfo>,
|
||||
body: UExpression,
|
||||
context: PsiElement?
|
||||
): ULambdaExpression? {
|
||||
val resolutionFacade = (context as? KtElement)?.getResolutionFacade()
|
||||
val validator = (context as? KtElement)?.let { usedNamesFilter(it) } ?: { true }
|
||||
|
||||
val newLambdaStatements = if (body is UBlockExpression) {
|
||||
body.expressions.flatMap { member ->
|
||||
when {
|
||||
member is UReturnExpression -> member.returnExpression?.toSourcePsiFakeAware().orEmpty()
|
||||
else -> member.toSourcePsiFakeAware()
|
||||
}
|
||||
}
|
||||
} else
|
||||
listOf(body.sourcePsi!!)
|
||||
|
||||
val ktLambdaExpression = psiFactory.createLambdaExpression(
|
||||
parameters.joinToString(", ") { p ->
|
||||
val ktype = resolutionFacade?.let { p.type?.resolveToKotlinType(it) }
|
||||
StringBuilder().apply {
|
||||
append(p.suggestedName ?: ktype?.let { KotlinNameSuggester.suggestNamesByType(it, validator).firstOrNull() })
|
||||
?: KotlinNameSuggester.suggestNameByName("v", validator)
|
||||
ktype?.fqName?.toString()?.let { append(": ").append(it) }
|
||||
}
|
||||
},
|
||||
newLambdaStatements.joinToString("\n") { "placeholder" }
|
||||
)
|
||||
|
||||
for ((old, new) in ktLambdaExpression.bodyExpression!!.statements.zip(newLambdaStatements)) {
|
||||
old.replace(new)
|
||||
}
|
||||
|
||||
return ktLambdaExpression.toUElementOfType()!!
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createLambdaExpression(parameters: List<UParameterInfo>, body: UExpression): ULambdaExpression? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createLambdaExpression(parameters, body, null)
|
||||
}
|
||||
|
||||
/*override*/ fun createLocalVariable(
|
||||
suggestedName: String?,
|
||||
type: PsiType?,
|
||||
initializer: UExpression,
|
||||
immutable: Boolean,
|
||||
context: PsiElement?
|
||||
): ULocalVariable? {
|
||||
val resolutionFacade = (context as? KtElement)?.getResolutionFacade()
|
||||
val validator = (context as? KtElement)?.let { usedNamesFilter(it) } ?: { true }
|
||||
val ktype = resolutionFacade?.let { type?.resolveToKotlinType(it) }
|
||||
|
||||
val function = psiFactory.createFunction(
|
||||
buildString {
|
||||
append("fun foo() { ")
|
||||
append(if (immutable) "val" else "var")
|
||||
append(" ")
|
||||
append(suggestedName ?: ktype?.let { KotlinNameSuggester.suggestNamesByType(it, validator).firstOrNull() })
|
||||
?: KotlinNameSuggester.suggestNameByName("v", validator)
|
||||
ktype?.fqName?.toString()?.let { append(": ").append(it) }
|
||||
append(" = null")
|
||||
append("}")
|
||||
}
|
||||
)
|
||||
|
||||
val ktVariable = PsiTreeUtil.findChildOfType(function, KtVariableDeclaration::class.java)!!
|
||||
val newVariable = ktVariable.initializer!!.replace(initializer.sourcePsi!!).parent
|
||||
return newVariable.toUElementOfType<UVariable>() as ULocalVariable
|
||||
}
|
||||
|
||||
@Deprecated("use version with context parameter")
|
||||
override fun createLocalVariable(
|
||||
suggestedName: String?,
|
||||
type: PsiType?,
|
||||
initializer: UExpression,
|
||||
immutable: Boolean
|
||||
): ULocalVariable? {
|
||||
logger<KotlinUastElementFactory>().error("Please switch caller to the version with a context parameter")
|
||||
return createLocalVariable(suggestedName, type, initializer, immutable, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun usedNamesFilter(context: KtElement): (String) -> Boolean {
|
||||
val scope = context.getResolutionScope()
|
||||
return { name: String -> scope.findClassifier(Name.identifier(name), NoLookupLocation.FROM_IDE) == null }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.test.common.UElementToParentMap
|
||||
import org.jetbrains.uast.test.common.kotlin.IdentifiersTestBase
|
||||
import org.jetbrains.uast.test.common.visitUFileAndGetResult
|
||||
import org.jetbrains.uast.test.env.assertEqualsToFile
|
||||
import java.io.File
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
|
||||
abstract class AbstractKotlinIdentifiersTest : AbstractKotlinUastTest(), IdentifiersTestBase {
|
||||
|
||||
private fun getTestFile(testName: String, ext: String) =
|
||||
File(File(TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext)
|
||||
|
||||
override fun getIdentifiersFile(testName: String): File = getTestFile(testName, "identifiers.txt")
|
||||
|
||||
override fun check(testName: String, file: UFile) {
|
||||
super.check(testName, file)
|
||||
assertEqualsToFile("refNames", getTestFile(testName, "refNames.txt"), file.asRefNames())
|
||||
}
|
||||
}
|
||||
|
||||
private fun refNameRetriever(psiElement: PsiElement): UElement? =
|
||||
when (val uElement = psiElement.toUElementOfExpectedTypes(UCallExpression::class.java, UReferenceExpression::class.java)) {
|
||||
is UReferenceExpression -> uElement.referenceNameElement
|
||||
is UCallExpression -> uElement.classReference?.referenceNameElement
|
||||
else -> null
|
||||
}?.also {
|
||||
assertNotNull(it.sourcePsi, "referenceNameElement should have physical source, origin = $psiElement")
|
||||
}
|
||||
|
||||
fun UFile.asRefNames() = object : UElementToParentMap(::refNameRetriever) {
|
||||
override fun renderSource(element: PsiElement): String = element.javaClass.simpleName
|
||||
}.visitUFileAndGetResult(this)
|
||||
Reference in New Issue
Block a user