Build: Drop IntelliJ 2018.3 and Android Studio 3.4 support
Delete *.183 and *.as34 bunch-files
This commit is contained in:
-78
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.kotlin.android.model.impl
|
||||
|
||||
import com.android.builder.model.SourceProvider
|
||||
import com.android.tools.idea.gradle.project.GradleProjectInfo
|
||||
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||
import com.android.tools.idea.res.AppResourceRepository
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
import org.jetbrains.kotlin.android.model.AndroidModuleInfoProvider
|
||||
import java.io.File
|
||||
|
||||
class AndroidModuleInfoProviderImpl(override val module: Module) : AndroidModuleInfoProvider {
|
||||
private val androidFacet: AndroidFacet?
|
||||
get() = AndroidFacet.getInstance(module)
|
||||
|
||||
private val androidModuleModel: AndroidModuleModel?
|
||||
get() = AndroidModuleModel.get(module)
|
||||
|
||||
override fun isAndroidModule() = androidFacet != null
|
||||
override fun isGradleModule() = GradleProjectInfo.getInstance(module.project).isBuildWithGradle
|
||||
|
||||
override fun getAllResourceDirectories(): List<VirtualFile> {
|
||||
return androidFacet?.allResourceDirectories ?: emptyList()
|
||||
}
|
||||
|
||||
override fun getApplicationPackage() = androidFacet?.manifest?.`package`?.toString()
|
||||
|
||||
override fun getMainSourceProvider(): AndroidModuleInfoProvider.SourceProviderMirror? {
|
||||
return androidFacet?.mainSourceProvider?.let(::SourceProviderMirrorImpl)
|
||||
}
|
||||
|
||||
override fun getApplicationResourceDirectories(createIfNecessary: Boolean): Collection<VirtualFile> {
|
||||
return AppResourceRepository.getOrCreateInstance(module)?.resourceDirs ?: emptyList()
|
||||
}
|
||||
|
||||
override fun getAllSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {
|
||||
val androidModuleModel = this.androidModuleModel ?: return emptyList()
|
||||
return androidModuleModel.allSourceProviders.map(::SourceProviderMirrorImpl)
|
||||
}
|
||||
|
||||
override fun getActiveSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {
|
||||
val androidModuleModel = this.androidModuleModel ?: return emptyList()
|
||||
return androidModuleModel.activeSourceProviders.map(::SourceProviderMirrorImpl)
|
||||
}
|
||||
|
||||
override fun getFlavorSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {
|
||||
val androidModuleModel = this.androidModuleModel ?: return emptyList()
|
||||
|
||||
val getFlavorSourceProvidersMethod = try {
|
||||
AndroidFacet::class.java.getMethod("getFlavorSourceProviders")
|
||||
} catch (e: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
|
||||
return if (getFlavorSourceProvidersMethod != null) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceProviders = getFlavorSourceProvidersMethod.invoke(androidFacet) as? List<SourceProvider>
|
||||
sourceProviders?.map(::SourceProviderMirrorImpl) ?: emptyList()
|
||||
} else {
|
||||
androidModuleModel.flavorSourceProviders.map(::SourceProviderMirrorImpl)
|
||||
}
|
||||
}
|
||||
|
||||
private class SourceProviderMirrorImpl(val sourceProvider: SourceProvider) :
|
||||
AndroidModuleInfoProvider.SourceProviderMirror {
|
||||
override val name: String
|
||||
get() = sourceProvider.name
|
||||
|
||||
override val resDirectories: Collection<File>
|
||||
get() = sourceProvider.resDirectories
|
||||
}
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.kotlin.android.model.impl
|
||||
|
||||
import com.android.builder.model.SourceProvider
|
||||
import com.android.tools.idea.gradle.project.GradleProjectInfo
|
||||
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||
import com.android.tools.idea.res.ResourceRepositoryManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
import org.jetbrains.kotlin.android.model.AndroidModuleInfoProvider
|
||||
import java.io.File
|
||||
|
||||
class AndroidModuleInfoProviderImpl(override val module: Module) : AndroidModuleInfoProvider {
|
||||
private val androidFacet: AndroidFacet?
|
||||
get() = AndroidFacet.getInstance(module)
|
||||
|
||||
private val androidModuleModel: AndroidModuleModel?
|
||||
get() = AndroidModuleModel.get(module)
|
||||
|
||||
override fun isAndroidModule() = androidFacet != null
|
||||
override fun isGradleModule() = GradleProjectInfo.getInstance(module.project).isBuildWithGradle
|
||||
|
||||
override fun getAllResourceDirectories(): List<VirtualFile> {
|
||||
return androidFacet?.allResourceDirectories ?: emptyList()
|
||||
}
|
||||
|
||||
override fun getApplicationPackage() = androidFacet?.manifest?.`package`?.toString()
|
||||
|
||||
override fun getMainSourceProvider(): AndroidModuleInfoProvider.SourceProviderMirror? {
|
||||
return androidFacet?.mainSourceProvider?.let(::SourceProviderMirrorImpl)
|
||||
}
|
||||
|
||||
override fun getApplicationResourceDirectories(createIfNecessary: Boolean): Collection<VirtualFile> {
|
||||
return ResourceRepositoryManager.getOrCreateInstance(module)?.getAppResources(createIfNecessary)?.resourceDirs ?: emptyList()
|
||||
}
|
||||
|
||||
override fun getAllSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {
|
||||
val androidModuleModel = this.androidModuleModel ?: return emptyList()
|
||||
return androidModuleModel.allSourceProviders.map(::SourceProviderMirrorImpl)
|
||||
}
|
||||
|
||||
override fun getActiveSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {
|
||||
val androidModuleModel = this.androidModuleModel ?: return emptyList()
|
||||
return androidModuleModel.activeSourceProviders.map(::SourceProviderMirrorImpl)
|
||||
}
|
||||
|
||||
override fun getFlavorSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {
|
||||
val androidModuleModel = this.androidModuleModel ?: return emptyList()
|
||||
|
||||
val getFlavorSourceProvidersMethod = try {
|
||||
AndroidFacet::class.java.getMethod("getFlavorSourceProviders")
|
||||
} catch (e: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
|
||||
return if (getFlavorSourceProvidersMethod != null) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceProviders = getFlavorSourceProvidersMethod.invoke(androidFacet) as? List<SourceProvider>
|
||||
sourceProviders?.map(::SourceProviderMirrorImpl) ?: emptyList()
|
||||
} else {
|
||||
androidModuleModel.flavorSourceProviders.map(::SourceProviderMirrorImpl)
|
||||
}
|
||||
}
|
||||
|
||||
private class SourceProviderMirrorImpl(val sourceProvider: SourceProvider) :
|
||||
AndroidModuleInfoProvider.SourceProviderMirror {
|
||||
override val name: String
|
||||
get() = sourceProvider.name
|
||||
|
||||
override val resDirectories: Collection<File>
|
||||
get() = sourceProvider.resDirectories
|
||||
}
|
||||
}
|
||||
-200
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* 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.kapt.idea
|
||||
|
||||
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.*
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.tooling.model.idea.IdeaModule
|
||||
import org.jetbrains.kotlin.gradle.AbstractKotlinGradleModelBuilder
|
||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.lang.Exception
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
interface KaptSourceSetModel : Serializable {
|
||||
val sourceSetName: String
|
||||
val isTest: Boolean
|
||||
val generatedSourcesDir: String
|
||||
val generatedClassesDir: String
|
||||
val generatedKotlinSourcesDir: String
|
||||
|
||||
val generatedSourcesDirFile get() = generatedSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||
val generatedClassesDirFile get() = generatedClassesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||
val generatedKotlinSourcesDirFile get() = generatedKotlinSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||
}
|
||||
|
||||
class KaptSourceSetModelImpl(
|
||||
override val sourceSetName: String,
|
||||
override val isTest: Boolean,
|
||||
override val generatedSourcesDir: String,
|
||||
override val generatedClassesDir: String,
|
||||
override val generatedKotlinSourcesDir: String
|
||||
) : KaptSourceSetModel
|
||||
|
||||
interface KaptGradleModel : Serializable {
|
||||
val isEnabled: Boolean
|
||||
val buildDirectory: File
|
||||
val sourceSets: List<KaptSourceSetModel>
|
||||
}
|
||||
|
||||
class KaptGradleModelImpl(
|
||||
override val isEnabled: Boolean,
|
||||
override val buildDirectory: File,
|
||||
override val sourceSets: List<KaptSourceSetModel>
|
||||
) : KaptGradleModel
|
||||
|
||||
@Suppress("unused")
|
||||
class KaptProjectResolverExtension : AbstractProjectResolverExtension() {
|
||||
private companion object {
|
||||
private val LOG = Logger.getInstance(KaptProjectResolverExtension::class.java)
|
||||
}
|
||||
|
||||
override fun getExtraProjectModelClasses() = setOf(KaptGradleModel::class.java)
|
||||
override fun getToolingExtensionsClasses() = setOf(KaptModelBuilderService::class.java, Unit::class.java)
|
||||
|
||||
override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
||||
val kaptModel = resolverCtx.getExtraProject(gradleModule, KaptGradleModel::class.java)
|
||||
|
||||
if (kaptModel != null && kaptModel.isEnabled) {
|
||||
for (sourceSet in kaptModel.sourceSets) {
|
||||
populateAndroidModuleModelIfNeeded(ideModule, sourceSet)
|
||||
|
||||
val sourceSetDataNode = ideModule.findGradleSourceSet(sourceSet.sourceSetName) ?: continue
|
||||
|
||||
fun addSourceSet(path: String, type: ExternalSystemSourceType) {
|
||||
val contentRootData = ContentRootData(GRADLE_SYSTEM_ID, path)
|
||||
contentRootData.storePath(type, path)
|
||||
sourceSetDataNode.createChild(ProjectKeys.CONTENT_ROOT, contentRootData)
|
||||
}
|
||||
|
||||
val sourceType = if (sourceSet.isTest) ExternalSystemSourceType.TEST_GENERATED else ExternalSystemSourceType.SOURCE_GENERATED
|
||||
sourceSet.generatedSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
|
||||
sourceSet.generatedKotlinSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
|
||||
|
||||
sourceSet.generatedClassesDirFile?.let { generatedClassesDir ->
|
||||
val libraryData = LibraryData(GRADLE_SYSTEM_ID, "kaptGeneratedClasses")
|
||||
libraryData.addPath(LibraryPathType.BINARY, generatedClassesDir.absolutePath)
|
||||
val libraryDependencyData = LibraryDependencyData(sourceSetDataNode.data, libraryData, LibraryLevel.MODULE)
|
||||
sourceSetDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.populateModuleExtraModels(gradleModule, ideModule)
|
||||
}
|
||||
|
||||
private fun populateAndroidModuleModelIfNeeded(ideModule: DataNode<ModuleData>, sourceSet: KaptSourceSetModel) {
|
||||
ideModule.findAndroidModuleModel()?.let { androidModelAny ->
|
||||
// We can cast to AndroidModuleModel cause we already checked in findAndroidModuleModel() that the class exists
|
||||
|
||||
val generatedKotlinSources = sourceSet.generatedKotlinSourcesDirFile ?: return
|
||||
|
||||
val androidModel = androidModelAny.data as? AndroidModuleModel ?: return
|
||||
val variant = androidModel.findVariantByName(sourceSet.sourceSetName) ?: return
|
||||
|
||||
androidModel.registerExtraGeneratedSourceFolder(generatedKotlinSources)
|
||||
|
||||
// TODO remove this when IDEA eventually migrate to the newer Android plugin
|
||||
try {
|
||||
variant.mainArtifact.generatedSourceFolders += generatedKotlinSources
|
||||
} catch (e: Throwable) {
|
||||
// There was an error being thrown here, but the code above doesn't work for the newer versions of Android Studio 3
|
||||
// (generatedSourceFolders returns a wrapped unmodifiable list), and the thrown exception breaks the import.
|
||||
// The error will be moved back when I find a work-around for AS3.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DataNode<ModuleData>.findAndroidModuleModel(): DataNode<*>? {
|
||||
val modelClassName = "com.android.tools.idea.gradle.project.model.AndroidModuleModel"
|
||||
val node = children.firstOrNull { it.key.dataType == modelClassName } ?: return null
|
||||
return if (!hasClassInClasspath(modelClassName)) null else node
|
||||
}
|
||||
|
||||
private fun hasClassInClasspath(name: String): Boolean {
|
||||
return try {
|
||||
Class.forName(name) != null
|
||||
} catch (thr: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun DataNode<ModuleData>.findGradleSourceSet(sourceSetName: String): DataNode<GradleSourceSetData>? {
|
||||
val moduleName = data.id
|
||||
for (child in children) {
|
||||
val gradleSourceSetData = child.data as? GradleSourceSetData ?: continue
|
||||
if (gradleSourceSetData.id == "$moduleName:$sourceSetName") {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return child as DataNode<GradleSourceSetData>?
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class KaptModelBuilderService : AbstractKotlinGradleModelBuilder() {
|
||||
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||
return ErrorMessageBuilder.create(project, e, "Gradle import errors")
|
||||
.withDescription("Unable to build kotlin-kapt plugin configuration")
|
||||
}
|
||||
|
||||
override fun canBuild(modelName: String?): Boolean = modelName == KaptGradleModel::class.java.name
|
||||
|
||||
override fun buildAll(modelName: String?, project: Project): Any {
|
||||
val kaptPlugin: Plugin<*>? = project.plugins.findPlugin("kotlin-kapt")
|
||||
val kaptIsEnabled = kaptPlugin != null
|
||||
|
||||
val sourceSets = mutableListOf<KaptSourceSetModel>()
|
||||
|
||||
if (kaptIsEnabled) {
|
||||
project.getAllTasks(false)[project]?.forEach { compileTask ->
|
||||
if (compileTask.javaClass.name !in kotlinCompileJvmTaskClasses) return@forEach
|
||||
|
||||
val sourceSetName = compileTask.getSourceSetName()
|
||||
val isTest = sourceSetName.toLowerCase().endsWith("test")
|
||||
|
||||
val kaptGeneratedSourcesDir = getKaptDirectory("getKaptGeneratedSourcesDir", project, sourceSetName)
|
||||
val kaptGeneratedClassesDir = getKaptDirectory("getKaptGeneratedClassesDir", project, sourceSetName)
|
||||
val kaptGeneratedKotlinSourcesDir = getKaptDirectory("getKaptGeneratedKotlinSourcesDir", project, sourceSetName)
|
||||
sourceSets += KaptSourceSetModelImpl(
|
||||
sourceSetName, isTest, kaptGeneratedSourcesDir, kaptGeneratedClassesDir, kaptGeneratedKotlinSourcesDir)
|
||||
}
|
||||
}
|
||||
|
||||
return KaptGradleModelImpl(kaptIsEnabled, project.buildDir, sourceSets)
|
||||
}
|
||||
|
||||
private fun getKaptDirectory(funName: String, project: Project, sourceSetName: String): String {
|
||||
val kotlinKaptPlugin = project.plugins.findPlugin("kotlin-kapt") ?: return ""
|
||||
|
||||
val targetMethod = kotlinKaptPlugin::class.java.methods.firstOrNull {
|
||||
Modifier.isStatic(it.modifiers) && it.name == funName && it.parameterCount == 2
|
||||
} ?: return ""
|
||||
|
||||
return (targetMethod(null, project, sourceSetName) as? File)?.absolutePath ?: ""
|
||||
}
|
||||
}
|
||||
-169
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* 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.kapt.idea
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.*
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.tooling.model.idea.IdeaModule
|
||||
import org.jetbrains.kotlin.gradle.AbstractKotlinGradleModelBuilder
|
||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.lang.Exception
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
interface KaptSourceSetModel : Serializable {
|
||||
val sourceSetName: String
|
||||
val isTest: Boolean
|
||||
val generatedSourcesDir: String
|
||||
val generatedClassesDir: String
|
||||
val generatedKotlinSourcesDir: String
|
||||
|
||||
val generatedSourcesDirFile get() = generatedSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||
val generatedClassesDirFile get() = generatedClassesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||
val generatedKotlinSourcesDirFile get() = generatedKotlinSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||
}
|
||||
|
||||
class KaptSourceSetModelImpl(
|
||||
override val sourceSetName: String,
|
||||
override val isTest: Boolean,
|
||||
override val generatedSourcesDir: String,
|
||||
override val generatedClassesDir: String,
|
||||
override val generatedKotlinSourcesDir: String
|
||||
) : KaptSourceSetModel
|
||||
|
||||
interface KaptGradleModel : Serializable {
|
||||
val isEnabled: Boolean
|
||||
val buildDirectory: File
|
||||
val sourceSets: List<KaptSourceSetModel>
|
||||
}
|
||||
|
||||
class KaptGradleModelImpl(
|
||||
override val isEnabled: Boolean,
|
||||
override val buildDirectory: File,
|
||||
override val sourceSets: List<KaptSourceSetModel>
|
||||
) : KaptGradleModel
|
||||
|
||||
@Suppress("unused")
|
||||
class KaptProjectResolverExtension : AbstractProjectResolverExtension() {
|
||||
private companion object {
|
||||
private val LOG = Logger.getInstance(KaptProjectResolverExtension::class.java)
|
||||
}
|
||||
|
||||
override fun getExtraProjectModelClasses() = setOf(KaptGradleModel::class.java)
|
||||
override fun getToolingExtensionsClasses() = setOf(KaptModelBuilderService::class.java, Unit::class.java)
|
||||
|
||||
override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
||||
val kaptModel = resolverCtx.getExtraProject(gradleModule, KaptGradleModel::class.java)
|
||||
|
||||
if (kaptModel != null && kaptModel.isEnabled) {
|
||||
for (sourceSet in kaptModel.sourceSets) {
|
||||
val parentDataNode = ideModule.findParentForSourceSetDataNode(sourceSet.sourceSetName) ?: continue
|
||||
|
||||
fun addSourceSet(path: String, type: ExternalSystemSourceType) {
|
||||
val contentRootData = ContentRootData(GRADLE_SYSTEM_ID, path)
|
||||
contentRootData.storePath(type, path)
|
||||
parentDataNode.createChild(ProjectKeys.CONTENT_ROOT, contentRootData)
|
||||
}
|
||||
|
||||
val sourceType =
|
||||
if (sourceSet.isTest) ExternalSystemSourceType.TEST_GENERATED else ExternalSystemSourceType.SOURCE_GENERATED
|
||||
sourceSet.generatedSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
|
||||
sourceSet.generatedKotlinSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
|
||||
|
||||
sourceSet.generatedClassesDirFile?.let { generatedClassesDir ->
|
||||
val libraryData = LibraryData(GRADLE_SYSTEM_ID, "kaptGeneratedClasses")
|
||||
val existingNode =
|
||||
parentDataNode.children.map { (it.data as? LibraryDependencyData)?.target }
|
||||
.firstOrNull { it?.externalName == libraryData.externalName }
|
||||
if (existingNode != null) {
|
||||
existingNode.addPath(LibraryPathType.BINARY, generatedClassesDir.absolutePath)
|
||||
} else {
|
||||
libraryData.addPath(LibraryPathType.BINARY, generatedClassesDir.absolutePath)
|
||||
val libraryDependencyData = LibraryDependencyData(parentDataNode.data, libraryData, LibraryLevel.MODULE)
|
||||
parentDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.populateModuleExtraModels(gradleModule, ideModule)
|
||||
}
|
||||
|
||||
private fun DataNode<ModuleData>.findParentForSourceSetDataNode(sourceSetName: String): DataNode<ModuleData>? {
|
||||
val moduleName = data.id
|
||||
for (child in children) {
|
||||
val gradleSourceSetData = child.data as? GradleSourceSetData ?: continue
|
||||
if (gradleSourceSetData.id == "$moduleName:$sourceSetName") {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return child as? DataNode<ModuleData>
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
class KaptModelBuilderService : AbstractKotlinGradleModelBuilder() {
|
||||
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||
return ErrorMessageBuilder.create(project, e, "Gradle import errors")
|
||||
.withDescription("Unable to build kotlin-kapt plugin configuration")
|
||||
}
|
||||
|
||||
override fun canBuild(modelName: String?): Boolean = modelName == KaptGradleModel::class.java.name
|
||||
|
||||
override fun buildAll(modelName: String?, project: Project): Any {
|
||||
val kaptPlugin: Plugin<*>? = project.plugins.findPlugin("kotlin-kapt")
|
||||
val kaptIsEnabled = kaptPlugin != null
|
||||
|
||||
val sourceSets = mutableListOf<KaptSourceSetModel>()
|
||||
|
||||
if (kaptIsEnabled) {
|
||||
project.getAllTasks(false)[project]?.forEach { compileTask ->
|
||||
if (compileTask.javaClass.name !in kotlinCompileJvmTaskClasses) return@forEach
|
||||
|
||||
val sourceSetName = compileTask.getSourceSetName()
|
||||
val isTest = sourceSetName.toLowerCase().endsWith("test")
|
||||
|
||||
val kaptGeneratedSourcesDir = getKaptDirectory("getKaptGeneratedSourcesDir", project, sourceSetName)
|
||||
val kaptGeneratedClassesDir = getKaptDirectory("getKaptGeneratedClassesDir", project, sourceSetName)
|
||||
val kaptGeneratedKotlinSourcesDir = getKaptDirectory("getKaptGeneratedKotlinSourcesDir", project, sourceSetName)
|
||||
sourceSets += KaptSourceSetModelImpl(
|
||||
sourceSetName, isTest, kaptGeneratedSourcesDir, kaptGeneratedClassesDir, kaptGeneratedKotlinSourcesDir)
|
||||
}
|
||||
}
|
||||
|
||||
return KaptGradleModelImpl(kaptIsEnabled, project.buildDir, sourceSets)
|
||||
}
|
||||
|
||||
private fun getKaptDirectory(funName: String, project: Project, sourceSetName: String): String {
|
||||
val kotlinKaptPlugin = project.plugins.findPlugin("kotlin-kapt") ?: return ""
|
||||
|
||||
val targetMethod = kotlinKaptPlugin::class.java.methods.firstOrNull {
|
||||
Modifier.isStatic(it.modifiers) && it.name == funName && it.parameterCount == 2
|
||||
} ?: return ""
|
||||
|
||||
return (targetMethod(null, project, sourceSetName) as? File)?.absolutePath ?: ""
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* 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.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.toLightGetter
|
||||
import org.jetbrains.kotlin.asJava.toLightSetter
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.expressions.KotlinLocalFunctionULambdaExpression
|
||||
import org.jetbrains.uast.kotlin.expressions.KotlinUElvisExpression
|
||||
import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
||||
|
||||
abstract class KotlinAbstractUElement(private val givenParent: UElement?) : KotlinUElementWithComments,
|
||||
JvmDeclarationUElementPlaceholder {
|
||||
|
||||
final override val uastParent: UElement? by lz {
|
||||
givenParent ?: convertParent()
|
||||
}
|
||||
|
||||
protected open fun convertParent(): UElement? {
|
||||
@Suppress("DEPRECATION")
|
||||
val psi = psi //TODO: `psi` is deprecated but it seems that it couldn't be simply replaced for this case
|
||||
var parent = psi?.parent ?: sourcePsi?.parent ?: psi?.containingFile
|
||||
|
||||
if (psi is PsiMethod && psi !is KtLightMethod) { // handling of synthetic things not represented in lightclasses directly
|
||||
when (parent) {
|
||||
is KtClassBody -> {
|
||||
val grandParent = parent.parent
|
||||
doConvertParent(this, grandParent)?.let { return it }
|
||||
parent = grandParent
|
||||
}
|
||||
is KtFile -> {
|
||||
parent.toUElementOfType<UClass>()?.let { return it } // mutlifile facade class
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (psi is KtLightClassForLocalDeclaration) {
|
||||
val originParent = psi.kotlinOrigin.parent
|
||||
parent = when (originParent) {
|
||||
is KtClassBody -> originParent.parent
|
||||
else -> originParent
|
||||
}
|
||||
}
|
||||
|
||||
if (psi is KtAnnotationEntry) {
|
||||
val parentUnwrapped = KotlinConverter.unwrapElements(parent) ?: return null
|
||||
val target = psi.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||
when (target) {
|
||||
AnnotationUseSiteTarget.PROPERTY_GETTER ->
|
||||
parent = (parentUnwrapped as? KtProperty)?.getter
|
||||
?: (parentUnwrapped as? KtParameter)?.toLightGetter()
|
||||
?: parent
|
||||
|
||||
AnnotationUseSiteTarget.PROPERTY_SETTER ->
|
||||
parent = (parentUnwrapped as? KtProperty)?.setter
|
||||
?: (parentUnwrapped as? KtParameter)?.toLightSetter()
|
||||
?: parent
|
||||
AnnotationUseSiteTarget.FIELD ->
|
||||
parent = (parentUnwrapped as? KtProperty)
|
||||
?: (parentUnwrapped as? KtParameter)
|
||||
?.takeIf { it.isPropertyParameter() }
|
||||
?.let(LightClassUtil::getLightClassBackingField)
|
||||
?: parent
|
||||
AnnotationUseSiteTarget.SETTER_PARAMETER ->
|
||||
parent = (parentUnwrapped as? KtParameter)
|
||||
?.toLightSetter()?.parameterList?.parameters?.firstOrNull() ?: parent
|
||||
}
|
||||
}
|
||||
if (psi is UastKotlinPsiVariable && parent != null) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
while (parent is KtStringTemplateEntryWithExpression ||
|
||||
parent is KtStringTemplateExpression && parent.entries.size == 1) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
if (parent is KtWhenConditionWithExpression) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
if (parent is KtImportList) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
if (psi is KtFunctionLiteral && parent is KtLambdaExpression) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
if (parent is KtLambdaArgument) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
if (psi is KtSuperTypeCallEntry) {
|
||||
parent = parent?.parent
|
||||
}
|
||||
|
||||
if (parent is KtPropertyDelegate) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
val result = doConvertParent(this, parent)
|
||||
if (result == this) {
|
||||
throw IllegalStateException("Loop in parent structure when converting a $psi of type ${psi?.javaClass} with parent $parent of type ${parent?.javaClass} text: [${parent?.text}], result = $result")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is UElement) {
|
||||
return false
|
||||
}
|
||||
|
||||
return this.psi == other.psi
|
||||
}
|
||||
|
||||
override fun hashCode() = psi?.hashCode() ?: 0
|
||||
}
|
||||
|
||||
fun doConvertParent(element: UElement, parent: PsiElement?): UElement? {
|
||||
val parentUnwrapped = KotlinConverter.unwrapElements(parent) ?: return null
|
||||
if (parent is KtValueArgument && parentUnwrapped is KtAnnotationEntry) {
|
||||
return (KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) as? KotlinUAnnotation)
|
||||
?.findAttributeValueExpression(parent)
|
||||
}
|
||||
|
||||
if (parent is KtParameter) {
|
||||
val annotationClass = findAnnotationClassFromConstructorParameter(parent)
|
||||
if (annotationClass != null) {
|
||||
return annotationClass.methods.find { it.name == parent.name }
|
||||
}
|
||||
}
|
||||
|
||||
if (parent is KtClassInitializer) {
|
||||
val containingClass = parent.containingClassOrObject
|
||||
if (containingClass != null) {
|
||||
val containingUClass = KotlinUastLanguagePlugin().convertElementWithParent(containingClass, null) as? KotlinUClass
|
||||
containingUClass?.methods?.filterIsInstance<KotlinConstructorUMethod>()?.firstOrNull { it.isPrimary }?.let {
|
||||
return it.uastBody
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val result = KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
||||
|
||||
if (result is KotlinUBlockExpression && element is UClass) {
|
||||
return KotlinUDeclarationsExpression(result).apply {
|
||||
declarations = listOf(element)
|
||||
}
|
||||
}
|
||||
|
||||
if (result is UEnumConstant && element is UDeclaration) {
|
||||
return result.initializingClass
|
||||
}
|
||||
|
||||
if (result is UCallExpression && result.uastParent is UEnumConstant) {
|
||||
return result.uastParent
|
||||
}
|
||||
|
||||
if (result is USwitchClauseExpressionWithBody && !isInConditionBranch(element, result)) {
|
||||
return result.body
|
||||
}
|
||||
|
||||
if (result is KotlinUDestructuringDeclarationExpression &&
|
||||
element.psi == (parent as KtDestructuringDeclaration).initializer) {
|
||||
return result.tempVarAssignment
|
||||
}
|
||||
|
||||
if (result is KotlinUElvisExpression && parent is KtBinaryExpression) {
|
||||
when (element.psi) {
|
||||
parent.left -> return result.lhsDeclaration
|
||||
parent.right -> return result.rhsIfExpression
|
||||
}
|
||||
}
|
||||
|
||||
if ((result is UMethod || result is KotlinLocalFunctionULambdaExpression)
|
||||
&& result !is KotlinConstructorUMethod // no sense to wrap super calls with `return`
|
||||
&& element is UExpression
|
||||
&& element !is UBlockExpression
|
||||
&& element !is UTypeReferenceExpression // when element is a type in extension methods
|
||||
) {
|
||||
return KotlinUBlockExpression.KotlinLazyUBlockExpression(result, { block ->
|
||||
listOf(KotlinUImplicitReturnExpression(block).apply { returnExpression = element })
|
||||
}).expressions.single()
|
||||
}
|
||||
|
||||
if (result is KotlinULambdaExpression.Body && element is UExpression && result.implicitReturn?.returnExpression == element) {
|
||||
return result.implicitReturn!!
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun isInConditionBranch(element: UElement, result: USwitchClauseExpressionWithBody) =
|
||||
element.psi?.parentsWithSelf?.takeWhile { it !== result.psi }?.any { it is KtWhenCondition } ?: false
|
||||
|
||||
|
||||
private fun findAnnotationClassFromConstructorParameter(parameter: KtParameter): UClass? {
|
||||
val primaryConstructor = parameter.getStrictParentOfType<KtPrimaryConstructor>() ?: return null
|
||||
val containingClass = primaryConstructor.getContainingClassOrObject()
|
||||
if (containingClass.isAnnotation()) {
|
||||
return KotlinUastLanguagePlugin().convertElementWithParent(containingClass, null) as? UClass
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
abstract class KotlinAbstractUExpression(givenParent: UElement?) :
|
||||
KotlinAbstractUElement(givenParent),
|
||||
UExpression,
|
||||
JvmDeclarationUElementPlaceholder {
|
||||
|
||||
override val javaPsi: PsiElement? = null
|
||||
|
||||
override val psi
|
||||
get() = sourcePsi
|
||||
|
||||
override val annotations: List<UAnnotation>
|
||||
get() {
|
||||
val annotatedExpression = sourcePsi?.parent as? KtAnnotatedExpression ?: return emptyList()
|
||||
return annotatedExpression.annotationEntries.map { KotlinUAnnotation(it, this) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,615 +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.uast.kotlin
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.elements.*
|
||||
import org.jetbrains.kotlin.asJava.findFacadeClass
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclaration
|
||||
import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclarationOrElement
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethodWithFakeLightDelegate
|
||||
import org.jetbrains.uast.kotlin.expressions.*
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
||||
|
||||
interface KotlinUastResolveProviderService {
|
||||
fun getBindingContext(element: KtElement): BindingContext
|
||||
fun getTypeMapper(element: KtElement): KotlinTypeMapper?
|
||||
fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings
|
||||
fun isJvmElement(psiElement: PsiElement): Boolean
|
||||
fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence<DeclarationDescriptor>
|
||||
}
|
||||
|
||||
var PsiElement.destructuringDeclarationInitializer: Boolean? by UserDataProperty(Key.create("kotlin.uast.destructuringDeclarationInitializer"))
|
||||
|
||||
class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
override val priority = 10
|
||||
|
||||
override val language: Language
|
||||
get() = KotlinLanguage.INSTANCE
|
||||
|
||||
override fun isFileSupported(fileName: String): Boolean {
|
||||
return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false)
|
||||
}
|
||||
|
||||
private val PsiElement.isJvmElement: Boolean
|
||||
get() {
|
||||
val resolveProvider = ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
|
||||
return resolveProvider.isJvmElement(this)
|
||||
}
|
||||
|
||||
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
|
||||
if (!element.isJvmElement) return null
|
||||
return convertDeclarationOrElement(element, parent, requiredType)
|
||||
}
|
||||
|
||||
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
|
||||
if (!element.isJvmElement) return null
|
||||
if (element is PsiFile) return convertDeclaration(element, null, requiredType)
|
||||
if (element is KtLightClassForFacade) return convertDeclaration(element, null, requiredType)
|
||||
|
||||
return convertDeclarationOrElement(element, null, requiredType)
|
||||
}
|
||||
|
||||
override fun getMethodCallExpression(
|
||||
element: PsiElement,
|
||||
containingClassFqName: String?,
|
||||
methodName: String
|
||||
): UastLanguagePlugin.ResolvedMethod? {
|
||||
if (element !is KtCallExpression) return null
|
||||
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return null
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
if (resultingDescriptor !is FunctionDescriptor || resultingDescriptor.name.asString() != methodName) return null
|
||||
|
||||
val parent = element.parent
|
||||
val parentUElement = convertElementWithParent(parent, null) ?: return null
|
||||
|
||||
val uExpression = KotlinUFunctionCallExpression(element, parentUElement, resolvedCall)
|
||||
val method = uExpression.resolve() ?: return null
|
||||
if (method.name != methodName) return null
|
||||
return UastLanguagePlugin.ResolvedMethod(uExpression, method)
|
||||
}
|
||||
|
||||
override fun getConstructorCallExpression(
|
||||
element: PsiElement,
|
||||
fqName: String
|
||||
): UastLanguagePlugin.ResolvedConstructor? {
|
||||
if (element !is KtCallExpression) return null
|
||||
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return null
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
if (resultingDescriptor !is ConstructorDescriptor
|
||||
|| resultingDescriptor.returnType.constructor.declarationDescriptor?.name?.asString() != fqName) {
|
||||
return null
|
||||
}
|
||||
|
||||
val parent = KotlinConverter.unwrapElements(element.parent) ?: return null
|
||||
val parentUElement = convertElementWithParent(parent, null) ?: return null
|
||||
|
||||
val uExpression = KotlinUFunctionCallExpression(element, parentUElement, resolvedCall)
|
||||
val method = uExpression.resolve() ?: return null
|
||||
val containingClass = method.containingClass ?: return null
|
||||
return UastLanguagePlugin.ResolvedConstructor(uExpression, method, containingClass)
|
||||
}
|
||||
|
||||
override fun isExpressionValueUsed(element: UExpression): Boolean {
|
||||
return when (element) {
|
||||
is KotlinUSimpleReferenceExpression.KotlinAccessorCallExpression -> element.setterValue != null
|
||||
is KotlinAbstractUExpression -> {
|
||||
val ktElement = element.sourcePsi as? KtElement ?: return false
|
||||
ktElement.analyze()[BindingContext.USED_AS_EXPRESSION, ktElement] ?: false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <reified ActualT : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? {
|
||||
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
|
||||
}
|
||||
|
||||
internal inline fun <reified ActualT : UElement> Class<out UElement>?.expr(f: () -> UExpression?): UExpression? {
|
||||
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal object KotlinConverter {
|
||||
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
|
||||
is KtValueArgumentList -> unwrapElements(element.parent)
|
||||
is KtValueArgument -> unwrapElements(element.parent)
|
||||
is KtDeclarationModifierList -> unwrapElements(element.parent)
|
||||
is KtContainerNode -> unwrapElements(element.parent)
|
||||
is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent)
|
||||
is KtLightParameterList -> unwrapElements(element.parent)
|
||||
is KtTypeElement -> unwrapElements(element.parent)
|
||||
is KtSuperTypeList -> unwrapElements(element.parent)
|
||||
else -> element
|
||||
}
|
||||
|
||||
private val identifiersTokens =
|
||||
setOf(KtTokens.IDENTIFIER, KtTokens.CONSTRUCTOR_KEYWORD, KtTokens.THIS_KEYWORD, KtTokens.SUPER_KEYWORD, KtTokens.OBJECT_KEYWORD)
|
||||
|
||||
internal fun convertPsiElement(element: PsiElement?,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?): UElement? {
|
||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? {
|
||||
return {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
ctor(element as P, givenParent)
|
||||
}
|
||||
}
|
||||
|
||||
return with (requiredType) { when (element) {
|
||||
is KtParameterList -> el<UDeclarationsExpression> {
|
||||
val declarationsExpression = KotlinUDeclarationsExpression(givenParent)
|
||||
declarationsExpression.apply {
|
||||
declarations = element.parameters.mapIndexed { i, p ->
|
||||
KotlinUParameter(UastKotlinPsiParameter.create(p, element, declarationsExpression, i), p, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtClassBody -> el<UExpressionList>(build(KotlinUExpressionList.Companion::createClassBody))
|
||||
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
|
||||
is KtVariableDeclaration ->
|
||||
if (element is KtProperty && !element.isLocal) {
|
||||
el<UField> {
|
||||
LightClassUtil.getLightClassBackingField(element)?.let {
|
||||
KotlinUField(it, element, givenParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
el<UVariable> {
|
||||
convertVariablesDeclaration(element, givenParent).declarations.singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, requiredType)
|
||||
is KtLambdaArgument -> element.getLambdaExpression()?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
|
||||
is KtLightElementBase -> {
|
||||
val expression = element.kotlinOrigin
|
||||
when (expression) {
|
||||
is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, requiredType)
|
||||
else -> el<UExpression> { UastEmptyExpression(givenParent) }
|
||||
}
|
||||
}
|
||||
is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el<ULiteralExpression>(build(::KotlinStringULiteralExpression))
|
||||
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
|
||||
is KtWhenEntry -> el<USwitchClauseExpressionWithBody>(build(::KotlinUSwitchEntry))
|
||||
is KtWhenCondition -> convertWhenCondition(element, givenParent, requiredType)
|
||||
is KtTypeReference -> el<UTypeReferenceExpression> { LazyKotlinUTypeReferenceExpression(element, givenParent) }
|
||||
is KtConstructorDelegationCall ->
|
||||
el<UCallExpression> { KotlinUFunctionCallExpression(element, givenParent) }
|
||||
is KtSuperTypeCallEntry ->
|
||||
el<UExpression> {
|
||||
(element.getParentOfType<KtClassOrObject>(true)?.parent as? KtObjectLiteralExpression)
|
||||
?.toUElementOfType<UExpression>()
|
||||
?: KotlinUFunctionCallExpression(element, givenParent)
|
||||
}
|
||||
is KtImportDirective -> el<UImportStatement>(build(::KotlinUImportStatement))
|
||||
else -> {
|
||||
if (element is LeafPsiElement) {
|
||||
if (element.elementType in identifiersTokens)
|
||||
if (element.elementType != KtTokens.OBJECT_KEYWORD || element.getParentOfType<KtObjectDeclaration>(false)?.nameIdentifier == null)
|
||||
el<UIdentifier>(build(::KotlinUIdentifier))
|
||||
else null
|
||||
else if (element.elementType in KtTokens.OPERATIONS && element.parent is KtOperationReferenceExpression)
|
||||
el<UIdentifier>(build(::KotlinUIdentifier))
|
||||
else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression)
|
||||
el<UIdentifier> {
|
||||
UIdentifier(
|
||||
element,
|
||||
KotlinUCollectionLiteralExpression(
|
||||
element.parent as KtCollectionLiteralExpression,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
else null
|
||||
} else null
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
internal fun convertEntry(entry: KtStringTemplateEntry,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>? = null): UExpression? {
|
||||
return with(requiredType) {
|
||||
if (entry is KtStringTemplateEntryWithExpression) {
|
||||
expr<UExpression> {
|
||||
KotlinConverter.convertOrEmpty(entry.expression, givenParent)
|
||||
}
|
||||
}
|
||||
else {
|
||||
expr<ULiteralExpression> {
|
||||
if (entry is KtEscapeStringTemplateEntry)
|
||||
KotlinStringULiteralExpression(entry, givenParent, entry.unescapedValue)
|
||||
else
|
||||
KotlinStringULiteralExpression(entry, givenParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun convertExpression(expression: KtExpression,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>? = null): UExpression? {
|
||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UExpression): () -> UExpression? {
|
||||
return {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
ctor(expression as P, givenParent)
|
||||
}
|
||||
}
|
||||
|
||||
return with (requiredType) { when (expression) {
|
||||
is KtVariableDeclaration -> expr<UDeclarationsExpression>(build(::convertVariablesDeclaration))
|
||||
|
||||
is KtStringTemplateExpression -> {
|
||||
when {
|
||||
expression.entries.isEmpty() -> {
|
||||
expr<ULiteralExpression> { KotlinStringULiteralExpression(expression, givenParent, "") }
|
||||
}
|
||||
expression.entries.size == 1 -> convertEntry(expression.entries[0], givenParent, requiredType)
|
||||
else -> {
|
||||
expr<UExpression> { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtDestructuringDeclaration -> expr<UDeclarationsExpression> {
|
||||
val declarationsExpression = KotlinUDestructuringDeclarationExpression(givenParent, expression)
|
||||
declarationsExpression.apply {
|
||||
val tempAssignment = KotlinULocalVariable(UastKotlinPsiVariable.create(expression, declarationsExpression), expression, declarationsExpression)
|
||||
val destructuringAssignments = expression.entries.mapIndexed { i, entry ->
|
||||
val psiFactory = KtPsiFactory(expression.project)
|
||||
val initializer = psiFactory.createAnalyzableExpression("${tempAssignment.name}.component${i + 1}()",
|
||||
expression.containingFile)
|
||||
initializer.destructuringDeclarationInitializer = true
|
||||
KotlinULocalVariable(UastKotlinPsiVariable.create(entry, tempAssignment.javaPsi, declarationsExpression, initializer), entry, declarationsExpression)
|
||||
}
|
||||
declarations = listOf(tempAssignment) + destructuringAssignments
|
||||
}
|
||||
}
|
||||
is KtLabeledExpression -> expr<ULabeledExpression>(build(::KotlinULabeledExpression))
|
||||
is KtClassLiteralExpression -> expr<UClassLiteralExpression>(build(::KotlinUClassLiteralExpression))
|
||||
is KtObjectLiteralExpression -> expr<UObjectLiteralExpression>(build(::KotlinUObjectLiteralExpression))
|
||||
is KtDotQualifiedExpression -> expr<UQualifiedReferenceExpression>(build(::KotlinUQualifiedReferenceExpression))
|
||||
is KtSafeQualifiedExpression -> expr<UQualifiedReferenceExpression>(build(::KotlinUSafeQualifiedExpression))
|
||||
is KtSimpleNameExpression -> expr<USimpleNameReferenceExpression>(build(::KotlinUSimpleReferenceExpression))
|
||||
is KtCallExpression -> expr<UCallExpression>(build(::KotlinUFunctionCallExpression))
|
||||
is KtCollectionLiteralExpression -> expr<UCallExpression>(build(::KotlinUCollectionLiteralExpression))
|
||||
is KtBinaryExpression -> {
|
||||
if (expression.operationToken == KtTokens.ELVIS) {
|
||||
expr<UExpressionList>(build(::createElvisExpression))
|
||||
}
|
||||
else expr<UBinaryExpression>(build(::KotlinUBinaryExpression))
|
||||
}
|
||||
is KtParenthesizedExpression -> expr<UParenthesizedExpression>(build(::KotlinUParenthesizedExpression))
|
||||
is KtPrefixExpression -> expr<UPrefixExpression>(build(::KotlinUPrefixExpression))
|
||||
is KtPostfixExpression -> expr<UPostfixExpression>(build(::KotlinUPostfixExpression))
|
||||
is KtThisExpression -> expr<UThisExpression>(build(::KotlinUThisExpression))
|
||||
is KtSuperExpression -> expr<USuperExpression>(build(::KotlinUSuperExpression))
|
||||
is KtCallableReferenceExpression -> expr<UCallableReferenceExpression>(build(::KotlinUCallableReferenceExpression))
|
||||
is KtIsExpression -> expr<UBinaryExpressionWithType>(build(::KotlinUTypeCheckExpression))
|
||||
is KtIfExpression -> expr<UIfExpression>(build(::KotlinUIfExpression))
|
||||
is KtWhileExpression -> expr<UWhileExpression>(build(::KotlinUWhileExpression))
|
||||
is KtDoWhileExpression -> expr<UDoWhileExpression>(build(::KotlinUDoWhileExpression))
|
||||
is KtForExpression -> expr<UForEachExpression>(build(::KotlinUForEachExpression))
|
||||
is KtWhenExpression -> expr<USwitchExpression>(build(::KotlinUSwitchExpression))
|
||||
is KtBreakExpression -> expr<UBreakExpression>(build(::KotlinUBreakExpression))
|
||||
is KtContinueExpression -> expr<UContinueExpression>(build(::KotlinUContinueExpression))
|
||||
is KtReturnExpression -> expr<UReturnExpression>(build(::KotlinUReturnExpression))
|
||||
is KtThrowExpression -> expr<UThrowExpression>(build(::KotlinUThrowExpression))
|
||||
is KtBlockExpression -> expr<UBlockExpression> {
|
||||
if (expression.parent is KtFunctionLiteral
|
||||
&& expression.parent.parent is KtLambdaExpression
|
||||
&& givenParent !is KotlinULambdaExpression
|
||||
) {
|
||||
KotlinULambdaExpression(expression.parent.parent as KtLambdaExpression, givenParent).body
|
||||
} else
|
||||
KotlinUBlockExpression(expression, givenParent)
|
||||
}
|
||||
is KtConstantExpression -> expr<ULiteralExpression>(build(::KotlinULiteralExpression))
|
||||
is KtTryExpression -> expr<UTryExpression>(build(::KotlinUTryExpression))
|
||||
is KtArrayAccessExpression -> expr<UArrayAccessExpression>(build(::KotlinUArrayAccessExpression))
|
||||
is KtLambdaExpression -> expr<ULambdaExpression>(build(::KotlinULambdaExpression))
|
||||
is KtBinaryExpressionWithTypeRHS -> expr<UBinaryExpressionWithType>(build(::KotlinUBinaryExpressionWithType))
|
||||
is KtClassOrObject -> expr<UDeclarationsExpression> {
|
||||
expression.toLightClass()?.let { lightClass ->
|
||||
KotlinUDeclarationsExpression(givenParent).apply {
|
||||
declarations = listOf(KotlinUClass.create(lightClass, this))
|
||||
}
|
||||
} ?: UastEmptyExpression(givenParent)
|
||||
}
|
||||
is KtFunction -> if (expression.name.isNullOrEmpty()) {
|
||||
expr<ULambdaExpression>(build(::createLocalFunctionLambdaExpression))
|
||||
}
|
||||
else {
|
||||
expr<UDeclarationsExpression>(build(::createLocalFunctionDeclaration))
|
||||
}
|
||||
|
||||
else -> expr<UExpression>(build(::UnknownKotlinExpression))
|
||||
}}
|
||||
}
|
||||
|
||||
internal fun convertWhenCondition(condition: KtWhenCondition,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>? = null
|
||||
): UExpression? {
|
||||
return with(requiredType) {
|
||||
when (condition) {
|
||||
is KtWhenConditionInRange -> expr<UBinaryExpression> {
|
||||
KotlinCustomUBinaryExpression(condition, givenParent).apply {
|
||||
leftOperand = KotlinStringUSimpleReferenceExpression("it", this)
|
||||
operator = when {
|
||||
condition.isNegated -> KotlinBinaryOperators.NOT_IN
|
||||
else -> KotlinBinaryOperators.IN
|
||||
}
|
||||
rightOperand = KotlinConverter.convertOrEmpty(condition.rangeExpression, this)
|
||||
}
|
||||
}
|
||||
is KtWhenConditionIsPattern -> expr<UBinaryExpression> {
|
||||
KotlinCustomUBinaryExpressionWithType(condition, givenParent).apply {
|
||||
operand = KotlinStringUSimpleReferenceExpression("it", this)
|
||||
operationKind = when {
|
||||
condition.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
||||
else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
||||
}
|
||||
val typeRef = condition.typeReference
|
||||
typeReference = typeRef?.let {
|
||||
LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is KtWhenConditionWithExpression ->
|
||||
condition.expression?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
|
||||
|
||||
else -> expr<UExpression> { UastEmptyExpression(givenParent) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertEnumEntry(original: KtEnumEntry, givenParent: UElement?): UElement? {
|
||||
return LightClassUtil.getLightClassBackingField(original)?.let { psiField ->
|
||||
if (psiField is KtLightFieldImpl.KtLightEnumConstant) {
|
||||
KotlinUEnumConstant(psiField, psiField.kotlinOrigin, givenParent)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun convertDeclaration(
|
||||
element: PsiElement,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?
|
||||
): UElement? {
|
||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? = {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
ctor(element as P, givenParent)
|
||||
}
|
||||
|
||||
fun <P : PsiElement, K : KtElement> buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? = {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
ctor(element as P, ktElement, givenParent)
|
||||
}
|
||||
|
||||
fun <P : PsiElement, K : KtElement> buildKtOpt(ktElement: K?, ctor: (P, K?, UElement?) -> UElement): () -> UElement? = {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
ctor(element as P, ktElement, givenParent)
|
||||
}
|
||||
|
||||
val original = element.originalElement
|
||||
return with(requiredType) {
|
||||
when (original) {
|
||||
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
|
||||
is KtLightClass -> when (original.kotlinOrigin) {
|
||||
is KtEnumEntry -> el<UEnumConstant> {
|
||||
convertEnumEntry(original.kotlinOrigin as KtEnumEntry, givenParent)
|
||||
}
|
||||
else -> el<UClass> { KotlinUClass.create(original, givenParent) }
|
||||
}
|
||||
is KtLightFieldImpl.KtLightEnumConstant -> el<UEnumConstant>(buildKtOpt(original.kotlinOrigin, ::KotlinUEnumConstant))
|
||||
is KtLightField -> el<UField>(buildKtOpt(original.kotlinOrigin, ::KotlinUField))
|
||||
is KtLightParameter -> el<UParameter>(buildKtOpt(original.kotlinOrigin, ::KotlinUParameter))
|
||||
is UastKotlinPsiParameter -> el<UParameter>(buildKt(original.ktParameter, ::KotlinUParameter))
|
||||
is UastKotlinPsiVariable -> el<UVariable>(buildKt(original.ktElement, ::KotlinUVariable))
|
||||
|
||||
is KtEnumEntry -> el<UEnumConstant> {
|
||||
convertEnumEntry(original, givenParent)
|
||||
}
|
||||
is KtClassOrObject -> el<UClass> {
|
||||
original.toLightClass()?.let { lightClass ->
|
||||
KotlinUClass.create(lightClass, givenParent)
|
||||
}
|
||||
}
|
||||
is KtFunction ->
|
||||
if (original.isLocal) {
|
||||
el<ULambdaExpression> {
|
||||
val parent = original.parent
|
||||
if (parent is KtLambdaExpression) {
|
||||
KotlinULambdaExpression(parent, givenParent) // your parent is the ULambdaExpression
|
||||
} else if (original.name.isNullOrEmpty()) {
|
||||
createLocalFunctionLambdaExpression(original, givenParent)
|
||||
}
|
||||
else {
|
||||
val uDeclarationsExpression = createLocalFunctionDeclaration(original, givenParent)
|
||||
val localFunctionVar = uDeclarationsExpression.declarations.single() as KotlinLocalFunctionUVariable
|
||||
localFunctionVar.uastInitializer
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
el<UMethod> {
|
||||
val lightMethod = LightClassUtil.getLightClassMethod(original)
|
||||
if (lightMethod != null)
|
||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
||||
else
|
||||
KotlinUMethodWithFakeLightDelegate(original, givenParent)
|
||||
}
|
||||
}
|
||||
|
||||
is KtPropertyAccessor -> el<UMethod> {
|
||||
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
|
||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
||||
}
|
||||
|
||||
is KtProperty ->
|
||||
if (original.isLocal) {
|
||||
KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
||||
}
|
||||
else {
|
||||
convertNonLocalProperty(original, givenParent, requiredType)
|
||||
}
|
||||
|
||||
is KtParameter -> el<UParameter> {
|
||||
val lightMethod = when (val ownerFunction = original.ownerFunction) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethod(ownerFunction)
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethod(ownerFunction)
|
||||
else -> null
|
||||
} ?: return null
|
||||
val lightParameter = lightMethod.parameterList.parameters.find { it.name == original.name } ?: return null
|
||||
KotlinUParameter(lightParameter, original, givenParent)
|
||||
}
|
||||
|
||||
is KtFile -> convertKtFile(original, givenParent, requiredType)
|
||||
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement) }
|
||||
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
||||
is KtCallExpression ->
|
||||
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
||||
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
|
||||
} else null
|
||||
is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, requiredType)
|
||||
is KtDelegatedSuperTypeEntry -> el<KotlinSupertypeDelegationUExpression> {
|
||||
KotlinSupertypeDelegationUExpression(original, givenParent)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun convertDeclarationOrElement(element: PsiElement, givenParent: UElement?, requiredType: Class<out UElement>?): UElement? {
|
||||
if (element is UElement) return element
|
||||
|
||||
if (element.isValid) {
|
||||
element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.get()?.let { cachedUElement ->
|
||||
return if (requiredType == null || requiredType.isInstance(cachedUElement)) cachedUElement else null
|
||||
}
|
||||
}
|
||||
|
||||
val uElement = convertDeclaration(element, givenParent, requiredType)
|
||||
?: KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
||||
/*
|
||||
if (uElement != null) {
|
||||
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, WeakReference(uElement))
|
||||
}
|
||||
*/
|
||||
return uElement
|
||||
}
|
||||
|
||||
private fun convertNonLocalProperty(
|
||||
property: KtProperty,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?
|
||||
): UElement? {
|
||||
val methods = LightClassUtil.getLightClassPropertyMethods(property)
|
||||
return methods.backingField?.let { backingField ->
|
||||
with(requiredType) {
|
||||
el<UField> { KotlinUField(backingField, (backingField as? KtLightElement<*, *>)?.kotlinOrigin, givenParent) }
|
||||
}
|
||||
} ?: methods.getter?.let { getter ->
|
||||
convertDeclaration(getter, givenParent, requiredType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertKtFile(
|
||||
element: KtFile,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?
|
||||
): UElement? {
|
||||
if (requiredType?.isAssignableFrom(KotlinUClass::class.java) == true)
|
||||
return element.findFacadeClass()?.let { KotlinUClass.create(it, givenParent) }
|
||||
if (requiredType?.isAssignableFrom(KotlinUFile::class.java) != false)
|
||||
return KotlinUFile(element)
|
||||
return null
|
||||
}
|
||||
|
||||
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
|
||||
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
|
||||
}
|
||||
|
||||
internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
|
||||
return if (expression != null) convertExpression(expression, parent, null) else null
|
||||
}
|
||||
|
||||
internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression =
|
||||
createAnalyzableProperty("val x = $text", context).initializer ?: error("Failed to create expression from text: '$text'")
|
||||
|
||||
internal fun KtPsiFactory.createAnalyzableProperty(text: String, context: PsiElement): KtProperty =
|
||||
createAnalyzableDeclaration(text, context)
|
||||
|
||||
internal fun <TDeclaration : KtDeclaration> KtPsiFactory.createAnalyzableDeclaration(text: String, context: PsiElement): TDeclaration {
|
||||
val file = createAnalyzableFile("dummy.kt", text, context)
|
||||
val declarations = file.declarations
|
||||
assert(declarations.size == 1) { "${declarations.size} declarations in $text" }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return declarations.first() as TDeclaration
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertVariablesDeclaration(
|
||||
psi: KtVariableDeclaration,
|
||||
parent: UElement?
|
||||
): UDeclarationsExpression {
|
||||
val declarationsExpression = parent as? KotlinUDeclarationsExpression
|
||||
?: psi.parent.toUElementOfType<UDeclarationsExpression>() as? KotlinUDeclarationsExpression
|
||||
?: KotlinUDeclarationsExpression(null, parent, psi)
|
||||
val parentPsiElement = parent?.javaPsi //TODO: looks weird. mb look for the first non-null `javaPsi` in `parents` ?
|
||||
val variable = KotlinUAnnotatedLocalVariable(
|
||||
UastKotlinPsiVariable.create(psi, parentPsiElement, declarationsExpression), psi, declarationsExpression) { annotationParent ->
|
||||
psi.annotationEntries.map { KotlinUAnnotation(it, annotationParent) }
|
||||
}
|
||||
return declarationsExpression.apply { declarations = listOf(variable) }
|
||||
}
|
||||
|
||||
val kotlinUastPlugin get() = UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin()
|
||||
@@ -1,386 +0,0 @@
|
||||
/*
|
||||
* 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.impl.light.LightPsiClassBuilder
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
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.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.internal.acceptList
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
|
||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
||||
import org.jetbrains.uast.visitor.UastVisitor
|
||||
|
||||
abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUElement(givenParent), UClassTypeSpecific, UAnchorOwner,
|
||||
JvmDeclarationUElementPlaceholder {
|
||||
|
||||
override val uastDeclarations by lz {
|
||||
mutableListOf<UDeclaration>().apply {
|
||||
addAll(fields)
|
||||
addAll(initializers)
|
||||
addAll(methods)
|
||||
addAll(innerClasses)
|
||||
}
|
||||
}
|
||||
|
||||
open val ktClass: KtClassOrObject? get() = (psi as? KtLightClass)?.kotlinOrigin
|
||||
|
||||
override val uastSuperTypes: List<UTypeReferenceExpression>
|
||||
get() = ktClass?.superTypeListEntries.orEmpty().mapNotNull { it.typeReference }.map {
|
||||
LazyKotlinUTypeReferenceExpression(it, this)
|
||||
}
|
||||
|
||||
val delegateExpressions: List<UExpression>
|
||||
get() = ktClass?.superTypeListEntries.orEmpty()
|
||||
.filterIsInstance<KtDelegatedSuperTypeEntry>()
|
||||
.map { KotlinSupertypeDelegationUExpression(it, this) }
|
||||
|
||||
override fun accept(visitor: UastVisitor) {
|
||||
if (visitor.visitClass(this)) return
|
||||
delegateExpressions.acceptList(visitor)
|
||||
annotations.acceptList(visitor)
|
||||
uastDeclarations.acceptList(visitor)
|
||||
visitor.afterVisitClass(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()
|
||||
|
||||
}
|
||||
|
||||
class KotlinSupertypeDelegationUExpression(override val sourcePsi: KtDelegatedSuperTypeEntry, givenParent: UElement?) :
|
||||
KotlinAbstractUExpression(givenParent), UExpressionList {
|
||||
|
||||
override val psi: PsiElement? get() = sourcePsi
|
||||
|
||||
val typeReference: UTypeReferenceExpression? by lazy {
|
||||
sourcePsi.typeReference?.let { KotlinUTypeReferenceExpression(it.toPsiType(this), it, this) }
|
||||
}
|
||||
|
||||
val delegateExpression: UExpression? by lazy {
|
||||
sourcePsi.delegateExpression?.let { kotlinUastPlugin.convertElement(it, this, UExpression::class.java) as? UExpression }
|
||||
}
|
||||
|
||||
override val expressions: List<UExpression>
|
||||
get() = listOfNotNull(typeReference, delegateExpression)
|
||||
|
||||
override val kind: UastSpecialExpressionKind get() = KotlinSpecialExpressionKinds.SUPER_DELEGATION
|
||||
|
||||
}
|
||||
|
||||
open class KotlinUClass private constructor(
|
||||
psi: KtLightClass,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
|
||||
final override 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 by lazy { getIdentifierSourcePsi()?.let { KotlinUIdentifier(nameIdentifier, it, this) } }
|
||||
|
||||
private fun getIdentifierSourcePsi(): PsiElement? {
|
||||
ktClass?.nameIdentifier?.let { return it }
|
||||
(ktClass as? KtObjectDeclaration)?.getObjectKeyword()?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
val result = ArrayList<UMethod>(javaPsi.methods.size)
|
||||
val handledKtDeclarations = mutableSetOf<PsiElement>()
|
||||
|
||||
for (lightMethod in javaPsi.methods) {
|
||||
if (isDelegatedMethod(lightMethod)) continue
|
||||
val uMethod = createUMethod(lightMethod)
|
||||
result.add(uMethod)
|
||||
handledKtDeclarations.addIfNotNull(uMethod.sourcePsi)
|
||||
}
|
||||
|
||||
val ktDeclarations: List<KtDeclaration> = run ktDeclarations@{
|
||||
ktClass?.let { return@ktDeclarations it.declarations }
|
||||
(javaPsi as? KtLightClassForFacade)?.let { facade ->
|
||||
return@ktDeclarations facade.files.flatMap { file -> file.declarations }
|
||||
}
|
||||
emptyList()
|
||||
}
|
||||
|
||||
ktDeclarations.asSequence()
|
||||
.filterNot { handledKtDeclarations.contains(it) }
|
||||
.mapNotNullTo(result) { KotlinConverter.convertDeclaration(it, this, null) as? UMethod }
|
||||
|
||||
return result.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, psi.kotlinOrigin, 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 uastAnchor: KotlinUIdentifier by lazy {
|
||||
KotlinUIdentifier(
|
||||
psi.nameIdentifier,
|
||||
if (isPrimary) ktClass?.nameIdentifier else (psi.kotlinOrigin as? KtSecondaryConstructor)?.getConstructorKeyword(),
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
override val javaPsi = psi
|
||||
|
||||
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? = ktClass
|
||||
|
||||
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 by lazy {
|
||||
val ktClassOrObject = (psi.originalElement as? KtLightClass)?.kotlinOrigin as? KtObjectDeclaration ?: return@lazy null
|
||||
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 by lazy { 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, psi.kotlinOrigin, givenParent) {
|
||||
override val uastBody: UExpression? by lz {
|
||||
val initializers = script.declarations.filterIsInstance<KtScriptInitializer>()
|
||||
KotlinUBlockExpression.create(initializers, this)
|
||||
}
|
||||
override val javaPsi = psi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of [UClass] for invalid code, when it is impossible to create a [KtLightClass]
|
||||
*/
|
||||
class KotlinInvalidUClass(
|
||||
override val psi: PsiClass,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
|
||||
constructor(name: String, context: PsiElement, givenParent: UElement?) : this(LightPsiClassBuilder(context, name), givenParent)
|
||||
|
||||
override fun getContainingFile(): PsiFile? = uastParent?.getContainingUFile()?.sourcePsi as? PsiFile
|
||||
|
||||
override val sourcePsi: PsiElement? get() = null
|
||||
|
||||
override val uastAnchor: UIdentifier? get() = null
|
||||
|
||||
override val javaPsi: PsiClass get() = psi
|
||||
|
||||
override fun getFields(): Array<UField> = emptyArray()
|
||||
|
||||
override fun getInitializers(): Array<UClassInitializer> = emptyArray()
|
||||
|
||||
override fun getInnerClasses(): Array<UClass> = emptyArray()
|
||||
|
||||
override fun getMethods(): Array<UMethod> = emptyArray()
|
||||
|
||||
override fun getSuperClass(): UClass? = null
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = null
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* 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.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder
|
||||
import com.intellij.psi.impl.light.LightModifierList
|
||||
import com.intellij.psi.impl.light.LightParameterListBuilder
|
||||
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.asJava.findFacadeClass
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
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: PsiMethod,
|
||||
final override val sourcePsi: KtDeclaration?,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUElement(givenParent), UMethodTypeSpecific, UAnchorOwner, JavaUElementWithComments, PsiMethod by psi {
|
||||
|
||||
constructor(psi: KtLightMethod, givenParent: UElement?) : this(psi, psi.kotlinOrigin, givenParent)
|
||||
|
||||
override val comments: List<UComment>
|
||||
get() = super<KotlinAbstractUElement>.comments
|
||||
|
||||
override val psi: PsiMethod = unwrap<UMethod, PsiMethod>(psi)
|
||||
|
||||
override val javaPsi = psi
|
||||
|
||||
override fun getSourceElement() = sourcePsi ?: this
|
||||
|
||||
private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi
|
||||
|
||||
override fun getContainingFile(): PsiFile? {
|
||||
kotlinOrigin?.containingFile?.let { return it }
|
||||
return unwrapFakeFileForLightClass(psi.containingFile)
|
||||
}
|
||||
|
||||
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
||||
|
||||
override val annotations: List<UAnnotation> 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 by lazy {
|
||||
KotlinUIdentifier(
|
||||
nameIdentifier,
|
||||
sourcePsi.let { sourcePsi ->
|
||||
when (sourcePsi) {
|
||||
is PsiNameIdentifierOwner -> sourcePsi.nameIdentifier
|
||||
is KtObjectDeclaration -> sourcePsi.getObjectKeyword()
|
||||
else -> sourcePsi?.navigationElement
|
||||
}
|
||||
},
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override val uastBody by lz {
|
||||
if (kotlinOrigin?.canAnalyze() != true) return@lz null // EA-137193
|
||||
val bodyExpression = when (kotlinOrigin) {
|
||||
is KtFunction -> kotlinOrigin.bodyExpression
|
||||
is KtProperty -> when {
|
||||
psi is KtLightMethod && psi.isGetter -> kotlinOrigin.getter?.bodyExpression
|
||||
psi is KtLightMethod && psi.isSetter -> kotlinOrigin.setter?.bodyExpression
|
||||
else -> null
|
||||
}
|
||||
else -> null
|
||||
} ?: return@lz null
|
||||
|
||||
wrapExpressionBody(this, bodyExpression)
|
||||
}
|
||||
|
||||
override val isOverride: Boolean
|
||||
get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false
|
||||
|
||||
|
||||
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
|
||||
|
||||
companion object {
|
||||
fun create(psi: KtLightMethod, containingElement: UElement?): KotlinUMethod {
|
||||
val kotlinOrigin = psi.kotlinOrigin
|
||||
return if (kotlinOrigin is KtConstructor<*>) {
|
||||
KotlinConstructorUMethod(
|
||||
kotlinOrigin.containingClassOrObject,
|
||||
psi,
|
||||
containingElement
|
||||
)
|
||||
} else if (kotlinOrigin is KtParameter && kotlinOrigin.getParentOfType<KtClass>(true)?.isAnnotation() == true)
|
||||
KotlinUAnnotationMethod(psi, containingElement)
|
||||
else
|
||||
KotlinUMethod(psi, containingElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class KotlinUAnnotationMethod(
|
||||
psi: KtLightMethod,
|
||||
givenParent: UElement?
|
||||
) : KotlinUMethod(psi, psi.kotlinOrigin, givenParent), UAnnotationMethod {
|
||||
|
||||
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
|
||||
|
||||
override val uastDefaultValue by lz {
|
||||
val annotationParameter = sourcePsi as? KtParameter ?: return@lz null
|
||||
val defaultValue = annotationParameter.defaultValue ?: return@lz null
|
||||
getLanguagePlugin().convertElement(defaultValue, this) as? UExpression
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun buildLightMethodFake(original: KtFunction): PsiMethod = object : LightMethodBuilder(
|
||||
original.manager, original.language, original.name,
|
||||
LightParameterListBuilder(original.manager, original.language),
|
||||
LightModifierList(original.manager)
|
||||
) {
|
||||
|
||||
init {
|
||||
containingClass = original.containingClassOrObject?.toLightClass() ?: original.containingKtFile.findFacadeClass()
|
||||
}
|
||||
|
||||
override fun getParent(): PsiElement? = containingClass
|
||||
}
|
||||
|
||||
class KotlinUMethodWithFakeLightDelegate(val original: KtFunction, givenParent: UElement?) :
|
||||
KotlinUMethod(buildLightMethodFake(original), original, givenParent) {
|
||||
override val annotations: List<UAnnotation>
|
||||
get() = original.annotationEntries.mapNotNull { it.toUElementOfType<UAnnotation>() }
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as KotlinUMethodWithFakeLightDelegate
|
||||
if (original != other.original) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = original.hashCode()
|
||||
}
|
||||
|
||||
internal fun wrapExpressionBody(function: UElement, bodyExpression: KtExpression): UExpression? = when (bodyExpression) {
|
||||
!is KtBlockExpression -> {
|
||||
KotlinUBlockExpression.KotlinLazyUBlockExpression(function) { block ->
|
||||
val implicitReturn = KotlinUImplicitReturnExpression(block)
|
||||
val uBody = function.getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression
|
||||
?: return@KotlinLazyUBlockExpression emptyList()
|
||||
listOf(implicitReturn.apply { returnExpression = uBody })
|
||||
}
|
||||
|
||||
}
|
||||
else -> function.getLanguagePlugin().convertElement(bodyExpression, function) as? UExpression
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
package org.jetbrains.uast.kotlin.evaluation
|
||||
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.uast.UBinaryExpression
|
||||
import org.jetbrains.uast.UastPostfixOperator
|
||||
import org.jetbrains.uast.evaluation.AbstractEvaluatorExtension
|
||||
import org.jetbrains.uast.evaluation.UEvaluationInfo
|
||||
import org.jetbrains.uast.evaluation.UEvaluationState
|
||||
import org.jetbrains.uast.kotlin.KotlinBinaryOperators
|
||||
import org.jetbrains.uast.kotlin.KotlinPostfixOperators
|
||||
import org.jetbrains.uast.values.*
|
||||
|
||||
class KotlinEvaluatorExtension : AbstractEvaluatorExtension(KotlinLanguage.INSTANCE) {
|
||||
|
||||
private data class Range(val from: UValue, val to: UValue) {
|
||||
override fun toString() = "$from..$to"
|
||||
}
|
||||
|
||||
private class UClosedRangeConstant(override val value: Range, override val source: UBinaryExpression?) : UAbstractConstant() {
|
||||
constructor(from: UValue, to: UValue, source: UBinaryExpression): this(Range(from, to), source)
|
||||
}
|
||||
|
||||
override fun evaluatePostfix(
|
||||
operator: UastPostfixOperator,
|
||||
operandValue: UValue,
|
||||
state: UEvaluationState
|
||||
): UEvaluationInfo {
|
||||
return when (operator) {
|
||||
KotlinPostfixOperators.EXCLEXCL -> when (operandValue.toConstant()) {
|
||||
UNullConstant -> UValue.UNREACHABLE
|
||||
is UConstant -> operandValue
|
||||
else -> UUndeterminedValue
|
||||
} to state
|
||||
else -> return super.evaluatePostfix(operator, operandValue, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun UValue.contains(value: UValue): UValue {
|
||||
val range = (this as? UClosedRangeConstant)?.value ?: return UUndeterminedValue
|
||||
return (value greaterOrEquals range.from) and (value lessOrEquals range.to)
|
||||
}
|
||||
|
||||
override fun evaluateBinary(
|
||||
binaryExpression: UBinaryExpression,
|
||||
leftValue: UValue,
|
||||
rightValue: UValue,
|
||||
state: UEvaluationState
|
||||
): UEvaluationInfo {
|
||||
return when (binaryExpression.operator) {
|
||||
KotlinBinaryOperators.IN -> rightValue.contains(leftValue)
|
||||
KotlinBinaryOperators.NOT_IN -> !rightValue.contains(leftValue)
|
||||
KotlinBinaryOperators.RANGE_TO -> UClosedRangeConstant(leftValue, rightValue, binaryExpression)
|
||||
else -> UUndeterminedValue
|
||||
} to state
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package org.jetbrains.uast.kotlin.expressions
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.CommonSupertypes
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.*
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
||||
|
||||
|
||||
private fun createVariableReferenceExpression(variable: UVariable, containingElement: UElement?) =
|
||||
object : USimpleNameReferenceExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override fun resolve(): PsiElement? = variable
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val resolvedName: String? = variable.name
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val identifier: String = variable.name.orAnonymous()
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
}
|
||||
|
||||
private fun createNullLiteralExpression(containingElement: UElement?) =
|
||||
object : ULiteralExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val value: Any? = null
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
}
|
||||
|
||||
private fun createNotEqWithNullExpression(variable: UVariable, containingElement: UElement?) =
|
||||
object : UBinaryExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val leftOperand: UExpression by lz { createVariableReferenceExpression(variable, this) }
|
||||
override val rightOperand: UExpression by lz { createNullLiteralExpression(this) }
|
||||
override val operator: UastBinaryOperator = UastBinaryOperator.NOT_EQUALS
|
||||
override val operatorIdentifier: UIdentifier? = KotlinUIdentifier(null, this)
|
||||
override fun resolveOperator(): PsiMethod? = null
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
}
|
||||
|
||||
private fun createElvisExpressions(
|
||||
left: KtExpression,
|
||||
right: KtExpression,
|
||||
containingElement: UElement?,
|
||||
psiParent: PsiElement): List<UExpression> {
|
||||
|
||||
val declaration = KotlinUDeclarationsExpression(containingElement)
|
||||
val tempVariable = KotlinULocalVariable(UastKotlinPsiVariable.create(left, declaration, psiParent), left, declaration)
|
||||
declaration.declarations = listOf(tempVariable)
|
||||
|
||||
val ifExpression = object : UIfExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
override val condition: UExpression by lz { createNotEqWithNullExpression(tempVariable, this) }
|
||||
override val thenExpression: UExpression? by lz { createVariableReferenceExpression(tempVariable, this) }
|
||||
override val elseExpression: UExpression? by lz { KotlinConverter.convertExpression(right, this ) }
|
||||
override val isTernary: Boolean = false
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val ifIdentifier: UIdentifier = KotlinUIdentifier(null, this)
|
||||
override val elseIdentifier: UIdentifier? = KotlinUIdentifier(null, this)
|
||||
}
|
||||
|
||||
return listOf(declaration, ifExpression)
|
||||
}
|
||||
|
||||
fun createElvisExpression(elvisExpression: KtBinaryExpression, givenParent: UElement?): UExpression {
|
||||
val left = elvisExpression.left ?: return UastEmptyExpression(givenParent)
|
||||
val right = elvisExpression.right ?: return UastEmptyExpression(givenParent)
|
||||
|
||||
return KotlinUElvisExpression(elvisExpression, left, right, givenParent)
|
||||
}
|
||||
|
||||
class KotlinUElvisExpression(
|
||||
private val elvisExpression: KtBinaryExpression,
|
||||
private val left: KtExpression,
|
||||
private val right: KtExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUElement(givenParent), UExpressionList, KotlinEvaluatableUElement {
|
||||
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = elvisExpression
|
||||
override val psi: PsiElement? = sourcePsi
|
||||
override val kind = KotlinSpecialExpressionKinds.ELVIS
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val expressions: List<UExpression> by lz {
|
||||
createElvisExpressions(left, right, this, elvisExpression.parent)
|
||||
}
|
||||
|
||||
val lhsDeclaration get() = (expressions[0] as UDeclarationsExpression).declarations.single()
|
||||
val rhsIfExpression get() = expressions[1] as UIfExpression
|
||||
|
||||
override fun asRenderString(): String {
|
||||
return kind.name + " " +
|
||||
expressions.joinToString(separator = "\n", prefix = "{\n", postfix = "\n}") {
|
||||
it.asRenderString().withMargin
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExpressionType(): PsiType? {
|
||||
val leftType = left.analyze()[BindingContext.EXPRESSION_TYPE_INFO, left]?.type ?: return null
|
||||
val rightType = right.analyze()[BindingContext.EXPRESSION_TYPE_INFO, right]?.type ?: return null
|
||||
|
||||
return CommonSupertypes
|
||||
.commonSupertype(listOf(leftType, rightType))
|
||||
.toPsiType(this, elvisExpression, boxed = false)
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.UPolyadicExpression
|
||||
import org.jetbrains.uast.UastBinaryOperator
|
||||
|
||||
class KotlinStringTemplateUPolyadicExpression(
|
||||
override val sourcePsi: KtStringTemplateExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent),
|
||||
UPolyadicExpression,
|
||||
KotlinUElementWithType,
|
||||
KotlinEvaluatableUElement {
|
||||
override val operands: List<UExpression> by lz { sourcePsi.entries.map { KotlinConverter.convertEntry(it, this)!! } }
|
||||
override val operator = UastBinaryOperator.PLUS
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.PsiNamedElement
|
||||
import com.intellij.psi.ResolveResult
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.uast.UCallableReferenceExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.UMultiResolvable
|
||||
import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
|
||||
|
||||
class KotlinUCallableReferenceExpression(
|
||||
override val sourcePsi: KtCallableReferenceExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, UMultiResolvable, KotlinUElementWithType {
|
||||
override val qualifierExpression: UExpression?
|
||||
get() {
|
||||
if (qualifierType != null) return null
|
||||
val receiverExpression = sourcePsi.receiverExpression ?: return null
|
||||
return KotlinConverter.convertExpression(receiverExpression, this)
|
||||
}
|
||||
|
||||
override val qualifierType by lz {
|
||||
val ktType = sourcePsi.analyze()[DOUBLE_COLON_LHS, sourcePsi.receiverExpression]?.type ?: return@lz null
|
||||
ktType.toPsiType(this, sourcePsi, boxed = true)
|
||||
}
|
||||
|
||||
override val callableName: String
|
||||
get() = sourcePsi.callableReference.getReferencedName()
|
||||
|
||||
override val resolvedName: String?
|
||||
get() = (resolve() as? PsiNamedElement)?.name
|
||||
|
||||
override fun resolve() = sourcePsi.callableReference.resolveCallToDeclaration()
|
||||
|
||||
override fun multiResolve(): Iterable<ResolveResult> = getResolveResultVariants(sourcePsi.callableReference)
|
||||
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.uast.UClassLiteralExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UExpression
|
||||
|
||||
class KotlinUClassLiteralExpression(
|
||||
override val sourcePsi: KtClassLiteralExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UClassLiteralExpression, KotlinUElementWithType {
|
||||
override val type by lz {
|
||||
val ktType = sourcePsi.analyze()[DOUBLE_COLON_LHS, sourcePsi.receiverExpression]?.type ?: return@lz null
|
||||
ktType.toPsiType(this, sourcePsi, boxed = true)
|
||||
}
|
||||
|
||||
override val expression: UExpression?
|
||||
get() {
|
||||
if (type != null) return null
|
||||
val receiverExpression = sourcePsi.receiverExpression ?: return null
|
||||
return KotlinConverter.convertExpression(receiverExpression, this)
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* 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.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.psi.KtObjectLiteralExpression
|
||||
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
|
||||
|
||||
class KotlinUObjectLiteralExpression(
|
||||
override val sourcePsi: KtObjectLiteralExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, UCallExpressionEx, DelegatedMultiResolve, KotlinUElementWithType {
|
||||
|
||||
override val declaration: UClass by lz {
|
||||
sourcePsi.objectDeclaration.toLightClass()
|
||||
?.let { getLanguagePlugin().convert<UClass>(it, this) }
|
||||
?: KotlinInvalidUClass("<invalid object code>", sourcePsi, this)
|
||||
}
|
||||
|
||||
override fun getExpressionType() = sourcePsi.objectDeclaration.toPsiType()
|
||||
|
||||
private val superClassConstructorCall by lz {
|
||||
sourcePsi.objectDeclaration.superTypeListEntries.firstOrNull { it is KtSuperTypeCallEntry } as? KtSuperTypeCallEntry
|
||||
}
|
||||
|
||||
override val classReference: UReferenceExpression? by lz { superClassConstructorCall?.let { ObjectLiteralClassReference(it, this) } }
|
||||
|
||||
override val valueArgumentCount: Int
|
||||
get() = superClassConstructorCall?.valueArguments?.size ?: 0
|
||||
|
||||
override val valueArguments by lz {
|
||||
val psi = superClassConstructorCall ?: return@lz emptyList<UExpression>()
|
||||
psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) }
|
||||
}
|
||||
|
||||
override val typeArgumentCount: Int
|
||||
get() = superClassConstructorCall?.typeArguments?.size ?: 0
|
||||
|
||||
override val typeArguments by lz {
|
||||
val psi = superClassConstructorCall ?: return@lz emptyList<PsiType>()
|
||||
psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) }
|
||||
}
|
||||
|
||||
override fun resolve() = superClassConstructorCall?.resolveCallToDeclaration() as? PsiMethod
|
||||
|
||||
override fun getArgumentForParameter(i: Int): UExpression? =
|
||||
superClassConstructorCall?.let { it.getResolvedCall(it.analyze()) }?.let { getArgumentExpressionByIndex(i, it, this) }
|
||||
|
||||
private class ObjectLiteralClassReference(
|
||||
override val sourcePsi: KtSuperTypeCallEntry,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUElement(givenParent), USimpleNameReferenceExpression {
|
||||
|
||||
override val javaPsi: PsiElement? get() = null
|
||||
override val psi: KtSuperTypeCallEntry get() = sourcePsi
|
||||
|
||||
override fun resolve() = (sourcePsi.resolveCallToDeclaration() as? PsiMethod)?.containingClass
|
||||
|
||||
override val annotations: List<UAnnotation>
|
||||
get() = emptyList()
|
||||
|
||||
override val resolvedName: String?
|
||||
get() = identifier
|
||||
|
||||
override val identifier: String
|
||||
get() = psi.name ?: "<error>"
|
||||
}
|
||||
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.PsiNamedElement
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UQualifiedReferenceExpression
|
||||
import org.jetbrains.uast.UastQualifiedExpressionAccessType
|
||||
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
|
||||
|
||||
class KotlinUQualifiedReferenceExpression(
|
||||
override val sourcePsi: KtDotQualifiedExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression, DelegatedMultiResolve,
|
||||
KotlinUElementWithType, KotlinEvaluatableUElement {
|
||||
override val receiver by lz { KotlinConverter.convertOrEmpty(sourcePsi.receiverExpression, this) }
|
||||
override val selector by lz { KotlinConverter.convertOrEmpty(sourcePsi.selectorExpression, this) }
|
||||
override val accessType = UastQualifiedExpressionAccessType.SIMPLE
|
||||
|
||||
override fun resolve() = sourcePsi.selectorExpression?.resolveCallToDeclaration()
|
||||
|
||||
override val resolvedName: String?
|
||||
get() = (resolve() as? PsiNamedElement)?.name
|
||||
}
|
||||
-261
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* 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.descriptors.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.internal.log
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
|
||||
import org.jetbrains.uast.visitor.UastVisitor
|
||||
|
||||
open class KotlinUSimpleReferenceExpression(
|
||||
override val sourcePsi: KtSimpleNameExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
|
||||
private val resolvedDeclaration: PsiElement? by lz {
|
||||
sourcePsi.resolveCallToDeclaration()?.let { return@lz it }
|
||||
|
||||
var declarationDescriptor = sourcePsi.analyze()[BindingContext.REFERENCE_TARGET, sourcePsi] ?: return@lz null
|
||||
if (declarationDescriptor is ImportedFromObjectCallableDescriptor<*>) {
|
||||
declarationDescriptor = declarationDescriptor.callableFromObject
|
||||
}
|
||||
if (declarationDescriptor is SyntheticJavaPropertyDescriptor) {
|
||||
declarationDescriptor = when (sourcePsi.readWriteAccess()) {
|
||||
ReferenceAccess.WRITE, ReferenceAccess.READ_WRITE ->
|
||||
declarationDescriptor.setMethod ?: declarationDescriptor.getMethod
|
||||
ReferenceAccess.READ -> declarationDescriptor.getMethod
|
||||
}
|
||||
}
|
||||
|
||||
if (declarationDescriptor is PackageViewDescriptor) {
|
||||
return@lz JavaPsiFacade.getInstance(sourcePsi.project).findPackage(declarationDescriptor.fqName.asString())
|
||||
}
|
||||
|
||||
resolveToPsiClass(this, declarationDescriptor, sourcePsi)?.let { return@lz it }
|
||||
if (declarationDescriptor is DeclarationDescriptorWithSource) {
|
||||
declarationDescriptor.source.getPsi()?.let { it.getMaybeLightElement() ?: it }?.let { return@lz it }
|
||||
}
|
||||
return@lz resolveDeserialized(sourcePsi, declarationDescriptor, sourcePsi.readWriteAccess())
|
||||
}
|
||||
|
||||
override val identifier get() = sourcePsi.getReferencedName()
|
||||
|
||||
override fun resolve() = resolvedDeclaration
|
||||
|
||||
override val resolvedName: String?
|
||||
get() = (resolvedDeclaration as? PsiNamedElement)?.name
|
||||
|
||||
override fun accept(visitor: UastVisitor) {
|
||||
visitor.visitSimpleNameReferenceExpression(this)
|
||||
|
||||
if (sourcePsi.parent.destructuringDeclarationInitializer != true) {
|
||||
visitAccessorCalls(visitor)
|
||||
}
|
||||
|
||||
visitor.afterVisitSimpleNameReferenceExpression(this)
|
||||
}
|
||||
|
||||
private fun visitAccessorCalls(visitor: UastVisitor) {
|
||||
// Visit Kotlin get-set synthetic Java property calls as function calls
|
||||
val bindingContext = sourcePsi.analyze()
|
||||
val access = sourcePsi.readWriteAccess()
|
||||
val resolvedCall = sourcePsi.getResolvedCall(bindingContext)
|
||||
val resultingDescriptor = resolvedCall?.resultingDescriptor as? SyntheticJavaPropertyDescriptor
|
||||
if (resultingDescriptor != null) {
|
||||
val setterValue = if (access.isWrite) {
|
||||
findAssignment(sourcePsi, sourcePsi.parent)?.right ?: run {
|
||||
visitor.afterVisitSimpleNameReferenceExpression(this)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (resolvedCall != null) {
|
||||
if (access.isRead) {
|
||||
val getDescriptor = resultingDescriptor.getMethod
|
||||
KotlinAccessorCallExpression(sourcePsi, this, resolvedCall, getDescriptor, null).accept(visitor)
|
||||
}
|
||||
|
||||
if (access.isWrite && setterValue != null) {
|
||||
val setDescriptor = resultingDescriptor.setMethod
|
||||
if (setDescriptor != null) {
|
||||
KotlinAccessorCallExpression(sourcePsi, this, resolvedCall, setDescriptor, setterValue).accept(visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun findAssignment(prev: PsiElement?, element: PsiElement?): KtBinaryExpression? = when (element) {
|
||||
is KtBinaryExpression -> if (element.left == prev && element.operationToken == KtTokens.EQ) element else null
|
||||
is KtQualifiedExpression -> findAssignment(element, element.parent)
|
||||
is KtSimpleNameExpression -> findAssignment(element, element.parent)
|
||||
else -> null
|
||||
}
|
||||
|
||||
class KotlinAccessorCallExpression(
|
||||
override val sourcePsi: KtSimpleNameExpression,
|
||||
override val uastParent: KotlinUSimpleReferenceExpression,
|
||||
private val resolvedCall: ResolvedCall<*>,
|
||||
private val accessorDescriptor: DeclarationDescriptor,
|
||||
val setterValue: KtExpression?
|
||||
) : UCallExpressionEx, DelegatedMultiResolve, JvmDeclarationUElementPlaceholder {
|
||||
override val methodName: String?
|
||||
get() = accessorDescriptor.name.asString()
|
||||
|
||||
override val receiver: UExpression?
|
||||
get() {
|
||||
val containingElement = uastParent.uastParent
|
||||
return if (containingElement is UQualifiedReferenceExpression && containingElement.selector == this)
|
||||
containingElement.receiver
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
override val javaPsi: PsiElement? get() = null
|
||||
override val psi: PsiElement? get() = sourcePsi
|
||||
|
||||
override val annotations: List<UAnnotation>
|
||||
get() = emptyList()
|
||||
|
||||
override val receiverType by lz {
|
||||
val type = (resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver)?.type ?: return@lz null
|
||||
type.toPsiType(this, sourcePsi, boxed = true)
|
||||
}
|
||||
|
||||
override val methodIdentifier: UIdentifier? by lazy { KotlinUIdentifier(sourcePsi.getReferencedNameElement(), this) }
|
||||
|
||||
override val classReference: UReferenceExpression?
|
||||
get() = null
|
||||
|
||||
override val valueArgumentCount: Int
|
||||
get() = if (setterValue != null) 1 else 0
|
||||
|
||||
override val valueArguments by lz {
|
||||
if (setterValue != null)
|
||||
listOf(KotlinConverter.convertOrEmpty(setterValue, this))
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
|
||||
override fun getArgumentForParameter(i: Int): UExpression? = valueArguments.getOrNull(i)
|
||||
|
||||
override val typeArgumentCount: Int
|
||||
get() = resolvedCall.typeArguments.size
|
||||
|
||||
override val typeArguments by lz {
|
||||
resolvedCall.typeArguments.values.map { it.toPsiType(this, sourcePsi, true) }
|
||||
}
|
||||
|
||||
override val returnType by lz {
|
||||
(accessorDescriptor as? CallableDescriptor)?.returnType?.toPsiType(this, sourcePsi, boxed = false)
|
||||
}
|
||||
|
||||
override val kind: UastCallKind
|
||||
get() = UastCallKind.METHOD_CALL
|
||||
|
||||
override fun resolve(): PsiMethod? {
|
||||
val source = accessorDescriptor.toSource()
|
||||
return resolveSource(sourcePsi, accessorDescriptor, source)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtExpression.readWriteAccess(): ReferenceAccess {
|
||||
var expression = getQualifiedExpressionForSelectorOrThis()
|
||||
loop@ while (true) {
|
||||
val parent = expression.parent
|
||||
when (parent) {
|
||||
is KtParenthesizedExpression, is KtAnnotatedExpression, is KtLabeledExpression -> expression = parent as KtExpression
|
||||
else -> break@loop
|
||||
}
|
||||
}
|
||||
|
||||
val assignment = expression.getAssignmentByLHS()
|
||||
if (assignment != null) {
|
||||
return when (assignment.operationToken) {
|
||||
KtTokens.EQ -> ReferenceAccess.WRITE
|
||||
else -> ReferenceAccess.READ_WRITE
|
||||
}
|
||||
}
|
||||
|
||||
return if ((expression.parent as? KtUnaryExpression)?.operationToken
|
||||
in constant { setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) }
|
||||
)
|
||||
ReferenceAccess.READ_WRITE
|
||||
else
|
||||
ReferenceAccess.READ
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinClassViaConstructorUSimpleReferenceExpression(
|
||||
override val sourcePsi: KtCallElement,
|
||||
override val identifier: String,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType {
|
||||
override val resolvedName: String?
|
||||
get() = (resolved as? PsiNamedElement)?.name
|
||||
|
||||
private val resolved by lazy {
|
||||
when (val resultingDescriptor = sourcePsi.getResolvedCall(sourcePsi.analyze())?.descriptorForResolveViaConstructor()) {
|
||||
is ConstructorDescriptor -> {
|
||||
resultingDescriptor.constructedClass.toSource()?.getMaybeLightElement()
|
||||
?: (resultingDescriptor as? DeserializedCallableMemberDescriptor)?.let { resolveContainingDeserializedClass(sourcePsi, it) }
|
||||
}
|
||||
is SamConstructorDescriptor ->
|
||||
(resultingDescriptor.returnType?.getFunctionalInterfaceType(this, sourcePsi) as? PsiClassType)?.resolve()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolve(): PsiElement? = resolved
|
||||
|
||||
override fun asLogString(): String = log<USimpleNameReferenceExpression>("identifier = $identifier, resolvesTo = $resolvedName")
|
||||
|
||||
// In new inference, SAM constructor is substituted with a function descriptor, so we use candidate descriptor to preserve behavior
|
||||
private fun ResolvedCall<*>.descriptorForResolveViaConstructor(): CallableDescriptor? {
|
||||
return if (this is NewResolvedCallImpl) candidateDescriptor else resultingDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinStringUSimpleReferenceExpression(
|
||||
override val identifier: String,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression {
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
|
||||
override fun resolve() = null
|
||||
override val resolvedName: String?
|
||||
get() = identifier
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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.PsiElement
|
||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||
import org.jetbrains.kotlin.psi.KtWhenEntry
|
||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
||||
|
||||
class KotlinUSwitchExpression(
|
||||
override val sourcePsi: KtWhenExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USwitchExpression, KotlinUElementWithType {
|
||||
override val expression by lz { KotlinConverter.convertOrNull(sourcePsi.subjectExpression, this) }
|
||||
|
||||
override val body: UExpressionList by lz {
|
||||
object : KotlinUExpressionList(sourcePsi, KotlinSpecialExpressionKinds.WHEN, this@KotlinUSwitchExpression) {
|
||||
override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin }
|
||||
}.apply {
|
||||
expressions = this@KotlinUSwitchExpression.sourcePsi.entries.map { KotlinUSwitchEntry(it, this) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun asRenderString() = buildString {
|
||||
val expr = expression?.let { "(" + it.asRenderString() + ") " } ?: ""
|
||||
appendln("switch $expr {")
|
||||
appendln(body.asRenderString())
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
override val switchIdentifier: UIdentifier
|
||||
get() = KotlinUIdentifier(null, this)
|
||||
}
|
||||
|
||||
class KotlinUSwitchEntry(
|
||||
override val sourcePsi: KtWhenEntry,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
|
||||
override val caseValues by lz {
|
||||
sourcePsi.conditions.map { KotlinConverter.convertWhenCondition(it, this) ?: UastEmptyExpression }
|
||||
}
|
||||
|
||||
override val body: UExpressionList by lz {
|
||||
object : KotlinUExpressionList(sourcePsi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this@KotlinUSwitchEntry) {
|
||||
override fun asRenderString() = buildString {
|
||||
appendln("{")
|
||||
expressions.forEach { appendln(it.asRenderString().withMargin) }
|
||||
appendln("}")
|
||||
}
|
||||
}.apply {
|
||||
val exprPsi = this@KotlinUSwitchEntry.sourcePsi.expression
|
||||
val userExpressions = when (exprPsi) {
|
||||
is KtBlockExpression -> exprPsi.statements.map { KotlinConverter.convertOrEmpty(it, this) }
|
||||
else -> listOf(KotlinConverter.convertOrEmpty(exprPsi, this))
|
||||
}
|
||||
expressions = userExpressions + object : UBreakExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
override val label: String?
|
||||
get() = null
|
||||
override val uastParent: UElement?
|
||||
get() = this@KotlinUSwitchEntry
|
||||
override val annotations: List<UAnnotation>
|
||||
get() = emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertParent(): UElement? {
|
||||
val result = KotlinConverter.unwrapElements(sourcePsi.parent)?.let { parentUnwrapped ->
|
||||
KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
||||
}
|
||||
return (result as? KotlinUSwitchExpression)?.body ?: result
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.psi.KtTryExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UIdentifier
|
||||
import org.jetbrains.uast.UTryExpression
|
||||
import org.jetbrains.uast.UVariable
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
|
||||
class KotlinUTryExpression(
|
||||
override val sourcePsi: KtTryExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UTryExpression, KotlinUElementWithType {
|
||||
override val tryClause by lz { KotlinConverter.convertOrEmpty(sourcePsi.tryBlock, this) }
|
||||
override val catchClauses by lz { sourcePsi.catchClauses.map { KotlinUCatchClause(it, this) } }
|
||||
override val finallyClause by lz { sourcePsi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, this) } }
|
||||
|
||||
override val resourceVariables: List<UVariable>
|
||||
get() = emptyList()
|
||||
|
||||
override val hasResources: Boolean
|
||||
get() = false
|
||||
|
||||
override val tryIdentifier: UIdentifier
|
||||
get() = KotlinUIdentifier(null, this)
|
||||
|
||||
override val finallyIdentifier: UIdentifier?
|
||||
get() = null
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
Test -> UAnnotation (fqName = null)
|
||||
A -> UClass (name = A)
|
||||
MyAnnotation -> UClass (name = MyAnnotation)
|
||||
text -> [!] UnknownKotlinExpression (VALUE_PARAMETER)
|
||||
String -> USimpleNameReferenceExpression (identifier = String)
|
||||
MyAnnotation -> UAnnotation (fqName = MyAnnotation)
|
||||
B -> UClass (name = B)
|
||||
MyAnnotation -> UAnnotation (fqName = MyAnnotation)
|
||||
InB -> UClass (name = InB)
|
||||
MyAnnotation -> UAnnotation (fqName = MyAnnotation)
|
||||
object -> UClass (name = Companion)
|
||||
MyAnnotation -> UAnnotation (fqName = MyAnnotation)
|
||||
Obj -> UClass (name = Obj)
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import org.jetbrains.uast.test.common.kotlin.IdentifiersTestBase
|
||||
import java.io.File
|
||||
|
||||
|
||||
abstract class AbstractKotlinIdentifiersTest : AbstractKotlinUastTest(), IdentifiersTestBase {
|
||||
|
||||
private fun getTestFile(testName: String, ext: String) =
|
||||
File(File(AbstractKotlinUastTest.TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext)
|
||||
|
||||
override fun getIdentifiersFile(testName: String): File = getTestFile(testName, "identifiers.txt")
|
||||
|
||||
|
||||
}
|
||||
@@ -1,587 +0,0 @@
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import com.intellij.psi.PsiAnnotation
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.testFramework.RunAll
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
||||
import org.jetbrains.uast.test.env.kotlin.findElementByText
|
||||
import org.jetbrains.uast.test.env.kotlin.findElementByTextFromPsi
|
||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import kotlin.test.fail as kfail
|
||||
|
||||
|
||||
class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
override fun check(testName: String, file: UFile) {
|
||||
}
|
||||
|
||||
@Test fun testAnnotationParameters() {
|
||||
doTest("AnnotationParameters") { _, file ->
|
||||
val annotation = file.findElementByText<UAnnotation>("@IntRange(from = 10, to = 0)")
|
||||
assertEquals(annotation.findAttributeValue("from")?.evaluate(), 10)
|
||||
val toAttribute = annotation.findAttributeValue("to")!!
|
||||
assertEquals(toAttribute.evaluate(), 0)
|
||||
KtUsefulTestCase.assertInstanceOf(annotation.psi.toUElement(), UAnnotation::class.java)
|
||||
KtUsefulTestCase.assertInstanceOf(
|
||||
annotation.psi.cast<KtAnnotationEntry>().toLightAnnotation().toUElement(),
|
||||
UAnnotation::class.java
|
||||
)
|
||||
KtUsefulTestCase.assertInstanceOf(toAttribute.uastParent, UNamedExpression::class.java)
|
||||
KtUsefulTestCase.assertInstanceOf(toAttribute.psi.toUElement()?.uastParent, UNamedExpression::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testConvertStringTemplate() {
|
||||
doTest("StringTemplateInClass") { _, file ->
|
||||
val literalExpression = file.findElementByText<ULiteralExpression>("lorem")
|
||||
val psi = literalExpression.psi!!
|
||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
||||
val literalExpressionAgain = psi.toUElement()
|
||||
Assert.assertTrue(literalExpressionAgain is ULiteralExpression)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testConvertStringTemplateWithExpectedType() {
|
||||
doTest("StringTemplateWithVar") { _, file ->
|
||||
val index = file.psi.text.indexOf("foo")
|
||||
val stringTemplate = file.psi.findElementAt(index)!!.getParentOfType<KtStringTemplateExpression>(false)
|
||||
val uLiteral = stringTemplate.toUElementOfType<ULiteralExpression>()
|
||||
assertNull(uLiteral)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testNameContainingFile() {
|
||||
doTest("NameContainingFile") { _, file ->
|
||||
val foo = file.findElementByText<UClass>("class Foo")
|
||||
assertEquals(file.psi, foo.nameIdentifier!!.containingFile)
|
||||
|
||||
val bar = file.findElementByText<UMethod>("fun bar() {}")
|
||||
assertEquals(file.psi, bar.nameIdentifier!!.containingFile)
|
||||
|
||||
val xyzzy = file.findElementByText<UVariable>("val xyzzy: Int = 0")
|
||||
assertEquals(file.psi, xyzzy.nameIdentifier!!.containingFile)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testInterfaceMethodWithBody() {
|
||||
doTest("DefaultImpls") { _, file ->
|
||||
val bar = file.findElementByText<UMethod>("fun bar() = \"Hello!\"")
|
||||
assertFalse(bar.containingFile.text!!, bar.psi.modifierList.hasExplicitModifier(PsiModifier.DEFAULT))
|
||||
assertTrue(bar.containingFile.text!!, bar.psi.modifierList.hasModifierProperty(PsiModifier.DEFAULT))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSAM() {
|
||||
doTest("SAM") { _, file ->
|
||||
runAll(
|
||||
{ assertNull(file.findElementByText<ULambdaExpression>("{ /* Not SAM */ }").functionalInterfaceType) }, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{/* Variable */}").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{/* Assignment */}").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{/* Type Cast */}").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{/* Argument */}").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{/* Return */}").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{ /* SAM */ }").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{ println(\"hello1\") }").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
file.findElementByText<ULambdaExpression>("{ println(\"hello2\") }").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
val call = file.findElementByText<UCallExpression>("Runnable { println(\"hello2\") }")
|
||||
assertEquals(
|
||||
"java.lang.Runnable",
|
||||
(call.classReference?.resolve() as? PsiClass)?.qualifiedName
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.util.function.Supplier<T>",
|
||||
file.findElementByText<ULambdaExpression>("{ \"Supplier\" }").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}, {
|
||||
assertEquals(
|
||||
"java.util.concurrent.Callable<V>",
|
||||
file.findElementByText<ULambdaExpression>("{ \"Callable\" }").functionalInterfaceType?.canonicalText
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testParameterPropertyWithAnnotation() {
|
||||
doTest("ParameterPropertyWithAnnotation") { _, file ->
|
||||
val test1 = file.classes.find { it.name == "Test1" }!!
|
||||
|
||||
val constructor1 = test1.methods.find { it.name == "Test1" }!!
|
||||
assertTrue(constructor1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" })
|
||||
|
||||
val getter1 = test1.methods.find { it.name == "getBar" }!!
|
||||
assertFalse(getter1.annotations.any { it.qualifiedName == "MyAnnotation" })
|
||||
|
||||
val setter1 = test1.methods.find { it.name == "setBar" }!!
|
||||
assertFalse(setter1.annotations.any { it.qualifiedName == "MyAnnotation" })
|
||||
assertFalse(setter1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" })
|
||||
|
||||
|
||||
val test2 = file.classes.find { it.name == "Test2" }!!
|
||||
val constructor2 = test2.methods.find { it.name == "Test2" }!!
|
||||
assertFalse(constructor2.uastParameters.first().annotations.any { it.qualifiedName?.startsWith("MyAnnotation") ?: false })
|
||||
|
||||
val getter2 = test2.methods.find { it.name == "getBar" }!!
|
||||
getter2.annotations.single { it.qualifiedName == "MyAnnotation" }
|
||||
|
||||
val setter2 = test2.methods.find { it.name == "setBar" }!!
|
||||
setter2.annotations.single { it.qualifiedName == "MyAnnotation2" }
|
||||
setter2.uastParameters.first().annotations.single { it.qualifiedName == "MyAnnotation3" }
|
||||
|
||||
test2.fields.find { it.name == "bar" }!!.annotations.single { it.qualifiedName == "MyAnnotation5" }
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testConvertTypeInAnnotation() {
|
||||
doTest("TypeInAnnotation") { _, file ->
|
||||
val index = file.psi.text.indexOf("Test")
|
||||
val element = file.psi.findElementAt(index)!!.getParentOfType<KtUserType>(false)!!
|
||||
assertNotNull(element.getUastParentOfType(UAnnotation::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testElvisType() {
|
||||
doTest("ElvisType") { _, file ->
|
||||
val elvisExpression = file.findElementByText<UExpression>("text ?: return")
|
||||
assertEquals("String", elvisExpression.getExpressionType()!!.presentableText)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testFindAttributeDefaultValue() {
|
||||
doTest("AnnotationParameters") { _, file ->
|
||||
val witDefaultValue = file.findElementByText<UAnnotation>("@WithDefaultValue")
|
||||
assertEquals(42, witDefaultValue.findAttributeValue("value")!!.evaluate())
|
||||
assertEquals(42, witDefaultValue.findAttributeValue(null)!!.evaluate())
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testIfCondition() {
|
||||
doTest("IfStatement") { _, file ->
|
||||
val psiFile = file.psi
|
||||
val element = psiFile.findElementAt(psiFile.text.indexOf("\"abc\""))!!
|
||||
val binaryExpression = element.getParentOfType<KtBinaryExpression>(false)!!
|
||||
val uBinaryExpression = KotlinUastLanguagePlugin().convertElementWithParent(binaryExpression, null)!!
|
||||
UsefulTestCase.assertInstanceOf(uBinaryExpression.uastParent, UIfExpression::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testWhenStringLiteral() {
|
||||
doTest("WhenStringLiteral") { _, file ->
|
||||
|
||||
file.findElementByTextFromPsi<ULiteralExpression>("abc").let { literalExpression ->
|
||||
val psi = literalExpression.psi!!
|
||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
||||
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java)
|
||||
}
|
||||
|
||||
file.findElementByTextFromPsi<ULiteralExpression>("def").let { literalExpression ->
|
||||
val psi = literalExpression.psi!!
|
||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
||||
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java)
|
||||
}
|
||||
|
||||
file.findElementByTextFromPsi<ULiteralExpression>("def1").let { literalExpression ->
|
||||
val psi = literalExpression.psi!!
|
||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
||||
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, UBlockExpression::class.java)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testWhenAndDestructing() {
|
||||
doTest("WhenAndDestructing") { _, file ->
|
||||
|
||||
file.findElementByTextFromPsi<UExpression>("val (bindingContext, statementFilter) = arr").let { e ->
|
||||
val uBlockExpression = e.getParentOfType<UBlockExpression>()
|
||||
Assert.assertNotNull(uBlockExpression)
|
||||
val uMethod = uBlockExpression!!.getParentOfType<UMethod>()
|
||||
Assert.assertNotNull(uMethod)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBrokenMethodTypeResolve() {
|
||||
doTest("BrokenMethod") { _, file ->
|
||||
|
||||
file.accept(object : AbstractUastVisitor() {
|
||||
override fun visitCallExpression(node: UCallExpression): Boolean {
|
||||
node.returnType
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimpleAnnotated() {
|
||||
doTest("SimpleAnnotated") { _, file ->
|
||||
file.findElementByTextFromPsi<UField>("@kotlin.SinceKotlin(\"1.0\")\n val property: String = \"Mary\"").let { field ->
|
||||
val annotation = field.annotations.assertedFind("kotlin.SinceKotlin") { it.qualifiedName }
|
||||
Assert.assertEquals("1.0", annotation.findDeclaredAttributeValue("version")?.evaluateString())
|
||||
Assert.assertEquals("SinceKotlin", annotation.cast<UAnchorOwner>().uastAnchor?.sourcePsi?.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun UFile.checkUastSuperTypes(refText: String, superTypes: List<String>) {
|
||||
findElementByTextFromPsi<UClass>(refText, false).let {
|
||||
assertEquals("base classes", superTypes, it.uastSuperTypes.map { it.getQualifiedName() })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testSuperTypes() {
|
||||
doTest("SuperCalls") { _, file ->
|
||||
file.checkUastSuperTypes("B", listOf("A"))
|
||||
file.checkUastSuperTypes("O", listOf("A"))
|
||||
file.checkUastSuperTypes("innerObject ", listOf("A"))
|
||||
file.checkUastSuperTypes("InnerClass", listOf("A"))
|
||||
file.checkUastSuperTypes("object : A(\"textForAnon\")", listOf("A"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAnonymousSuperTypes() {
|
||||
doTest("Anonymous") { _, file ->
|
||||
file.checkUastSuperTypes("object : Runnable { override fun run() {} }", listOf("java.lang.Runnable"))
|
||||
file.checkUastSuperTypes(
|
||||
"object : Runnable, Closeable { override fun close() {} override fun run() {} }",
|
||||
listOf("java.lang.Runnable", "java.io.Closeable")
|
||||
)
|
||||
file.checkUastSuperTypes(
|
||||
"object : InputStream(), Runnable { override fun read(): Int = 0; override fun run() {} }",
|
||||
listOf("java.io.InputStream", "java.lang.Runnable")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLiteralArraysTypes() {
|
||||
doTest("AnnotationParameters") { _, file ->
|
||||
file.findElementByTextFromPsi<UCallExpression>("intArrayOf(1, 2, 3)").let { field ->
|
||||
Assert.assertEquals("PsiType:int[]", field.returnType.toString())
|
||||
}
|
||||
file.findElementByTextFromPsi<UCallExpression>("[1, 2, 3]").let { field ->
|
||||
Assert.assertEquals("PsiType:int[]", field.returnType.toString())
|
||||
Assert.assertEquals("PsiType:int", field.typeArguments.single().toString())
|
||||
}
|
||||
file.findElementByTextFromPsi<UCallExpression>("[\"a\", \"b\", \"c\"]").let { field ->
|
||||
Assert.assertEquals("PsiType:String[]", field.returnType.toString())
|
||||
Assert.assertEquals("PsiType:String", field.typeArguments.single().toString())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTypeAliases() {
|
||||
doTest("TypeAliases") { _, file ->
|
||||
val g = (file.psi as KtFile).declarations.single { it.name == "G" } as KtTypeAlias
|
||||
val originalType = g.getTypeReference()!!.typeElement as KtFunctionType
|
||||
val originalTypeParameters = originalType.parameterList.toUElement() as UDeclarationsExpression
|
||||
Assert.assertTrue((originalTypeParameters.declarations.single() as UParameter).type.isValid)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
|
||||
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation(\"sv1\", \"sv2\"))")
|
||||
.findElementByTextFromPsi<UElement>("Annotation(\"sv1\", \"sv2\")")
|
||||
.sourcePsiElement
|
||||
.let { referenceExpression ->
|
||||
val convertedUAnnotation = referenceExpression
|
||||
.cast<KtReferenceExpression>()
|
||||
.toUElementOfType<UAnnotation>()
|
||||
?: throw AssertionError("haven't got annotation from $referenceExpression(${referenceExpression?.javaClass})")
|
||||
|
||||
checkDescriptorsLeak(convertedUAnnotation)
|
||||
assertEquals("Annotation", convertedUAnnotation.qualifiedName)
|
||||
val lightAnnotation = convertedUAnnotation.getAsJavaPsiElement(PsiAnnotation::class.java)
|
||||
?: throw AssertionError("can't get lightAnnotation from $convertedUAnnotation")
|
||||
assertEquals("Annotation", lightAnnotation.qualifiedName)
|
||||
assertEquals("Annotation", (convertedUAnnotation as UAnchorOwner).uastAnchor?.sourcePsi?.text)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNestedAnnotationParameters() = doTest("AnnotationComplex") { _, file ->
|
||||
|
||||
fun UFile.annotationAndParam(refText: String, check: (PsiAnnotation, String?) -> Unit) {
|
||||
findElementByTextFromPsi<UElement>(refText)
|
||||
.let { expression ->
|
||||
val (annotation: PsiAnnotation, paramname: String?) =
|
||||
getContainingAnnotationEntry(expression) ?: kfail("annotation not found for '$refText' ($expression)")
|
||||
check(annotation, paramname)
|
||||
}
|
||||
}
|
||||
|
||||
file.annotationAndParam("sv1") { annotation, paramname ->
|
||||
assertEquals("Annotation", annotation.qualifiedName)
|
||||
assertEquals(null, paramname)
|
||||
}
|
||||
file.annotationAndParam("sv2") { annotation, paramname ->
|
||||
assertEquals("Annotation", annotation.qualifiedName)
|
||||
assertEquals(null, paramname)
|
||||
}
|
||||
file.annotationAndParam("sar1") { annotation, paramname ->
|
||||
assertEquals("Annotation", annotation.qualifiedName)
|
||||
assertEquals("strings", paramname)
|
||||
}
|
||||
file.annotationAndParam("sar2") { annotation, paramname ->
|
||||
assertEquals("Annotation", annotation.qualifiedName)
|
||||
assertEquals("strings", paramname)
|
||||
}
|
||||
file.annotationAndParam("[sar]1") { annotation, paramname ->
|
||||
assertEquals("Annotation", annotation.qualifiedName)
|
||||
assertEquals("strings", paramname)
|
||||
}
|
||||
file.annotationAndParam("[sar]2") { annotation, paramname ->
|
||||
assertEquals("Annotation", annotation.qualifiedName)
|
||||
assertEquals("strings", paramname)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testParametersDisorder() = doTest("ParametersDisorder") { _, file ->
|
||||
|
||||
fun assertArguments(argumentsInPositionalOrder: List<String?>?, refText: String) =
|
||||
file.findElementByTextFromPsi<UCallExpression>(refText).let { call ->
|
||||
if (call !is UCallExpressionEx) throw AssertionError("${call.javaClass} is not a UCallExpressionEx")
|
||||
Assert.assertEquals(
|
||||
argumentsInPositionalOrder,
|
||||
call.resolve()?.let { psiMethod ->
|
||||
(0 until psiMethod.parameterList.parametersCount).map {
|
||||
call.getArgumentForParameter(it)?.asRenderString()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
assertArguments(listOf("2", "2.2"), "global(b = 2.2F, a = 2)")
|
||||
assertArguments(listOf(null, "\"bbb\""), "withDefault(d = \"bbb\")")
|
||||
assertArguments(listOf("1.3", "3.4"), "atan2(1.3, 3.4)")
|
||||
assertArguments(null, "unresolvedMethod(\"param1\", \"param2\")")
|
||||
assertArguments(listOf("\"%i %i %i\"", "varargs 1 : 2 : 3"), "format(\"%i %i %i\", 1, 2, 3)")
|
||||
assertArguments(listOf("\"%i %i %i\"", "varargs arrayOf(1, 2, 3)"), "format(\"%i %i %i\", arrayOf(1, 2, 3))")
|
||||
assertArguments(
|
||||
listOf("\"%i %i %i\"", "varargs arrayOf(1, 2, 3) : arrayOf(4, 5, 6)"),
|
||||
"format(\"%i %i %i\", arrayOf(1, 2, 3), arrayOf(4, 5, 6))"
|
||||
)
|
||||
assertArguments(listOf("\"%i %i %i\"", "\"\".chunked(2).toTypedArray()"), "format(\"%i %i %i\", *\"\".chunked(2).toTypedArray())")
|
||||
assertArguments(listOf("\"def\"", "8", "7.0"), "with2Receivers(8, 7.0F)")
|
||||
assertArguments(listOf("\"foo\"", "1"), "object : Parent(b = 1, a = \"foo\")\n")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolvedDeserializedMethod() = doTest("Resolve") { _, file ->
|
||||
|
||||
fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) {
|
||||
this.findElementByTextFromPsi<UCallExpression>(callText).let {
|
||||
val resolve = it.resolve().sure { "resolving '$callText'" }
|
||||
assertEquals(methodName, resolve.name)
|
||||
}
|
||||
}
|
||||
|
||||
file.findElementByTextFromPsi<UElement>("bar").getParentOfType<UMethod>()!!.let { barMethod ->
|
||||
barMethod.assertResolveCall("foo()")
|
||||
barMethod.assertResolveCall("inlineFoo()")
|
||||
barMethod.assertResolveCall("forEach { println(it) }", "forEach")
|
||||
barMethod.assertResolveCall("joinToString()")
|
||||
barMethod.assertResolveCall("last()")
|
||||
barMethod.assertResolveCall("setValue(\"123\")")
|
||||
barMethod.assertResolveCall("contains(2 as Int)", "longRangeContains")
|
||||
barMethod.assertResolveCall("IntRange(1, 2)")
|
||||
}
|
||||
|
||||
file.findElementByTextFromPsi<UElement>("barT").getParentOfType<UMethod>()!!.let { barMethod ->
|
||||
barMethod.assertResolveCall("foo()")
|
||||
}
|
||||
|
||||
file.findElementByTextFromPsi<UElement>("listT").getParentOfType<UMethod>()!!.let { barMethod ->
|
||||
barMethod.assertResolveCall("isEmpty()")
|
||||
barMethod.assertResolveCall("foo()")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUtilsStreamLambda() {
|
||||
doTest("Lambdas") { _, file ->
|
||||
val lambda = file.findElementByTextFromPsi<ULambdaExpression>("{ it.isEmpty() }")
|
||||
assertEquals(
|
||||
"java.util.function.Predicate<? super java.lang.String>",
|
||||
lambda.functionalInterfaceType?.canonicalText
|
||||
)
|
||||
assertEquals(
|
||||
"kotlin.jvm.functions.Function1<? super java.lang.String,? extends java.lang.Boolean>",
|
||||
lambda.getExpressionType()?.canonicalText
|
||||
)
|
||||
val uCallExpression = lambda.uastParent.assertedCast<UCallExpression> { "UCallExpression expected" }
|
||||
assertTrue(uCallExpression.valueArguments.contains(lambda))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLambdaParamCall() {
|
||||
doTest("Lambdas") { _, file ->
|
||||
val lambdaCall = file.findElementByTextFromPsi<UCallExpression>("selectItemFunction()")
|
||||
assertEquals(
|
||||
"UIdentifier (Identifier (selectItemFunction))",
|
||||
lambdaCall.methodIdentifier?.asLogString()
|
||||
)
|
||||
assertEquals(
|
||||
"selectItemFunction",
|
||||
lambdaCall.methodIdentifier?.name
|
||||
)
|
||||
assertEquals(
|
||||
"invoke",
|
||||
lambdaCall.methodName
|
||||
)
|
||||
val receiver = lambdaCall.receiver ?: kfail("receiver expected")
|
||||
assertEquals("UReferenceExpression", receiver.asLogString())
|
||||
val uParameter = (receiver as UReferenceExpression).resolve().toUElement() ?: kfail("uelement expected")
|
||||
assertEquals("UParameter (name = selectItemFunction)", uParameter.asLogString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLocalLambdaCall() {
|
||||
doTest("Lambdas") { _, file ->
|
||||
val lambdaCall = file.findElementByTextFromPsi<UCallExpression>("baz()")
|
||||
assertEquals(
|
||||
"UIdentifier (Identifier (baz))",
|
||||
lambdaCall.methodIdentifier?.asLogString()
|
||||
)
|
||||
assertEquals(
|
||||
"baz",
|
||||
lambdaCall.methodIdentifier?.name
|
||||
)
|
||||
assertEquals(
|
||||
"invoke",
|
||||
lambdaCall.methodName
|
||||
)
|
||||
val receiver = lambdaCall.receiver ?: kfail("receiver expected")
|
||||
assertEquals("UReferenceExpression", receiver.asLogString())
|
||||
val uParameter = (receiver as UReferenceExpression).resolve().toUElement() ?: kfail("uelement expected")
|
||||
assertEquals("ULocalVariable (name = baz)", uParameter.asLogString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLocalDeclarationCall() {
|
||||
doTest("LocalDeclarations") { _, file ->
|
||||
val localFunction = file.findElementByTextFromPsi<UElement>("bar() == Local()").
|
||||
findElementByText<UCallExpression>("bar()")
|
||||
assertEquals(
|
||||
"UIdentifier (Identifier (bar))",
|
||||
localFunction.methodIdentifier?.asLogString()
|
||||
)
|
||||
assertEquals(
|
||||
"bar",
|
||||
localFunction.methodIdentifier?.name
|
||||
)
|
||||
assertEquals(
|
||||
"bar",
|
||||
localFunction.methodName
|
||||
)
|
||||
assertNull(localFunction.resolve())
|
||||
val receiver = localFunction.receiver ?: kfail("receiver expected")
|
||||
assertEquals("UReferenceExpression", receiver.asLogString())
|
||||
val uParameter = (receiver as UReferenceExpression).resolve().toUElement() ?: kfail("uelement expected")
|
||||
assertEquals("ULambdaExpression", uParameter.asLogString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testVariablesTypeReferences() {
|
||||
doTest("TypeReferences") { _, file ->
|
||||
run {
|
||||
val localVariable = file.findElementByTextFromPsi<UVariable>("val varWithType: String? = \"Not Null\"")
|
||||
val typeReference = localVariable.typeReference
|
||||
assertEquals("java.lang.String", typeReference?.getQualifiedName())
|
||||
val sourcePsi = typeReference?.sourcePsi ?: kfail("no sourcePsi")
|
||||
assertTrue("sourcePsi = $sourcePsi should be physical", sourcePsi.isPhysical)
|
||||
assertEquals("String?", sourcePsi.text)
|
||||
}
|
||||
|
||||
run {
|
||||
val localVariable = file.findElementByTextFromPsi<UVariable>("val varWithoutType = \"lorem ipsum\"")
|
||||
val typeReference = localVariable.typeReference
|
||||
assertEquals("java.lang.String", typeReference?.getQualifiedName())
|
||||
assertNull(typeReference?.sourcePsi)
|
||||
}
|
||||
|
||||
run {
|
||||
val localVariable = file.findElementByTextFromPsi<UVariable>("parameter: Int")
|
||||
val typeReference = localVariable.typeReference
|
||||
assertEquals("int", typeReference?.type?.presentableText)
|
||||
val sourcePsi = typeReference?.sourcePsi ?: kfail("no sourcePsi")
|
||||
assertTrue("sourcePsi = $sourcePsi should be physical", sourcePsi.isPhysical)
|
||||
assertEquals("Int", sourcePsi.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <T, R> Iterable<T>.assertedFind(value: R, transform: (T) -> R): T =
|
||||
find { transform(it) == value } ?: throw AssertionError("'$value' not found, only ${this.joinToString { transform(it).toString() }}")
|
||||
|
||||
fun runAll(vararg asserts: () -> Unit) = RunAll(*asserts.map { ThrowableRunnable<Throwable>(it) }.toTypedArray()).run()
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.test.kotlin
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.patterns.uast.literalExpression
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl
|
||||
import com.intellij.psi.util.PropertyUtil
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.registerServiceInstance
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.evaluateString
|
||||
import org.jetbrains.uast.toUElementOfType
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.fail
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class KotlinUastReferencesTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||
|
||||
|
||||
@Test
|
||||
fun `test original getter is visible when reference is under renaming`() {
|
||||
|
||||
registerReferenceProviders(testRootDisposable) {
|
||||
registerUastReferenceProvider(literalExpression(), uastLiteralReferenceProvider { _, psiLanguageInjectionHost ->
|
||||
arrayOf(GetterReference("KotlinBean", psiLanguageInjectionHost))
|
||||
})
|
||||
}
|
||||
|
||||
myFixture.configureByText(
|
||||
"KotlinBean.kt", """
|
||||
data class KotlinBean(val myF<caret>ield: String)
|
||||
|
||||
val reference = "myField"
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
myFixture.renameElementAtCaret("myRenamedField")
|
||||
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
data class KotlinBean(val myRenamedField: String)
|
||||
|
||||
val reference = "myRenamedField"
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GetterReference(
|
||||
val className: String,
|
||||
psiElement: PsiElement
|
||||
) : PsiReferenceBase<PsiElement>(psiElement) {
|
||||
override fun resolve(): PsiMethod? {
|
||||
val psiClass = JavaPsiFacade.getInstance(element.project).findClass(className, element.resolveScope) ?: return null
|
||||
val name = element.toUElementOfType<UExpression>()?.evaluateString() ?: return null
|
||||
return PropertyUtil.getGetters(psiClass, name).firstOrNull()
|
||||
}
|
||||
|
||||
override fun handleElementRename(newElementName: String): PsiElement {
|
||||
val resolve = resolve()
|
||||
?: fail("can't resolve during rename, looks like someone renamed or removed the source element before updating references")
|
||||
|
||||
val newName =
|
||||
if (PropertyUtil.getPropertyName(resolve) != null)
|
||||
PropertyUtil.getPropertyName(newElementName) ?: newElementName
|
||||
else newElementName
|
||||
|
||||
return super.handleElementRename(newName)
|
||||
}
|
||||
|
||||
override fun getVariants(): Array<Any> = emptyArray()
|
||||
}
|
||||
|
||||
|
||||
fun registerReferenceProviders(disposable: Disposable, registerContributors: PsiReferenceRegistrar.() -> Unit) {
|
||||
registerReferenceContributor(object : PsiReferenceContributor() {
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) = registrar.registerContributors()
|
||||
}, disposable)
|
||||
}
|
||||
|
||||
fun registerReferenceContributor(contributor: PsiReferenceContributor, disposable: Disposable) {
|
||||
val referenceContributorEp = Extensions.getArea(null).getExtensionPoint<PsiReferenceContributorEP>(PsiReferenceContributor.EP_NAME.name)
|
||||
|
||||
val contributorEp = object : PsiReferenceContributorEP() {
|
||||
override fun getInstance(): PsiReferenceContributor = contributor
|
||||
}
|
||||
|
||||
referenceContributorEp.registerExtension(contributorEp)
|
||||
|
||||
val application = ApplicationManager.getApplication()
|
||||
|
||||
//we need a fresh ReferenceProvidersRegistry after updating ReferenceContributors
|
||||
val oldReferenceProviderRegistry =
|
||||
application.picoContainer.getComponentInstance(ReferenceProvidersRegistry::class.java) as ReferenceProvidersRegistry
|
||||
application.registerServiceInstance(ReferenceProvidersRegistry::class.java, ReferenceProvidersRegistryImpl())
|
||||
|
||||
Disposer.register(disposable, Disposable {
|
||||
referenceContributorEp.unregisterExtension(contributorEp)
|
||||
application.registerServiceInstance(ReferenceProvidersRegistry::class.java, oldReferenceProviderRegistry)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
|
||||
@Test fun testLocalDeclarations() = doTest("LocalDeclarations")
|
||||
|
||||
@Test fun testSimple() = doTest("Simple")
|
||||
|
||||
@Test fun testWhenIs() = doTest("WhenIs")
|
||||
|
||||
@Test fun testDefaultImpls() = doTest("DefaultImpls")
|
||||
|
||||
@Test fun testElvis() = doTest("Elvis")
|
||||
|
||||
@Test fun testPropertyAccessors() = doTest("PropertyAccessors")
|
||||
|
||||
@Test fun testPropertyInitializer() = doTest("PropertyInitializer")
|
||||
|
||||
@Test fun testPropertyInitializerWithoutSetter() = doTest("PropertyInitializerWithoutSetter")
|
||||
|
||||
@Test fun testAnnotationParameters() = doTest("AnnotationParameters")
|
||||
|
||||
@Test fun testEnumValueMembers() = doTest("EnumValueMembers")
|
||||
|
||||
@Test fun testStringTemplate() = doTest("StringTemplate")
|
||||
|
||||
@Test fun testStringTemplateComplex() = doTest("StringTemplateComplex")
|
||||
|
||||
@Test fun testQualifiedConstructorCall() = doTest("QualifiedConstructorCall")
|
||||
|
||||
@Test fun testPropertyDelegate() = doTest("PropertyDelegate")
|
||||
|
||||
@Test fun testLocalVariableWithAnnotation() = doTest("LocalVariableWithAnnotation")
|
||||
|
||||
@Test fun testPropertyWithAnnotation() = doTest("PropertyWithAnnotation")
|
||||
|
||||
@Test fun testIfStatement() = doTest("IfStatement")
|
||||
|
||||
@Test fun testInnerClasses() = doTest("InnerClasses")
|
||||
|
||||
@Test fun testSimpleScript() = doTest("SimpleScript") { testName, file -> check(testName, file, false) }
|
||||
|
||||
@Test fun testDestructuringDeclaration() = doTest("DestructuringDeclaration")
|
||||
|
||||
@Test fun testDefaultParameterValues() = doTest("DefaultParameterValues")
|
||||
|
||||
@Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation")
|
||||
|
||||
@Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues")
|
||||
|
||||
@Test
|
||||
fun testUnexpectedContainer() = doTest("UnexpectedContainerException")
|
||||
|
||||
@Test
|
||||
fun testWhenStringLiteral() = doTest("WhenStringLiteral")
|
||||
|
||||
@Test
|
||||
fun testWhenAndDestructing() = doTest("WhenAndDestructing") { testName, file -> check(testName, file, false) }
|
||||
|
||||
@Test
|
||||
fun testSuperCalls() = doTest("SuperCalls")
|
||||
|
||||
@Test
|
||||
fun testConstructors() = doTest("Constructors")
|
||||
|
||||
@Test
|
||||
fun testClassAnnotation() = doTest("ClassAnnotation")
|
||||
|
||||
@Test
|
||||
fun testReceiverFun() = doTest("ReceiverFun")
|
||||
|
||||
@Test
|
||||
fun testAnonymous() = doTest("Anonymous")
|
||||
|
||||
@Test
|
||||
fun testAnnotationComplex() = doTest("AnnotationComplex")
|
||||
|
||||
@Test
|
||||
fun testParametersDisorder() = doTest("ParametersDisorder") { testName, file ->
|
||||
// disabled due to inconsistent parents for 2-receivers call (KT-22344)
|
||||
check(testName, file, false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLambdas() = doTest("Lambdas")
|
||||
|
||||
@Test
|
||||
fun testTypeReferences() = doTest("TypeReferences")
|
||||
|
||||
@Test
|
||||
fun testDelegate() = doTest("Delegate")
|
||||
|
||||
@Test
|
||||
fun testConstructorDelegate() = doTest("ConstructorDelegate")
|
||||
|
||||
@Test
|
||||
fun testLambdaReturn() = doTest("LambdaReturn")
|
||||
|
||||
@Test
|
||||
fun testReified() = doTest("Reified")
|
||||
|
||||
@Test
|
||||
fun testSuspend() = doTest("Suspend")
|
||||
|
||||
@Test
|
||||
fun testDeprecatedHidden() = doTest("DeprecatedHidden")
|
||||
}
|
||||
Reference in New Issue
Block a user