Compare commits

...

6 Commits

Author SHA1 Message Date
Nicolay Mitropolsky
59a30b92eb KotlinElementActionsFactory: adding empty annotations without parenthesises 2019-03-18 22:48:43 +03:00
Nicolay Mitropolsky
a97fe698f2 KotlinElementActionsFactory: changing parameters could add annotations 2019-03-18 22:48:12 +03:00
Nicolay Mitropolsky
d71098b6c4 KotlinElementActionsFactory: support for keeping existing parameters on signature change 2019-03-18 22:40:57 +03:00
Nicolay Mitropolsky
dd7c3a84fd hacky fixes for 192 2019-03-14 16:18:32 +03:00
Nicolay Mitropolsky
b47a46a3f0 fixes for 192 2019-03-14 13:31:13 +03:00
Nicolay Mitropolsky
61d4e45537 ~~~~ switch 191 ~~~~ 2019-03-14 11:51:06 +03:00
120 changed files with 7636 additions and 427 deletions

View File

@@ -1,11 +1,9 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.plugins.ide.idea.model.IdeaModel
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import proguard.gradle.ProGuardTask
import org.gradle.kotlin.dsl.*
import org.jetbrains.kotlin.gradle.tasks.*
import org.gradle.plugins.ide.idea.model.IdeaModel
buildscript {
extra["defaultSnapshotVersion"] = "1.3-SNAPSHOT"
@@ -169,15 +167,16 @@ extra["intellijUltimateEnabled"] = intellijUltimateEnabled
extra["intellijSeparateSdks"] = intellijSeparateSdks
extra["IntellijCoreDependencies"] =
listOf(if (Platform[191].orHigher()) "asm-all-7.0" else "asm-all",
"guava",
"jdom",
"jna",
"log4j",
"picocontainer",
"snappy-in-java",
"streamex",
"trove4j")
listOf(
if (Platform[191].orHigher()) "asm-all-7.0.1" else "asm-all",
"guava",
"jdom",
"jna",
"log4j",
"picocontainer",
"snappy-in-java",
"streamex",
"trove4j")
extra["compilerModules"] = arrayOf(
@@ -380,13 +379,13 @@ allprojects {
gradle.taskGraph.whenReady {
if (isTeamcityBuild) {
logger.warn("CI build profile is active (IC is off, proguard is on). Use -Pteamcity=false to reproduce local build")
for (task in allTasks) {
when (task) {
is AbstractKotlinCompile<*> -> task.incremental = false
is JavaCompile -> task.options.isIncremental = false
}
}
// logger.warn("CI build profile is active (IC is off, proguard is on). Use -Pteamcity=false to reproduce local build")
// for (task in allTasks) {
// when (task) {
// is AbstractKotlinCompile<*> -> task.incremental = false
// is JavaCompile -> task.options.isIncremental = false
// }
// }
} else {
logger.warn("Local build profile is active (IC is on, proguard is off). Use -Pteamcity=true to reproduce TC build")
for (task in allTasks) {
@@ -699,9 +698,9 @@ tasks.create("findShadowJarsInClasspath").doLast {
is ShadowJar -> {
shadowJars.add(fileFrom(task.archivePath))
}
is ProGuardTask -> {
shadowJars.addAll(task.outputs.files.toList())
}
// is ProGuardTask -> {
// shadowJars.addAll(task.outputs.files.toList())
// }
}
}
}

View File

@@ -51,7 +51,11 @@ class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
throw UnsupportedOperationException("not implemented")
}
override fun hasAnnotationRootsForFile(file: VirtualFile): Boolean {
throw UnsupportedOperationException("not implemented")
}
override fun hasAnnotationRootsForFile(file: VirtualFile): Boolean = false
override fun findDefaultConstructorExternalAnnotations(aClass: PsiClass, annotationFQN: String): List<PsiAnnotation> = emptyList()
override fun findDefaultConstructorExternalAnnotations(aClass: PsiClass): List<PsiAnnotation> = emptyList()
override fun findExternalAnnotations(listOwner: PsiModifierListOwner, annotationFQN: String): List<PsiAnnotation> = emptyList()
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.codeInsight.ExternalAnnotationsManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
override fun chooseAnnotationsPlace(element: PsiElement): AnnotationPlace? = null
override fun isExternalAnnotationWritable(listOwner: PsiModifierListOwner, annotationFQN: String): Boolean = false
override fun isExternalAnnotation(annotation: PsiAnnotation): Boolean = false
override fun findExternalAnnotationsFiles(listOwner: PsiModifierListOwner): List<PsiFile>? = null
override fun findExternalAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String): PsiAnnotation? = null
override fun findExternalAnnotations(listOwner: PsiModifierListOwner): Array<out PsiAnnotation>? = null
override fun annotateExternally(
listOwner: PsiModifierListOwner,
annotationFQName: String,
fromFile: PsiFile,
value: Array<out PsiNameValuePair>?
) {
throw UnsupportedOperationException("not implemented")
}
override fun deannotate(listOwner: PsiModifierListOwner, annotationFQN: String): Boolean {
throw UnsupportedOperationException("not implemented")
}
override fun editExternalAnnotation(
listOwner: PsiModifierListOwner,
annotationFQN: String,
value: Array<out PsiNameValuePair>?
): Boolean {
throw UnsupportedOperationException("not implemented")
}
override fun hasAnnotationRootsForFile(file: VirtualFile): Boolean {
throw UnsupportedOperationException("not implemented")
}
}

View File

@@ -16,6 +16,7 @@ messages/**)
-dontnote **
-dontwarn com.intellij.util.ui.IsRetina*
-dontwarn com.intellij.util.ui.UIUtilities
-dontwarn com.intellij.util.RetinaImage*
-dontwarn apple.awt.*
-dontwarn dk.brics.automaton.*
@@ -201,7 +202,6 @@ messages/**)
-keep class org.jetbrains.org.objectweb.asm.tree.FieldNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.ParameterNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.TypeAnnotationNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.InsnList { *; }
-keep class org.jetbrains.org.objectweb.asm.signature.SignatureReader { *; }
-keep class org.jetbrains.org.objectweb.asm.signature.SignatureVisitor { *; }

255
compiler/compiler.pro.183 Normal file
View File

@@ -0,0 +1,255 @@
-injars '<kotlin-compiler-jar-before-shrink>'(
!org/apache/log4j/jmx/Agent*,
!org/apache/log4j/net/JMS*,
!org/apache/log4j/net/SMTP*,
!org/apache/log4j/or/jms/MessageRenderer*,
!org/jdom/xpath/Jaxen*,
!org/jline/builtins/ssh/**,
!org/mozilla/javascript/xml/impl/xmlbeans/**,
!net/sf/cglib/**,
!META-INF/maven**,
**.class,**.properties,**.kt,**.kotlin_*,**.jnilib,**.so,**.dll,**.txt,**.caps,
META-INF/services/**,META-INF/native/**,META-INF/extensions/**,META-INF/MANIFEST.MF,
messages/**)
-outjars '<kotlin-compiler-jar>'
-dontnote **
-dontwarn com.intellij.util.ui.IsRetina*
-dontwarn com.intellij.util.RetinaImage*
-dontwarn apple.awt.*
-dontwarn dk.brics.automaton.*
-dontwarn org.fusesource.**
-dontwarn org.imgscalr.Scalr**
-dontwarn org.xerial.snappy.SnappyBundleActivator
-dontwarn com.intellij.util.CompressionUtil
-dontwarn com.intellij.util.SnappyInitializer
-dontwarn com.intellij.util.SVGLoader
-dontwarn com.intellij.util.SVGLoader$MyTranscoder
-dontwarn net.sf.cglib.**
-dontwarn org.objectweb.asm.** # this is ASM3, the old version that we do not use
-dontwarn com.sun.jna.NativeString
-dontwarn com.sun.jna.WString
-dontwarn com.intellij.psi.util.PsiClassUtil
-dontwarn org.apache.hadoop.io.compress.*
-dontwarn com.google.j2objc.annotations.Weak
-dontwarn org.iq80.snappy.HadoopSnappyCodec$SnappyCompressionInputStream
-dontwarn org.iq80.snappy.HadoopSnappyCodec$SnappyCompressionOutputStream
-dontwarn com.google.common.util.concurrent.*
-dontwarn org.apache.xerces.dom.**
-dontwarn org.apache.xerces.util.**
-dontwarn org.w3c.dom.ElementTraversal
-dontwarn javaslang.match.annotation.Unapply
-dontwarn javaslang.match.annotation.Patterns
-dontwarn javaslang.*
-dontwarn com.google.errorprone.**
-dontwarn com.google.j2objc.**
-dontwarn javax.crypto.**
-dontwarn java.lang.invoke.MethodHandle
-dontwarn org.jline.builtins.Nano$Buffer
-dontwarn org.jetbrains.annotations.ReadOnly
-dontwarn org.jetbrains.annotations.Mutable
-dontwarn com.intellij.util.io.TarUtil
-dontwarn com.intellij.util.io.Compressor$Tar
# Annotations from intellijCore/annotations.jar that not presented in org.jetbrains.annotations
-dontwarn org.jetbrains.annotations.Async*
-dontwarn org.jetbrains.annotations.Nls$Capitalization
# Nullability annotations used in Guava
-dontwarn org.checkerframework.checker.nullness.compatqual.NullableDecl
-dontwarn org.checkerframework.checker.nullness.compatqual.MonotonicNonNullDecl
-dontwarn org.checkerframework.checker.nullness.qual.Nullable
-dontwarn org.checkerframework.checker.nullness.qual.MonotonicNonNull
# Depends on apache batick which has lots of dependencies
-dontwarn com.intellij.util.SVGLoader*
-dontwarn org.apache.batik.script.rhino.RhinoInterpreter
-dontwarn org.apache.batik.script.rhino.RhinoInterpreterFactory
# The appropriate jar is either loaded separately or added explicitly to the classpath then needed
-dontwarn org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
-dontwarn org.jdom.xpath.jaxen.*
-dontwarn com.intellij.util.io.Decompressor*
-dontwarn org.w3c.dom.Location
-dontwarn org.w3c.dom.Window
#-libraryjars '<rtjar>'
#-libraryjars '<jssejar>'
#-libraryjars '<bootstrap.runtime>'
#-libraryjars '<bootstrap.reflect>'
#-libraryjars '<bootstrap.script.runtime>'
#-libraryjars '<tools.jar>'
-dontoptimize
-dontobfuscate
-keep class org.fusesource.** { *; }
-keep class com.sun.jna.** { *; }
-keep class org.jetbrains.annotations.** {
public protected *;
}
-keep class javax.inject.** {
public protected *;
}
-keep class org.jetbrains.kotlin.** {
public protected *;
}
-keep class org.jetbrains.kotlin.compiler.plugin.** {
public protected *;
}
-keep class org.jetbrains.kotlin.extensions.** {
public protected *;
}
-keep class org.jetbrains.kotlin.protobuf.** {
public protected *;
}
-keep class org.jetbrains.kotlin.container.** { *; }
-keep class org.jetbrains.org.objectweb.asm.Opcodes { *; }
-keep class org.jetbrains.kotlin.codegen.extensions.** {
public protected *;
}
-keepclassmembers class com.intellij.openapi.vfs.VirtualFile {
public protected *;
}
-keep class com.intellij.openapi.vfs.StandardFileSystems {
public static *;
}
# needed for jar cache cleanup in the gradle plugin and compile daemon
-keepclassmembers class com.intellij.openapi.vfs.impl.ZipHandler {
public static void clearFileAccessorCache();
}
-keep class jet.** {
public protected *;
}
-keep class com.intellij.psi.** {
public protected *;
}
# This is needed so that the platform code which parses XML wouldn't fail, see KT-16968
# This API is used from org.jdom.input.SAXBuilder via reflection.
-keep class org.jdom.input.JAXPParserFactory { public ** createParser(...); }
# Without this class PluginManagerCore.loadDescriptorFromJar fails
-keep class org.jdom.output.XMLOutputter { *; }
# for kdoc & dokka
-keep class com.intellij.openapi.util.TextRange { *; }
-keep class com.intellij.lang.impl.PsiBuilderImpl* {
public protected *;
}
-keep class com.intellij.openapi.util.text.StringHash { *; }
# for j2k
-keep class com.intellij.codeInsight.NullableNotNullManager { public protected *; }
# for gradle (see KT-12549)
-keep class com.intellij.lang.properties.charset.Native2AsciiCharsetProvider { *; }
# for kotlin-build-common (consider repacking compiler together with kotlin-build-common and remove this part afterwards)
-keep class com.intellij.util.io.IOUtil { public *; }
-keep class com.intellij.openapi.util.io.FileUtil { public *; }
-keep class com.intellij.util.SystemProperties { public *; }
-keep class com.intellij.util.containers.hash.LinkedHashMap { *; }
-keep class com.intellij.util.containers.ConcurrentIntObjectMap { *; }
-keep class com.intellij.util.containers.ComparatorUtil { *; }
-keep class com.intellij.util.io.PersistentHashMapValueStorage { *; }
-keep class com.intellij.util.io.PersistentHashMap { *; }
-keep class com.intellij.util.io.BooleanDataDescriptor { *; }
-keep class com.intellij.util.io.EnumeratorStringDescriptor { *; }
-keep class com.intellij.util.io.ExternalIntegerKeyDescriptor { *; }
-keep class com.intellij.util.containers.hash.EqualityPolicy { *; }
-keep class com.intellij.util.containers.hash.EqualityPolicy.* { *; }
-keep class com.intellij.util.containers.Interner { *; }
-keep class gnu.trove.TIntHashSet { *; }
-keep class gnu.trove.TIntIterator { *; }
-keep class org.iq80.snappy.SlowMemory { *; }
-keep class javaslang.match.PatternsProcessor { *; }
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * {
** toString();
** hashCode();
void start();
void stop();
void dispose();
}
-keep class org.jetbrains.org.objectweb.asm.tree.AnnotationNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.ClassNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.LocalVariableNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.MethodNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.FieldNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.ParameterNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.TypeAnnotationNode { *; }
-keep class org.jetbrains.org.objectweb.asm.tree.InsnList { *; }
-keep class org.jetbrains.org.objectweb.asm.signature.SignatureReader { *; }
-keep class org.jetbrains.org.objectweb.asm.signature.SignatureVisitor { *; }
-keep class org.jetbrains.org.objectweb.asm.Type {
public protected *;
}
-keepclassmembers class org.jetbrains.org.objectweb.asm.ClassReader {
*** SKIP_CODE;
*** SKIP_DEBUG;
*** SKIP_FRAMES;
}
-keepclassmembers class com.intellij.openapi.project.Project {
** getBasePath();
}
# for kotlin-android-extensions in maven
-keep class com.intellij.openapi.module.ModuleServiceManager { public *; }
# for building kotlin-build-common-test
-keep class org.jetbrains.kotlin.build.SerializationUtilsKt { *; }
# for tools.jar
-keep class com.sun.tools.javac.** { *; }
-keep class com.sun.source.** { *; }
# for coroutines
-keep class kotlinx.coroutines.** { *; }
# for webdemo
-keep class com.intellij.openapi.progress.ProgressManager { *; }
# for kapt
-keep class com.intellij.openapi.project.Project { *; }
-keepclassmembers class com.intellij.util.PathUtil {
public static java.lang.String getJarPathForClass(java.lang.Class);
}
-keepclassmembers class com.intellij.util.PathUtil {
public static java.lang.String getJarPathForClass(java.lang.Class);
}
# remove when KT-18563 would be fixed
-keep class org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt { *; }
-keep class net.jpountz.lz4.* { *; }
# used in LazyScriptDescriptor
-keep class org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt { *; }

View File

@@ -19,16 +19,7 @@ package org.jetbrains.kotlin.generators.tests
import org.jetbrains.kotlin.AbstractDataFlowValueRenderingTest
import org.jetbrains.kotlin.addImport.AbstractAddImportTest
import org.jetbrains.kotlin.allopen.AbstractBytecodeListingTestForAllOpen
import org.jetbrains.kotlin.android.*
import org.jetbrains.kotlin.android.annotator.AbstractAndroidGutterIconTest
import org.jetbrains.kotlin.android.configure.AbstractConfigureProjectTest
import org.jetbrains.kotlin.android.folding.AbstractAndroidResourceFoldingTest
import org.jetbrains.kotlin.android.intention.AbstractAndroidIntentionTest
import org.jetbrains.kotlin.android.intention.AbstractAndroidResourceIntentionTest
import org.jetbrains.kotlin.android.lint.AbstractKotlinLintTest
import org.jetbrains.kotlin.android.parcel.AbstractParcelBytecodeListingTest
import org.jetbrains.kotlin.android.quickfix.AbstractAndroidLintQuickfixTest
import org.jetbrains.kotlin.android.quickfix.AbstractAndroidQuickFixMultiFileTest
import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBoxTest
import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBytecodeShapeTest
import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidSyntheticPropertyDescriptorTest
@@ -652,10 +643,6 @@ fun main(args: Array<String>) {
model("debugger/tinyApp/src/evaluate/multipleBreakpoints", testMethod = "doMultipleBreakpointsTest")
}
testClass<AbstractAsyncStackTraceTest> {
model("debugger/tinyApp/src/asyncStackTrace")
}
testClass<AbstractFileRankingTest> {
model("debugger/fileRanking")
}
@@ -1134,7 +1121,7 @@ fun main(args: Array<String>) {
model("script", extension = "kts")
}
}
/*
testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") {
testClass<AbstractAndroidCompletionTest> {
model("android/completion", recursive = false, extension = null)
@@ -1207,4 +1194,5 @@ fun main(args: Array<String>) {
model("android/gutterIcon")
}
}
*/
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
versions.intellijSdk=183.5153.4
versions.intellijSdk=191.5109.14
versions.androidBuildTools=r23.0.1
versions.idea.NodeJS=181.3494.12
versions.jar.asm-all=7.0.1
versions.jar.guava=25.1-jre
versions.jar.groovy-all=2.4.15
versions.jar.lombok-ast=0.2.3
versions.jar.swingx-core=1.6.2-2
versions.jar.kxml2=2.3.0
versions.jar.streamex=0.6.7
versions.jar.streamex=0.6.8
versions.jar.gson=2.8.5
versions.jar.oro=2.0.8
versions.jar.picocontainer=1.2
versions.jar.asm-all=7.0
ignore.jar.snappy-in-java=true
versions.gradle-api=4.5.1

View File

@@ -0,0 +1,15 @@
versions.intellijSdk=183.5153.4
versions.androidBuildTools=r23.0.1
versions.idea.NodeJS=181.3494.12
versions.jar.guava=25.1-jre
versions.jar.groovy-all=2.4.15
versions.jar.lombok-ast=0.2.3
versions.jar.swingx-core=1.6.2-2
versions.jar.kxml2=2.3.0
versions.jar.streamex=0.6.7
versions.jar.gson=2.8.5
versions.jar.oro=2.0.8
versions.jar.picocontainer=1.2
versions.jar.asm-all=7.0
ignore.jar.snappy-in-java=true
versions.gradle-api=4.5.1

View File

@@ -1,17 +1,90 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.idea.caches.project
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.LIBRARY_KEY
import org.jetbrains.kotlin.idea.MODULE_ROOT_TYPE_KEY
import org.jetbrains.kotlin.idea.SDK_KEY
import org.jetbrains.kotlin.idea.caches.project.UserDataModuleContainer.ForPsiElement
import org.jetbrains.kotlin.idea.caches.project.UserDataModuleContainer.ForVirtualFile
import org.jetbrains.kotlin.idea.core.getSourceType
import org.jetbrains.kotlin.utils.addIfNotNull
// This file declares non-exported API for overriding module info with user-data
// NO-OP implementation, full implementation only for AS3.3, AS3.4
private sealed class UserDataModuleContainer {
abstract fun <T> getUserData(key: Key<T>): T?
abstract fun getModule(): Module?
data class ForVirtualFile(val virtualFile: VirtualFile, val project: Project) : UserDataModuleContainer() {
override fun <T> getUserData(key: Key<T>): T? = virtualFile.getUserData(key)
override fun getModule(): Module? = ModuleUtilCore.findModuleForFile(virtualFile, project)
}
data class ForPsiElement(val psiElement: PsiElement) : UserDataModuleContainer() {
override fun <T> getUserData(key: Key<T>): T? {
return psiElement.getUserData(key)
?: psiElement.containingFile?.getUserData(key)
?: psiElement.containingFile?.originalFile?.virtualFile?.getUserData(key)
}
override fun getModule(): Module? = ModuleUtilCore.findModuleForPsiElement(psiElement)
}
}
private fun collectModuleInfoByUserData(
project: Project,
container: UserDataModuleContainer
): List<IdeaModuleInfo> {
fun forModule(): ModuleSourceInfo? {
val rootType = container.getUserData(MODULE_ROOT_TYPE_KEY) ?: return null
val module = container.getModule() ?: return null
return when (rootType.getSourceType()) {
null -> null
SourceType.PRODUCTION -> module.productionSourceInfo()
SourceType.TEST -> module.testSourceInfo()
}
}
val result = mutableListOf<IdeaModuleInfo>()
result.addIfNotNull(forModule())
val library = container.getUserData(LIBRARY_KEY)
if (library != null) {
result.addAll(createLibraryInfo(project, library))
}
val sdk = container.getUserData(SDK_KEY)
if (sdk != null) {
result.add(SdkInfo(project, sdk))
}
return result
}
fun collectModuleInfoByUserData(
project: Project,
virtualFile: VirtualFile
): List<IdeaModuleInfo> = emptyList()
): List<IdeaModuleInfo> = collectModuleInfoByUserData(project, ForVirtualFile(virtualFile, project))
fun collectModuleInfoByUserData(
psiElement: PsiElement
): List<IdeaModuleInfo> = emptyList()
): List<IdeaModuleInfo> = collectModuleInfoByUserData(psiElement.project, ForPsiElement(psiElement))

View File

@@ -0,0 +1,17 @@
package org.jetbrains.kotlin.idea.caches.project
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
// NO-OP implementation, full implementation only for AS3.3, AS3.4
fun collectModuleInfoByUserData(
project: Project,
virtualFile: VirtualFile
): List<IdeaModuleInfo> = emptyList()
fun collectModuleInfoByUserData(
psiElement: PsiElement
): List<IdeaModuleInfo> = emptyList()

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.idea
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.util.Key
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
// WARNING, this API is used by AS3.3+
const val LIBRARY_KEY_NAME = "Kt_Library"
const val SDK_KEY_NAME = "Kt_Sdk"
const val MODULE_ROOT_TYPE_KEY_NAME = "Kt_SourceRootType"
@JvmField
val MODULE_ROOT_TYPE_KEY = getOrCreateKey<JpsModuleSourceRootType<*>>(MODULE_ROOT_TYPE_KEY_NAME)
@JvmField
val SDK_KEY = getOrCreateKey<Sdk>(SDK_KEY_NAME)
@JvmField
val LIBRARY_KEY = getOrCreateKey<Library>(LIBRARY_KEY_NAME)
inline fun <reified T> getOrCreateKey(name: String): Key<T> {
@Suppress("DEPRECATION", "UNCHECKED_CAST")
val existingKey = Key.findKeyByName(name) as Key<T>?
return existingKey ?: Key.create<T>(name)
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.run
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.execution.junit.PatternConfigurationProducer
import com.intellij.ide.plugins.PluginManager
@@ -28,6 +29,7 @@ import com.intellij.openapi.util.component2
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.idea.caches.project.isMPPModule
import org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer
import org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer
import org.jetbrains.plugins.gradle.util.GradleConstants
@@ -96,6 +98,15 @@ class KotlinTestClassGradleConfigurationProducer : TestClassGradleConfigurationP
return true
}
override fun onFirstRun(fromContext: ConfigurationFromContext, context: ConfigurationContext, performRunnable: Runnable) {
if (context.location?.module?.isMPPModule == true) {
// TODO: remove hack when IDEA has new API
performRunnable.run()
} else {
super.onFirstRun(fromContext, context, performRunnable)
}
}
override fun doIsConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean {
if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false
@@ -154,6 +165,15 @@ class KotlinTestMethodGradleConfigurationProducer : TestMethodGradleConfiguratio
return true
}
override fun onFirstRun(fromContext: ConfigurationFromContext, context: ConfigurationContext, performRunnable: Runnable) {
if (context.location?.module?.isMPPModule == true) {
// TODO: remove hack when IDEA has new API
performRunnable.run()
} else {
super.onFirstRun(fromContext, context, performRunnable)
}
}
override fun doIsConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean {
if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false

View File

@@ -0,0 +1,221 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.run
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.execution.junit.PatternConfigurationProducer
import com.intellij.ide.plugins.PluginManager
import com.intellij.openapi.extensions.PluginId.getId
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.component1
import com.intellij.openapi.util.component2
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer
import org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer
import org.jetbrains.plugins.gradle.util.GradleConstants
private val IS_JUNIT_ENABLED by lazy { isPluginEnabled("JUnit") }
private val IS_TESTNG_ENABLED by lazy { isPluginEnabled("TestNG-J") }
private val IS_TEST_FRAMEWORK_PLUGIN_ENABLED by lazy { IS_JUNIT_ENABLED || IS_TESTNG_ENABLED }
private fun isPluginEnabled(id: String): Boolean {
return PluginManager.isPluginInstalled(getId(id)) && id !in PluginManager.getDisabledPlugins()
}
private fun getTestClass(leaf: PsiElement): PsiClass? {
if (IS_JUNIT_ENABLED) {
KotlinJUnitRunConfigurationProducer.getTestClass(leaf)?.let { return it }
}
if (IS_TESTNG_ENABLED) {
KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.let { (testClass, testMethod) ->
return if (testMethod == null) testClass else null
}
}
return null
}
private fun getTestMethod(leaf: PsiElement): PsiMethod? {
if (IS_JUNIT_ENABLED) {
KotlinJUnitRunConfigurationProducer.getTestMethod(leaf)?.let { return it }
}
if (IS_TESTNG_ENABLED) {
KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.second?.let { return it }
}
return null
}
class KotlinTestClassGradleConfigurationProducer : TestClassGradleConfigurationProducer() {
override fun doSetupConfigurationFromContext(
configuration: ExternalSystemRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
): Boolean {
if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false
val contextLocation = context.location ?: return false
val module = context.module?.asJvmModule() ?: return false
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
return false
}
val leaf = context.location?.psiElement ?: return false
val testClass = getTestClass(leaf) ?: return false
sourceElement.set(testClass)
if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return false
val projectPath = resolveProjectPath(module) ?: return false
val tasksToRun = getTasksToRun(module)
if (tasksToRun.isEmpty()) return false
configuration.settings.externalProjectPath = projectPath
configuration.settings.taskNames = tasksToRun
configuration.settings.scriptParameters = String.format("--tests \"%s\"", testClass.qualifiedName)
configuration.name = testClass.name ?: "unknown"
JavaRunConfigurationExtensionManagerUtil.getInstance().extendCreatedConfiguration(configuration, contextLocation)
return true
}
override fun doIsConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean {
if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false
val leaf = context.location?.psiElement ?: return false
val module = context.module?.asJvmModule() ?: return false
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
return false
}
if (getTestMethod(leaf) != null) return false
val testClass = getTestClass(leaf)
if (testClass == null || testClass.qualifiedName == null) return false
val projectPath = resolveProjectPath(module) ?: return false
if (projectPath != configuration.settings.externalProjectPath) {
return false
}
if (!configuration.settings.taskNames.containsAll(getTasksToRun(module))) return false
val scriptParameters = configuration.settings.scriptParameters + ' '
val i = scriptParameters.indexOf("--tests ")
if (i == -1) return false
val str = scriptParameters.substringAfter("--tests ").trim() + ' '
return str.startsWith("\"" + testClass.qualifiedName + "\"" + ' ') && !str.contains("--tests")
}
}
class KotlinTestMethodGradleConfigurationProducer : TestMethodGradleConfigurationProducer() {
override fun doSetupConfigurationFromContext(
configuration: ExternalSystemRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
): Boolean {
if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false
val contextLocation = context.location ?: return false
context.module?.asJvmModule() ?: return false
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
return false
}
val psiMethod = getTestMethod(contextLocation.psiElement) ?: return false
sourceElement.set(psiMethod)
val containingClass = psiMethod.containingClass ?: return false
if (!applyTestMethodConfiguration(configuration, context, psiMethod, containingClass)) return false
JavaRunConfigurationExtensionManagerUtil.getInstance().extendCreatedConfiguration(configuration, contextLocation)
return true
}
override fun doIsConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean {
if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
return false
}
val contextLocation = context.location ?: return false
val module = context.module?.asJvmModule() ?: return false
val psiMethod = getTestMethod(contextLocation.psiElement) ?: return false
val containingClass = psiMethod.containingClass ?: return false
val projectPath = resolveProjectPath(module) ?: return false
if (projectPath != configuration.settings.externalProjectPath) {
return false
}
if (!configuration.settings.taskNames.containsAll(getTasksToRun(module))) return false
val scriptParameters = configuration.settings.scriptParameters + ' '
val testFilter = createTestFilter(containingClass, psiMethod)
return scriptParameters.contains(testFilter!!)
}
private fun applyTestMethodConfiguration(
configuration: ExternalSystemRunConfiguration,
context: ConfigurationContext,
psiMethod: PsiMethod,
vararg containingClasses: PsiClass
): Boolean {
val module = context.module ?: return false
if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return false
val projectPath = resolveProjectPath(module) ?: return false
val tasksToRun = getTasksToRun(module)
if (tasksToRun.isEmpty()) return false
configuration.settings.externalProjectPath = projectPath
configuration.settings.taskNames = tasksToRun
val params = containingClasses.joinToString("") { aClass -> createTestFilter(aClass, psiMethod) ?: "" }
configuration.settings.scriptParameters = params.trim()
configuration.name = (if (containingClasses.size == 1) containingClasses[0].name + "." else "") + psiMethod.name
return true
}
companion object {
private fun createTestFilter(aClass: PsiClass, psiMethod: PsiMethod): String? {
return createTestFilter(aClass.qualifiedName, psiMethod.name)
}
fun createTestFilter(aClass: String?, method: String?): String? {
if (aClass == null) return null
val testFilterPattern = aClass + if (method == null) "" else '.' + method
return "--tests \"$testFilterPattern\" "
}
}
}

View File

@@ -31,6 +31,7 @@ import org.gradle.tooling.model.DomainObjectSet;
import org.gradle.tooling.model.idea.IdeaModule;
import org.gradle.util.GradleVersion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.model.ClassSetProjectImportExtraModelProvider;
import org.jetbrains.plugins.gradle.model.ExternalProject;
import org.jetbrains.plugins.gradle.model.ProjectImportAction;
import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
@@ -140,7 +141,7 @@ public abstract class AbstractModelBuilderTest {
try {
ProjectImportAction projectImportAction = new ProjectImportAction(false);
projectImportAction.addExtraProjectModelClasses(getModels());
projectImportAction.addProjectImportExtraModelProvider(new ClassSetProjectImportExtraModelProvider(getModels()));
BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
assertNotNull(initScript);

View File

@@ -0,0 +1,261 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.codeInsight.gradle;
import com.google.common.collect.Multimap;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
import org.gradle.tooling.BuildActionExecuter;
import org.gradle.tooling.GradleConnector;
import org.gradle.tooling.ProjectConnection;
import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
import org.gradle.tooling.model.DomainObjectSet;
import org.gradle.tooling.model.idea.IdeaModule;
import org.gradle.util.GradleVersion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.model.ExternalProject;
import org.jetbrains.plugins.gradle.model.ProjectImportAction;
import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeThat;
// part of org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest
@RunWith(value = Parameterized.class)
public abstract class AbstractModelBuilderTest {
public static final Object[][] SUPPORTED_GRADLE_VERSIONS = {{"3.5"}, {"4.9"}};
private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*: with Gradle-.*)\\]");
private static File ourTempDir;
@NotNull
private final String gradleVersion;
private File testDir;
private ProjectImportAction.AllModels allModels;
@Rule public TestName name = new TestName();
@Rule public VersionMatcherRule versionMatcherRule = new VersionMatcherRule();
public AbstractModelBuilderTest(@NotNull String gradleVersion) {
this.gradleVersion = gradleVersion;
}
@Parameterized.Parameters(name = "{index}: with Gradle-{0}")
public static Collection<Object[]> data() {
return Arrays.asList(SUPPORTED_GRADLE_VERSIONS);
}
@Before
public void setUp() throws Exception {
assumeThat(gradleVersion, versionMatcherRule.getMatcher());
ensureTempDirCreated();
String methodName = name.getMethodName();
Matcher m = TEST_METHOD_NAME_PATTERN.matcher(methodName);
if (m.matches()) {
methodName = m.group(1);
}
testDir = new File(ourTempDir, methodName);
FileUtil.ensureExists(testDir);
InputStream buildScriptStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.DEFAULT_SCRIPT_NAME);
try {
FileUtil.writeToFile(
new File(testDir, GradleConstants.DEFAULT_SCRIPT_NAME),
FileUtil.loadTextAndClose(buildScriptStream)
);
}
finally {
StreamUtil.closeStream(buildScriptStream);
}
InputStream settingsStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.SETTINGS_FILE_NAME);
try {
if (settingsStream != null) {
FileUtil.writeToFile(
new File(testDir, GradleConstants.SETTINGS_FILE_NAME),
FileUtil.loadTextAndClose(settingsStream)
);
}
}
finally {
StreamUtil.closeStream(settingsStream);
}
GradleConnector connector = GradleConnector.newConnector();
URI distributionUri = new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
connector.useDistribution(distributionUri);
connector.forProjectDirectory(testDir);
int daemonMaxIdleTime = 10;
try {
daemonMaxIdleTime = Integer.parseInt(System.getProperty("gradleDaemonMaxIdleTime", "10"));
}
catch (NumberFormatException ignore) {
}
((DefaultGradleConnector) connector).daemonMaxIdleTime(daemonMaxIdleTime, TimeUnit.SECONDS);
ProjectConnection connection = connector.connect();
try {
ProjectImportAction projectImportAction = new ProjectImportAction(false);
projectImportAction.addExtraProjectModelClasses(getModels());
BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
assertNotNull(initScript);
String jdkHome = IdeaTestUtil.requireRealJdkHome();
buildActionExecutor.setJavaHome(new File(jdkHome));
buildActionExecutor.setJvmArguments("-Xmx128m", "-XX:MaxPermSize=64m");
buildActionExecutor
.withArguments("--info", "--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath());
allModels = buildActionExecutor.run();
assertNotNull(allModels);
}
finally {
connection.close();
}
}
@NotNull
private static Set<Class> getToolingExtensionClasses() {
Set<Class> classes = ContainerUtil.<Class>set(
ExternalProject.class,
// gradle-tooling-extension-api jar
ProjectImportAction.class,
// gradle-tooling-extension-impl jar
ModelBuildScriptClasspathBuilderImpl.class,
Multimap.class,
ShortTypeHandling.class
);
ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses());
return classes;
}
@NotNull
private static Set<Class> doGetToolingExtensionClasses() {
return Collections.emptySet();
}
@After
public void tearDown() throws Exception {
if (testDir != null) {
FileUtil.delete(testDir);
}
}
protected abstract Set<Class> getModels();
private <T> Map<String, T> getModulesMap(final Class<T> aClass) {
DomainObjectSet<? extends IdeaModule> ideaModules = allModels.getIdeaProject().getModules();
final String filterKey = "to_filter";
Map<String, T> map = ContainerUtil.map2Map(ideaModules, new Function<IdeaModule, Pair<String, T>>() {
@Override
public Pair<String, T> fun(IdeaModule module) {
T value = allModels.getExtraProject(module, aClass);
String key = value != null ? module.getGradleProject().getPath() : filterKey;
return Pair.create(key, value);
}
});
map.remove(filterKey);
return map;
}
private static void ensureTempDirCreated() throws IOException {
if (ourTempDir != null) return;
ourTempDir = new File(FileUtil.getTempDirectory(), "gradleTests");
FileUtil.delete(ourTempDir);
FileUtil.ensureExists(ourTempDir);
}
public static class DistributionLocator {
private static final String RELEASE_REPOSITORY_ENV = "GRADLE_RELEASE_REPOSITORY";
private static final String SNAPSHOT_REPOSITORY_ENV = "GRADLE_SNAPSHOT_REPOSITORY";
private static final String GRADLE_RELEASE_REPO = "https://services.gradle.org/distributions";
private static final String GRADLE_SNAPSHOT_REPO = "https://services.gradle.org/distributions-snapshots";
@NotNull private final String myReleaseRepoUrl;
@NotNull private final String mySnapshotRepoUrl;
public DistributionLocator() {
this(DistributionLocator.getRepoUrl(false), DistributionLocator.getRepoUrl(true));
}
public DistributionLocator(@NotNull String releaseRepoUrl, @NotNull String snapshotRepoUrl) {
myReleaseRepoUrl = releaseRepoUrl;
mySnapshotRepoUrl = snapshotRepoUrl;
}
@NotNull
public URI getDistributionFor(@NotNull GradleVersion version) throws URISyntaxException {
return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
}
@NotNull
private String getDistributionRepository(@NotNull GradleVersion version) {
return version.isSnapshot() ? mySnapshotRepoUrl : myReleaseRepoUrl;
}
private static URI getDistribution(
@NotNull String repositoryUrl,
@NotNull GradleVersion version,
@NotNull String archiveName,
@NotNull String archiveClassifier
) throws URISyntaxException {
return new URI(String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier));
}
@NotNull
public static String getRepoUrl(boolean isSnapshotUrl) {
String envRepoUrl = System.getenv(isSnapshotUrl ? SNAPSHOT_REPOSITORY_ENV : RELEASE_REPOSITORY_ENV);
if (envRepoUrl != null) return envRepoUrl;
return isSnapshotUrl ? GRADLE_SNAPSHOT_REPO : GRADLE_RELEASE_REPO;
}
}
}

View File

@@ -11,18 +11,15 @@ import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
sealed class KotlinResourceRootType(val isTest: Boolean) : JpsElementTypeBase<JavaResourceRootProperties>(),
JpsModuleSourceRootType<JavaResourceRootProperties>, KotlinRootType {
sealed class KotlinResourceRootType() : JpsElementTypeBase<JavaResourceRootProperties>(),
JpsModuleSourceRootType<JavaResourceRootProperties> {
override fun createDefaultProperties() =
JpsJavaExtensionService.getInstance().createResourceRootProperties("", false)
override fun isTestRoot() = isTest
override fun isForTests() = isTest
override fun equals(other: Any?) = if (super.equals(other)) true else isSameRootType(this, other)
}
object ResourceKotlinRootType : KotlinResourceRootType(false)
object TestResourceKotlinRootType : KotlinResourceRootType(true)
object ResourceKotlinRootType : KotlinResourceRootType()
object TestResourceKotlinRootType : KotlinResourceRootType() {
override fun isForTests() = true
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.config
import org.jetbrains.jps.model.ex.JpsElementTypeBase
import org.jetbrains.jps.model.java.JavaResourceRootProperties
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
sealed class KotlinResourceRootType(val isTest: Boolean) : JpsElementTypeBase<JavaResourceRootProperties>(),
JpsModuleSourceRootType<JavaResourceRootProperties>, KotlinRootType {
override fun createDefaultProperties() =
JpsJavaExtensionService.getInstance().createResourceRootProperties("", false)
override fun isTestRoot() = isTest
override fun isForTests() = isTest
override fun equals(other: Any?) = if (super.equals(other)) true else isSameRootType(this, other)
}
object ResourceKotlinRootType : KotlinResourceRootType(false)
object TestResourceKotlinRootType : KotlinResourceRootType(true)

View File

@@ -11,21 +11,16 @@ import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
sealed class KotlinSourceRootType(val isTest: Boolean) : JpsElementTypeBase<JavaSourceRootProperties>(), JpsModuleSourceRootType<JavaSourceRootProperties>, KotlinRootType {
sealed class KotlinSourceRootType() : JpsElementTypeBase<JavaSourceRootProperties>(), JpsModuleSourceRootType<JavaSourceRootProperties> {
override fun createDefaultProperties() = JpsJavaExtensionService.getInstance().createSourceRootProperties("")
override fun isTestRoot() = isTest
override fun isForTests() = isTest
override fun equals(other: Any?) = if (super.equals(other)) true else isSameRootType(this, other)
}
object SourceKotlinRootType : KotlinSourceRootType(false)
object SourceKotlinRootType : KotlinSourceRootType()
object TestSourceKotlinRootType : KotlinSourceRootType(true)
object TestSourceKotlinRootType : KotlinSourceRootType() {
override fun isForTests() = true
}
val ALL_KOTLIN_SOURCE_ROOT_TYPES = setOf(SourceKotlinRootType, TestSourceKotlinRootType)

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.config
import org.jetbrains.jps.model.ex.JpsElementTypeBase
import org.jetbrains.jps.model.java.JavaSourceRootProperties
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
sealed class KotlinSourceRootType(val isTest: Boolean) : JpsElementTypeBase<JavaSourceRootProperties>(), JpsModuleSourceRootType<JavaSourceRootProperties>, KotlinRootType {
override fun createDefaultProperties() = JpsJavaExtensionService.getInstance().createSourceRootProperties("")
override fun isTestRoot() = isTest
override fun isForTests() = isTest
override fun equals(other: Any?) = if (super.equals(other)) true else isSameRootType(this, other)
}
object SourceKotlinRootType : KotlinSourceRootType(false)
object TestSourceKotlinRootType : KotlinSourceRootType(true)
val ALL_KOTLIN_SOURCE_ROOT_TYPES = setOf(SourceKotlinRootType, TestSourceKotlinRootType)

View File

@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.maven
import com.intellij.openapi.util.AsyncResult
import org.jetbrains.concurrency.AsyncPromise
import org.jetbrains.idea.maven.model.MavenArtifact
import org.jetbrains.idea.maven.project.MavenProject
import org.jetbrains.idea.maven.project.MavenProjectsManager
@@ -17,5 +17,5 @@ fun scheduleArtifactsDownloading(
toBeDownloaded: List<MavenArtifact>
) {
//true, false, AsyncResult()
projectsManager.scheduleArtifactsDownloading(projects, toBeDownloaded, true, false, AsyncResult())
projectsManager.scheduleArtifactsDownloading(projects, toBeDownloaded, true, false, AsyncPromise())
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.idea.maven
import com.intellij.openapi.util.AsyncResult
import org.jetbrains.idea.maven.model.MavenArtifact
import org.jetbrains.idea.maven.project.MavenProject
import org.jetbrains.idea.maven.project.MavenProjectsManager
//BUNCH: 183
fun scheduleArtifactsDownloading(
projectsManager: MavenProjectsManager,
projects: List<MavenProject>,
toBeDownloaded: List<MavenArtifact>
) {
//true, false, AsyncResult()
projectsManager.scheduleArtifactsDownloading(projects, toBeDownloaded, true, false, AsyncResult())
}

View File

@@ -7,14 +7,6 @@
interface="org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.androidDexer"
interface="org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.AndroidDexer"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.android.model.androidModuleInfoProvider"
interface="org.jetbrains.kotlin.android.model.AndroidModuleInfoProvider"
area="IDEA_MODULE"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.idePlatformKindResolution"
interface="org.jetbrains.kotlin.caches.resolve.IdePlatformKindResolution"/>

View File

@@ -0,0 +1,92 @@
<idea-plugin>
<extensionPoints>
<extensionPoint qualifiedName="org.jetbrains.kotlin.updater" beanClass="com.intellij.openapi.fileTypes.FileTypeExtensionPoint"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.projectConfigurator" interface="org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.declarationAttributeAltererExtension"
interface="org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.androidDexer"
interface="org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.AndroidDexer"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.android.model.androidModuleInfoProvider"
interface="org.jetbrains.kotlin.android.model.AndroidModuleInfoProvider"
area="IDEA_MODULE"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.idePlatformKindResolution"
interface="org.jetbrains.kotlin.caches.resolve.IdePlatformKindResolution"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.highlighterExtension"
interface="org.jetbrains.kotlin.idea.highlighter.HighlighterExtension"/>
<extensionPoint name="scratchFileLanguageProvider" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider"/>
</extensionPoint>
<extensionPoint qualifiedName="org.jetbrains.kotlin.binaryExtension"
interface="org.jetbrains.kotlin.idea.util.KotlinBinaryExtension"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.facetValidatorCreator"
interface="org.jetbrains.kotlin.idea.facet.KotlinFacetValidatorCreator"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.clearBuildState"
interface="org.jetbrains.kotlin.idea.compiler.configuration.ClearBuildStateExtension"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.newFileHook"
interface="org.jetbrains.kotlin.idea.actions.NewKotlinFileHook"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.completionExtension"
interface="org.jetbrains.kotlin.idea.completion.KotlinCompletionExtension"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.buildSystemTypeDetector"
interface="org.jetbrains.kotlin.idea.configuration.BuildSystemTypeDetector"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.idePlatformKind"
interface="org.jetbrains.kotlin.platform.IdePlatformKind"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.idePlatformKindTooling"
interface="org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.scriptRelatedModulesProvider"
interface="org.jetbrains.kotlin.idea.core.script.dependencies.ScriptRelatedModulesProvider"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.scriptDefinitionsProvider"
interface="kotlin.script.experimental.intellij.ScriptDefinitionsProvider"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.syntheticScopeProviderExtension"
interface="org.jetbrains.kotlin.synthetic.SyntheticScopeProviderExtension"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.resolveScopeEnlarger"
interface="org.jetbrains.kotlin.idea.caches.resolve.util.KotlinResolveScopeEnlarger"/>
</extensionPoints>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJavaModuleConfigurator"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsModuleConfigurator"/>
<scriptDefinitionContributor
id="ScriptTemplatesFromCompilerSettingsProvider"
implementation="org.jetbrains.kotlin.idea.script.ScriptTemplatesFromCompilerSettingsProvider"/>
<scriptDefinitionContributor
id="BridgeScriptDefinitionsContributor"
implementation="org.jetbrains.kotlin.idea.script.BridgeScriptDefinitionsContributor"/>
<scriptDefinitionContributor
id="ScriptTemplatesFromDependenciesProvider"
implementation="org.jetbrains.kotlin.idea.script.ScriptTemplatesFromDependenciesProvider"/>
<scriptDefinitionContributor id="StandardScriptDefinitionContributor"
order="last"
implementation="org.jetbrains.kotlin.idea.core.script.StandardScriptDefinitionContributor"/>
<scriptDefinitionContributor id="ConsoleScriptDefinitionContributor"
implementation="org.jetbrains.kotlin.console.ConsoleScriptDefinitionContributor"/>
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.JvmPlatformKindResolution"/>
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.JsPlatformKindResolution"/>
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.CommonPlatformKindResolution"/>
<scratchFileLanguageProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileLanguageProvider"/>
<scriptRelatedModulesProvider implementation="org.jetbrains.kotlin.idea.scratch.ScratchModuleDependencyProvider"/>
</extensions>
</idea-plugin>

View File

@@ -60,7 +60,7 @@
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
<orderEnumerationHandlerFactory implementation="org.jetbrains.kotlin.android.KotlinAndroidGradleOrderEnumerationHandler$FactoryImpl" order="first"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">

View File

@@ -0,0 +1,87 @@
<idea-plugin>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSFrameworkSupportProvider"/>
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSFrameworkSupportProvider"/>
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
<projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentKotlinGradleVersionInspection"
displayName="Kotlin Gradle and IDE plugins versions are different"
groupName="Kotlin"
enabledByDefault="true"
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentStdlibGradleVersionInspection"
displayName="Kotlin library and Gradle plugin versions are different"
groupName="Kotlin"
enabledByDefault="true"
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DeprecatedGradleDependencyInspection"
displayName="Deprecated library is used in Gradle"
groupName="Kotlin"
enabledByDefault="true"
cleanupTool="true"
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.GradleKotlinxCoroutinesDeprecationInspection"
displayName="Incompatible kotlinx.coroutines dependency is used with Kotlin 1.3+ in Gradle"
groupPath="Kotlin,Migration"
groupName="Gradle"
enabledByDefault="true"
language="Groovy"
hasStaticDescription="true"
level="ERROR"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
<orderEnumerationHandlerFactory implementation="org.jetbrains.kotlin.android.KotlinAndroidGradleOrderEnumerationHandler$FactoryImpl" order="first"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlinx.serialization.idea.KotlinSerializationGradleImportHandler"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsGradleModuleConfigurator"/>
<gradleModelFacade implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultGradleModelFacade"/>
<scriptDefinitionContributor implementation="org.jetbrains.kotlin.idea.core.script.GradleScriptDefinitionsContributor" order="first"/>
<scriptRelatedModulesProvider implementation="org.jetbrains.kotlin.idea.core.script.GradleBuildSrcModuleDependencyProvider"/>
<moduleBuilder implementation="org.jetbrains.kotlin.ide.konan.gradle.KotlinGradleNativeMultiplatformModuleBuilder"/>
<moduleBuilder implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSharedMultiplatformModuleBuilder"/>
<moduleBuilder implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleWebMultiplatformModuleBuilder"/>
<moduleBuilder implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleMobileMultiplatformModuleBuilder"/>
<moduleBuilder implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleMobileSharedMultiplatformModuleBuilder"/>
</extensions>
</idea-plugin>

View File

@@ -166,6 +166,11 @@
description="Whether to use multi resolve for UAST in Kotlin provided by `Call.resolveCandidates`, otherwise PsiPolyVariantReference-based multiResolve will be performed"
defaultValue="true"
restartRequired="false"/>
<registryKey key="kotlin.uast.force.uinjectionhost"
description="Whether to convert `KtStringTemplateExpression` to `KotlinStringTemplateUPolyadicExpression` in all cases"
defaultValue="false"
restartRequired="false"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.uast">

View File

@@ -0,0 +1,206 @@
<idea-plugin>
<extensionPoints>
<extensionPoint qualifiedName="org.jetbrains.kotlin.platformGradleDetector"
interface="org.jetbrains.kotlin.idea.inspections.gradle.KotlinPlatformGradleDetector"/>
</extensionPoints>
<application-components>
<component>
<implementation-class>org.jetbrains.kotlin.idea.JvmPluginStartupComponent</implementation-class>
</component>
</application-components>
<project-components>
<component>
<implementation-class>org.jetbrains.kotlin.idea.compiler.KotlinCompilerManager</implementation-class>
</component>
<component>
<implementation-class>org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerComponent</implementation-class>
</component>
<component>
<implementation-class>org.jetbrains.kotlin.idea.scratch.ui.ScratchFileHook</implementation-class>
</component>
<component>
<implementation-class>org.jetbrains.kotlin.idea.scratch.ScratchFileModuleInfoProvider</implementation-class>
</component>
</project-components>
<actions>
<!-- Kotlin Console REPL-->
<action id="KotlinConsoleREPL" class="org.jetbrains.kotlin.console.actions.RunKotlinConsoleAction"
text="Kotlin REPL"
icon="/org/jetbrains/kotlin/idea/icons/kotlin_launch_configuration.png">
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
</action>
<action id="ConfigureKotlinInProject" class="org.jetbrains.kotlin.idea.actions.ConfigureKotlinJavaInProjectAction"
text="Configure Kotlin in Project">
<add-to-group group-id="KotlinToolsGroup"/>
</action>
<action id="ConfigureKotlinJsInProject" class="org.jetbrains.kotlin.idea.actions.ConfigureKotlinJsInProjectAction"
text="Configure Kotlin (JavaScript) in Project">
<add-to-group group-id="KotlinToolsGroup"/>
</action>
<action id="ShowKotlinBytecode" class="org.jetbrains.kotlin.idea.actions.ShowKotlinBytecodeAction"
text="Show Kotlin Bytecode">
<add-to-group group-id="KotlinToolsGroup"/>
</action>
<action id="CreateIncrementalCompilationBackup"
class="org.jetbrains.kotlin.idea.internal.makeBackup.CreateIncrementalCompilationBackup" internal="true">
<add-to-group group-id="KotlinInternalGroup"/>
</action>
<action id="ReactivePostOpenProjectActionsAction" class="org.jetbrains.kotlin.idea.actions.internal.ReactivePostOpenProjectActionsAction"
text="Kotlin Project Post-Open Activity" internal="true">
<add-to-group group-id="KotlinInternalGroup"/>
</action>
<action id="AddToProblemApiInspection" class="org.jetbrains.kotlin.idea.inspections.api.AddIncompatibleApiAction"
text="Report as incompatible API">
</action>
<group id="Kotlin.XDebugger.Actions">
<action id="Kotlin.XDebugger.ToggleKotlinVariableView"
class="org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesView"
icon="/org/jetbrains/kotlin/idea/icons/kotlin.png"/>
</group>
<group id="Kotlin.XDebugger.Watches.Tree.Toolbar">
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
</group>
</actions>
<extensions defaultExtensionNs="com.intellij">
<projectService serviceInterface="org.jetbrains.kotlin.console.KotlinConsoleKeeper"
serviceImplementation="org.jetbrains.kotlin.console.KotlinConsoleKeeper"/>
<buildProcess.parametersProvider implementation="org.jetbrains.kotlin.idea.compiler.configuration.KotlinBuildProcessParametersProvider"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.scratch.ScratchFileAutoRunner"
serviceImplementation="org.jetbrains.kotlin.idea.scratch.ScratchFileAutoRunner"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
<applicationService serviceImplementation="org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesState"/>
<debugger.asyncStackTraceProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinCoroutinesAsyncStackTraceProvider"/>
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
<debugger.positionManagerFactory implementation="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerFactory"/>
<debugger.codeFragmentFactory implementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory"/>
<debuggerEditorTextProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider"/>
<debuggerClassFilterProvider implementation="org.jetbrains.kotlin.idea.debugger.filter.KotlinDebuggerInternalClassesFilterProvider"/>
<debugger.nodeRenderer implementation="org.jetbrains.kotlin.idea.debugger.render.KotlinClassWithDelegatedPropertyRenderer"/>
<debugger.sourcePositionProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinSourcePositionProvider"/>
<debugger.sourcePositionHighlighter implementation="org.jetbrains.kotlin.idea.debugger.KotlinSourcePositionHighlighter"/>
<debugger.frameExtraVarsProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider"/>
<debugger.extraSteppingFilter implementation="org.jetbrains.kotlin.idea.KotlinExtraSteppingFilter"/>
<xdebugger.settings implementation="org.jetbrains.kotlin.idea.debugger.KotlinDebuggerSettings"/>
<xdebugger.breakpointType implementation="org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType"/>
<xdebugger.breakpointType implementation="org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinLineBreakpointType" order="first"/>
<debugger.syntheticProvider implementation="org.jetbrains.kotlin.idea.debugger.filter.KotlinSyntheticTypeComponentProvider"/>
<debugger.javaBreakpointHandlerFactory implementation="org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointHandlerFactory"/>
<debugger.javaBreakpointHandlerFactory implementation="org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinLineBreakpointHandlerFactory"/>
<debugger.jvmSteppingCommandProvider implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSteppingCommandProvider"/>
<debugger.simplePropertyGetterProvider implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSimpleGetterProvider"/>
<framework.type implementation="org.jetbrains.kotlin.idea.framework.JavaFrameworkType"/>
<projectTemplatesFactory implementation="org.jetbrains.kotlin.idea.framework.KotlinTemplatesFactory" />
<library.presentationProvider implementation="org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider"/>
<configurationType implementation="org.jetbrains.kotlin.idea.run.KotlinRunConfigurationType"/>
<configurationType implementation="org.jetbrains.kotlin.idea.run.script.standalone.KotlinStandaloneScriptRunConfigurationType"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinRunConfigurationProducer"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.script.standalone.KotlinStandaloneScriptRunConfigurationProducer"/>
<library.type implementation="org.jetbrains.kotlin.idea.framework.JSLibraryType"/>
<library.javaSourceRootDetector implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceRootDetector"/>
<multipleRunLocationsProvider implementation="org.jetbrains.kotlin.idea.run.multiplatform.KotlinMultiplatformRunLocationsProvider"/>
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.configuration.KotlinSetupEnvironmentNotificationProvider"/>
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinAlternativeSourceNotificationProvider"/>
<consoleFilterProvider implementation="org.jetbrains.kotlin.idea.run.KotlinConsoleFilterProvider"/>
<exceptionFilter implementation="org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterFactory" order="first"/>
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.configuration.KotlinExternalSystemSyncListener"/>
<lang.surroundDescriptor language="kotlin"
implementationClass="org.jetbrains.kotlin.idea.debugger.surroundWith.KotlinDebuggerExpressionSurroundDescriptor"/>
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider"/>
<scratch.creationHelper language="kotlin"
implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileCreationHelper"/>
<localInspection
groupName="Plugin DevKit"
shortName="IncompatibleAPI"
enabledByDefault="false"
level="ERROR"
displayName="Incompatible API usage"
implementationClass="org.jetbrains.kotlin.idea.inspections.api.IncompatibleAPIInspection"/>
<projectService serviceInterface="org.jetbrains.uast.kotlin.KotlinUastResolveProviderService"
serviceImplementation="org.jetbrains.uast.kotlin.internal.IdeaKotlinUastResolveProviderService"/>
<applicationService
serviceInterface="org.jetbrains.kotlin.platform.DefaultIdeTargetPlatformKindProvider"
serviceImplementation="org.jetbrains.kotlin.platform.impl.IdeaDefaultIdeTargetPlatformKindProvider"/>
<registryKey key="kotlin.use.ultra.light.classes"
description="Whether to use an experimental implementation of Kotlin-as-Java classes"
defaultValue="false"
restartRequired="false"/>
<registryKey key="kotlin.uast.multiresolve.enabled"
description="Whether to use multi resolve for UAST in Kotlin provided by `Call.resolveCandidates`, otherwise PsiPolyVariantReference-based multiResolve will be performed"
defaultValue="true"
restartRequired="false"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.uast">
<uastLanguagePlugin implementation="org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<diagnosticSuppressor implementation="org.jetbrains.kotlin.idea.debugger.DiagnosticSuppressorForDebugger"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.samWithReceiver.ide.IdeSamWithReceiverComponentContributor"/>
<declarationAttributeAltererExtension implementation="org.jetbrains.kotlin.allopen.ide.IdeAllOpenDeclarationAttributeAltererExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgComponentContainerContributor"/>
<expressionCodegenExtension implementation="org.jetbrains.kotlin.noarg.NoArgExpressionCodegenExtension"/>
<defaultErrorMessages implementation="org.jetbrains.kotlin.noarg.diagnostic.DefaultErrorMessagesNoArg"/>
<completionExtension implementation="org.jetbrains.kotlin.idea.properties.PropertyKeyCompletion"/>
<newFileHook implementation="org.jetbrains.kotlin.idea.configuration.NewKotlinFileConfigurationHook"/>
<quickFixContributor implementation="org.jetbrains.kotlin.idea.quickfix.JvmQuickFixRegistrar"/>
<clearBuildState implementation="org.jetbrains.kotlin.idea.compiler.configuration.ClearBuildManagerState"/>
<facetValidatorCreator implementation="org.jetbrains.kotlin.idea.facet.KotlinLibraryValidatorCreator"/>
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleJavaFrameworkSupportProvider" />
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleKotlinDSLKotlinJavaFrameworkSupportProvider" />
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleKotlinDSLKotlinJSFrameworkSupportProvider" />
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleGroovyFrameworkSupportProvider" />
<idePlatformKind implementation="org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind"/>
<idePlatformKind implementation="org.jetbrains.kotlin.platform.impl.JsIdePlatformKind"/>
<idePlatformKindTooling implementation="org.jetbrains.kotlin.idea.core.platform.impl.JvmIdePlatformKindTooling"/>
<idePlatformKindTooling implementation="org.jetbrains.kotlin.idea.core.platform.impl.JsIdePlatformKindTooling"/>
<syntheticScopeProviderExtension implementation="org.jetbrains.kotlin.idea.debugger.evaluate.DebuggerFieldSyntheticScopeProvider"/>
<expressionCodegenExtension implementation="org.jetbrains.kotlin.idea.debugger.evaluate.DebuggerFieldExpressionCodegenExtension"/>
<completionInformationProvider implementation="org.jetbrains.kotlin.idea.debugger.evaluate.DebuggerFieldCompletionInformationProvider" />
</extensions>
</idea-plugin>

View File

@@ -13,7 +13,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<version>@snapshot@</version>
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
<idea-version since-build="183.3283.2" until-build="183.*"/>
<idea-version since-build="191.5109.14" until-build="192.*"/>
<depends>com.intellij.modules.platform</depends>
@@ -25,7 +25,6 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle.java</depends>
<depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
<depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
<depends optional="true" config-file="android.xml">org.jetbrains.android</depends>
<depends optional="true" config-file="coverage.xml">Coverage</depends>
<depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
<depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
@@ -69,7 +68,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
</extensions>
<extensions defaultExtensionNs="com.intellij.codeInsight">
<nonBlockingContextChecker implementation="org.jetbrains.kotlin.idea.inspections.blockingCallsDetection.CoroutineNonBlockingContextChecker"/>
<nonBlockingContextChecker implementation="org.jetbrains.kotlin.idea.inspections.blockingCallsDetection.CoroutineNonBlockingContextChecker"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,75 @@
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2" url="http://kotlinlang.org" allow-bundled-update="true">
<id>org.jetbrains.kotlin</id>
<name>Kotlin</name>
<description><![CDATA[
The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<br>
<a href="http://kotlinlang.org/docs/tutorials/getting-started.html">Getting Started in IntelliJ IDEA</a><br>
<a href="http://kotlinlang.org/docs/tutorials/kotlin-android.html">Getting Started in Android Studio</a><br>
<a href="http://slack.kotlinlang.org/">Public Slack</a><br>
<a href="https://youtrack.jetbrains.com/issues/KT">Issue tracker</a><br>
]]></description>
<version>@snapshot@</version>
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
<idea-version since-build="183.3283.2" until-build="183.*"/>
<depends>com.intellij.modules.platform</depends>
<!-- required for Kotlin/Native plugin -->
<depends optional="true">org.jetbrains.kotlin.native.platform.deps</depends>
<depends optional="true" config-file="junit.xml">JUnit</depends>
<depends optional="true" config-file="gradle.xml">org.jetbrains.plugins.gradle</depends>
<depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle.java</depends>
<depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
<depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
<depends optional="true" config-file="android.xml">org.jetbrains.android</depends>
<depends optional="true" config-file="coverage.xml">Coverage</depends>
<depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
<depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
<depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
<depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
<!-- CIDR-PLUGIN-PLACEHOLDER-START -->
<depends>com.intellij.modules.idea</depends>
<depends>com.intellij.modules.java</depends>
<depends optional="true" config-file="javaScriptDebug.xml">JavaScriptDebugger</depends>
<depends optional="true" config-file="kotlin-copyright.xml">com.intellij.copyright</depends>
<depends optional="true" config-file="injection.xml">org.intellij.intelliLang</depends>
<!-- CIDR-PLUGIN-PLACEHOLDER-END -->
<xi:include href="plugin-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
<!-- CIDR-PLUGIN-EXCLUDE-START -->
<xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
<!-- CIDR-PLUGIN-EXCLUDE-END -->
<xi:include href="native.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="tipsAndTricks.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="kotlinx-serialization.xml" xpointer="xpointer(/idea-plugin/*)"/>
<extensionPoints>
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
</extensionPoints>
<xi:include href="plugin-kotlin-extensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
<extensions defaultExtensionNs="com.intellij.jvm">
<declarationSearcher language="kotlin" implementationClass="org.jetbrains.kotlin.idea.jvm.KotlinDeclarationSearcher"/>
</extensions>
<extensions defaultExtensionNs="com.intellij.codeInsight">
<nonBlockingContextChecker implementation="org.jetbrains.kotlin.idea.inspections.blockingCallsDetection.CoroutineNonBlockingContextChecker"/>
</extensions>
</idea-plugin>

View File

@@ -5,38 +5,51 @@
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.lang.jvm.actions.AnnotationRequest
import com.intellij.lang.jvm.actions.ChangeParametersRequest
import com.intellij.lang.jvm.actions.ExpectedParameter
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.JvmPsiConversionHelper
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameterList
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
internal class ChangeMethodParameters(
target: KtNamedFunction,
private val request: List<Pair<Name, KotlinType>>,
private val isValid: () -> Boolean
val request: ChangeParametersRequest
) : KotlinQuickFixAction<KtNamedFunction>(target) {
override fun getText(): String {
val parametersString = request.joinToString(", ", "(", ")") { (name, type) ->
"${name.asString()}: ${IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(type)}"
val target = element ?: return "<not available>"
val helper = JvmPsiConversionHelper.getInstance(target.project)
val parametersString = request.expectedParameters.joinToString(", ", "(", ")") { ep ->
val kotlinType =
ep.expectedTypes.firstOrNull()?.theType?.let { helper.convertType(it).resolveToKotlinType(target.getResolutionFacade()) }
"${ep.semanticNames.firstOrNull() ?: "parameter"}: ${kotlinType?.let {
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(it)
} ?: "<error>"}"
}
val shortenParameterString = StringUtil.shortenTextWithEllipsis(parametersString, 30, 5)
@@ -45,12 +58,122 @@ internal class ChangeMethodParameters(
override fun getFamilyName(): String = QuickFixBundle.message("change.method.parameters.family")
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean = element != null && isValid()
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean = element != null && request.isValid
private sealed class ParameterModification {
data class Keep(val ktParameter: KtParameter) : ParameterModification()
data class Remove(val ktParameter: KtParameter) : ParameterModification()
data class Add(
val name: String,
val ktType: KotlinType,
val expectedAnnotations: Collection<AnnotationRequest>,
val beforeAnchor: KtParameter?
) : ParameterModification()
}
private tailrec fun getParametersModifications(
target: KtNamedFunction,
currentParameters: List<KtParameter>,
expectedParameters: List<ExpectedParameter>,
index: Int = 0,
collected: List<ParameterModification> = ArrayList(expectedParameters.size)
): List<ParameterModification> {
val expectedHead = expectedParameters.firstOrNull() ?: return collected + currentParameters.map { ParameterModification.Remove(it) }
if (expectedHead is ChangeParametersRequest.ExistingParameterWrapper) {
val expectedExistingParameter = expectedHead.existingKtParameter
if (expectedExistingParameter == null) {
LOG.error("can't find the kotlinOrigin for parameter ${expectedHead.existingParameter} at index $index")
return collected
}
val existingInTail = currentParameters.indexOf(expectedExistingParameter)
if (existingInTail == -1) {
throw IllegalArgumentException("can't find existing for parameter ${expectedHead.existingParameter} at index $index")
}
return getParametersModifications(
target,
currentParameters.subList(existingInTail + 1, currentParameters.size),
expectedParameters.subList(1, expectedParameters.size),
index,
collected
+ currentParameters.subList(0, existingInTail).map { ParameterModification.Remove(it) }
+ ParameterModification.Keep(expectedExistingParameter)
)
}
val helper = JvmPsiConversionHelper.getInstance(target.project)
val theType = expectedHead.expectedTypes.firstOrNull()?.theType ?: return emptyList()
val kotlinType = helper.convertType(theType).resolveToKotlinType(target.getResolutionFacade()) ?: return emptyList()
return getParametersModifications(
target,
currentParameters,
expectedParameters.subList(1, expectedParameters.size),
index + 1,
collected + ParameterModification.Add(
expectedHead.semanticNames.firstOrNull() ?: "param$index",
kotlinType,
expectedHead.expectedAnnotations,
currentParameters.firstOrNull { anchor ->
expectedParameters.any {
it is ChangeParametersRequest.ExistingParameterWrapper && it.existingKtParameter == anchor
}
})
)
}
private val ChangeParametersRequest.ExistingParameterWrapper.existingKtParameter
get() = (existingParameter as? KtLightElement<*, *>)?.kotlinOrigin as? KtParameter
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val target = element ?: return
val functionDescriptor = target.resolveToDescriptorIfAny(BodyResolveMode.FULL) ?: return
val parameterActions = getParametersModifications(target, target.valueParameters, request.expectedParameters)
val parametersGenerated = parameterActions.filterIsInstance<ParameterModification.Add>().let {
it zip generateParameterList(project, functionDescriptor, it).parameters
}.toMap()
for (action in parameterActions) {
when (action) {
is ParameterModification.Add -> {
val parameter = parametersGenerated.getValue(action)
for (expectedAnnotation in action.expectedAnnotations) {
addAnnotationEntry(parameter, expectedAnnotation, null)
}
val anchor = action.beforeAnchor
if (anchor != null) {
target.valueParameterList!!.addParameterBefore(parameter, anchor)
} else {
target.valueParameterList!!.addParameter(parameter)
}
}
is ParameterModification.Keep -> {
// Do nothing
}
is ParameterModification.Remove -> {
target.valueParameterList!!.removeParameter(action.ktParameter)
}
}
}
ShortenReferences.DEFAULT.process(target.valueParameterList!!)
}
private fun generateParameterList(
project: Project,
functionDescriptor: FunctionDescriptor,
paramsToAdd: List<ParameterModification.Add>
): KtParameterList {
val newFunctionDescriptor = SimpleFunctionDescriptorImpl.create(
functionDescriptor.containingDeclaration,
functionDescriptor.annotations,
@@ -62,11 +185,11 @@ internal class ChangeMethodParameters(
functionDescriptor.extensionReceiverParameter?.copy(this),
functionDescriptor.dispatchReceiverParameter,
functionDescriptor.typeParameters,
request.withIndex().map { (index, parameter) ->
paramsToAdd.mapIndexed { index, parameter ->
ValueParameterDescriptorImpl(
this, null, index, Annotations.EMPTY,
Name.identifier(parameter.first.toString()),
parameter.second, false,
Name.identifier(parameter.name),
parameter.ktType, false,
false, false, null, SourceElement.NO_SOURCE
)
},
@@ -92,9 +215,15 @@ internal class ChangeMethodParameters(
}
}
val newParameterList = target.valueParameterList!!.replace(newFunction.valueParameterList!!) as KtParameterList
ShortenReferences.DEFAULT.process(newParameterList)
return newFunction.valueParameterList!!
}
companion object {
fun create(ktNamedFunction: KtNamedFunction, request: ChangeParametersRequest): ChangeMethodParameters? =
ChangeMethodParameters(ktNamedFunction, request)
}
}
}
private val LOG = Logger.getInstance(ChangeMethodParameters::class.java)

View File

@@ -192,54 +192,6 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
.toTypedArray()
}
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
val results = ArrayList<PsiTypeParameter>()
accept(
object : PsiTypeVisitor<Unit>() {
override fun visitArrayType(arrayType: PsiArrayType) {
arrayType.componentType.accept(this)
}
override fun visitClassType(classType: PsiClassType) {
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
classType.parameters.forEach { it.accept(this) }
}
override fun visitWildcardType(wildcardType: PsiWildcardType) {
wildcardType.bound?.accept(this)
}
}
)
return results
}
private fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
val typeParameters = collectTypeParameters()
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
val dummyClassDescriptor = ClassDescriptorImpl(
dummyPackageDescriptor,
Name.identifier("Dummy"),
Modality.FINAL,
ClassKind.CLASS,
emptyList(),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
)
val typeParameterResolver = object : TypeParameterResolver {
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
val index = typeParameters.indexOf(psiTypeParameter)
if (index < 0) return null
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
}
}
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
}
private fun ExpectedTypes.toKotlinTypeInfo(resolutionFacade: ResolutionFacade): TypeInfo {
val candidateTypes = flatMapTo(LinkedHashSet<KotlinType>()) {
@@ -485,67 +437,117 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
val target = pointer.element ?: return
val annotationClass = JavaPsiFacade.getInstance(project).findClass(request.qualifiedName, target.resolveScope)
val kotlinAnnotation = annotationClass?.language == KotlinLanguage.INSTANCE
val annotationUseSiteTargetPrefix = run prefixEvaluation@{
if (annotationTarget == null) return@prefixEvaluation ""
val moduleDescriptor = (target as? KtDeclaration)?.resolveToDescriptorIfAny()?.module ?: return@prefixEvaluation ""
val annotationClassDescriptor = moduleDescriptor.resolveClassByFqName(
FqName(request.qualifiedName), NoLookupLocation.FROM_IDE
) ?: return@prefixEvaluation ""
val applicableTargetSet =
AnnotationChecker.applicableTargetSet(annotationClassDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET
if (KotlinTarget.PROPERTY !in applicableTargetSet) return@prefixEvaluation ""
"${annotationTarget.renderName}:"
}
val entry = target.addAnnotationEntry(
KtPsiFactory(target)
.createAnnotationEntry(
"@$annotationUseSiteTargetPrefix${request.qualifiedName}${
request.attributes.mapIndexed { i, p ->
if (!kotlinAnnotation && i == 0 && p.name == "value")
renderAttributeValue(p.value).toString()
else
"${p.name} = ${renderAttributeValue(p.value)}"
}.joinToString(", ", "(", ")")
}"
)
)
val entry = addAnnotationEntry(target, request, annotationTarget)
ShortenReferences.DEFAULT.process(entry)
}
private fun renderAttributeValue(annotationAttributeRequest: AnnotationAttributeValueRequest) =
when (annotationAttributeRequest) {
is AnnotationAttributeValueRequest.PrimitiveValue -> annotationAttributeRequest.value
is AnnotationAttributeValueRequest.StringValue -> "\"" + annotationAttributeRequest.value + "\""
}
}
override fun createChangeParametersActions(target: JvmMethod, request: ChangeParametersRequest): List<IntentionAction> {
val ktNamedFunction = (target as? KtLightElement<*, *>)?.kotlinOrigin as? KtNamedFunction ?: return emptyList()
val helper = JvmPsiConversionHelper.getInstance(target.project)
val params = request.expectedParameters.map { ep ->
val name = ep.semanticNames.singleOrNull() ?: return emptyList()
val expectedType = ep.expectedTypes.singleOrNull() ?: return emptyList()
val kotlinType =
helper.convertType(expectedType.theType).resolveToKotlinType(ktNamedFunction.getResolutionFacade()) ?: return emptyList()
Name.identifier(name) to kotlinType
}
return listOf(ChangeMethodParameters(ktNamedFunction, params, { request.isValid }))
return listOfNotNull(ChangeMethodParameters.create(ktNamedFunction, request))
}
}
internal fun addAnnotationEntry(
target: KtModifierListOwner,
request: AnnotationRequest,
annotationTarget: AnnotationUseSiteTarget?
): KtAnnotationEntry {
val annotationClass = JavaPsiFacade.getInstance(target.project).findClass(request.qualifiedName, target.resolveScope)
val kotlinAnnotation = annotationClass?.language == KotlinLanguage.INSTANCE
val annotationUseSiteTargetPrefix = run prefixEvaluation@{
if (annotationTarget == null) return@prefixEvaluation ""
val moduleDescriptor = (target as? KtDeclaration)?.resolveToDescriptorIfAny()?.module ?: return@prefixEvaluation ""
val annotationClassDescriptor = moduleDescriptor.resolveClassByFqName(
FqName(request.qualifiedName), NoLookupLocation.FROM_IDE
) ?: return@prefixEvaluation ""
val applicableTargetSet =
AnnotationChecker.applicableTargetSet(annotationClassDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET
if (KotlinTarget.PROPERTY !in applicableTargetSet) return@prefixEvaluation ""
"${annotationTarget.renderName}:"
}
// could be generated via descriptor when KT-30478 is fixed
val entry = target.addAnnotationEntry(
KtPsiFactory(target)
.createAnnotationEntry(
"@$annotationUseSiteTargetPrefix${request.qualifiedName}${
request.attributes.takeIf { it.isNotEmpty() }?.mapIndexed { i, p ->
if (!kotlinAnnotation && i == 0 && p.name == "value")
renderAttributeValue(p.value).toString()
else
"${p.name} = ${renderAttributeValue(p.value)}"
}?.joinToString(", ", "(", ")") ?: ""
}"
)
)
return entry
}
private fun renderAttributeValue(annotationAttributeRequest: AnnotationAttributeValueRequest) =
when (annotationAttributeRequest) {
is AnnotationAttributeValueRequest.PrimitiveValue -> annotationAttributeRequest.value
is AnnotationAttributeValueRequest.StringValue -> "\"" + annotationAttributeRequest.value + "\""
}
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
val results = ArrayList<PsiTypeParameter>()
accept(
object : PsiTypeVisitor<Unit>() {
override fun visitArrayType(arrayType: PsiArrayType) {
arrayType.componentType.accept(this)
}
override fun visitClassType(classType: PsiClassType) {
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
classType.parameters.forEach { it.accept(this) }
}
override fun visitWildcardType(wildcardType: PsiWildcardType) {
wildcardType.bound?.accept(this)
}
}
)
return results
}
internal fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
val typeParameters = collectTypeParameters()
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
val dummyClassDescriptor = ClassDescriptorImpl(
dummyPackageDescriptor,
Name.identifier("Dummy"),
Modality.FINAL,
ClassKind.CLASS,
emptyList(),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
)
val typeParameterResolver = object : TypeParameterResolver {
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
val index = typeParameters.indexOf(psiTypeParameter)
if (index < 0) return null
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
}
}
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
}
private fun JvmPsiConversionHelper.asPsiType(param: Pair<SuggestedNameInfo, List<ExpectedType>>): PsiType? =
param.second.firstOrNull()?.theType?.let { convertType(it) }

View File

@@ -64,6 +64,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.utils.ifEmpty
import org.jetbrains.kotlin.utils.keysToMap
import java.lang.AssertionError
import java.util.*
interface Mover : (KtNamedDeclaration, KtElement) -> KtNamedDeclaration {
@@ -202,12 +203,8 @@ class MoveKotlinDeclarationsProcessor(
fun collectUsages(kotlinToLightElements: Map<KtNamedDeclaration, List<PsiNamedElement>>, result: MutableCollection<UsageInfo>) {
kotlinToLightElements.values.flatten().flatMapTo(result) { lightElement ->
val searchScope = getSearchScope(lightElement) ?: return@flatMapTo emptyList()
val newFqName = StringUtil.getQualifiedName(newContainerName, lightElement.name)
val newFqNameForKt = StringUtil.getQualifiedName(
newContainerName,
lightElement.namedUnwrappedElement?.name?: lightElement.name
)
val elementName = lightElement.name ?: return@flatMapTo emptyList()
val newFqName = StringUtil.getQualifiedName(newContainerName, elementName)
val foundReferences = HashSet<PsiReference>()
val results = ReferencesSearch
@@ -235,19 +232,6 @@ class MoveKotlinDeclarationsProcessor(
if (handler !is MoveKotlinClassHandler) handler.preprocessUsages(results)
}
results
.filter { it is NonCodeUsageInfo && it.file is KtFile }
.forEach {
val newText = NonCodeUsageInfo::class.java.getField("newText")
// A 'newText' is marked as final initially, but here we need to change it to prevent
// light-class names in kotlin files.
val oldAccessibility = newText.isAccessible
newText.isAccessible = true
newText.set(it, newFqNameForKt)
// Restore initial accessibility of 'newText' field.
newText.isAccessible = oldAccessibility
}
results
}
}

View File

@@ -0,0 +1,389 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.util.EditorHelper
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.move.MoveCallback
import com.intellij.refactoring.move.MoveMultipleElementsViewDescriptor
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
import com.intellij.refactoring.rename.RenameUtil
import com.intellij.refactoring.util.NonCodeUsageInfo
import com.intellij.refactoring.util.RefactoringUIUtil
import com.intellij.refactoring.util.TextOccurrencesUtil
import com.intellij.usageView.UsageInfo
import com.intellij.usageView.UsageViewBundle
import com.intellij.usageView.UsageViewDescriptor
import com.intellij.usageView.UsageViewUtil
import com.intellij.util.IncorrectOperationException
import com.intellij.util.containers.MultiMap
import gnu.trove.THashMap
import gnu.trove.TObjectHashingStrategy
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToBeShortenedDescendantsToWaitingSet
import org.jetbrains.kotlin.idea.core.deleteSingle
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.refactoring.broadcastRefactoringExit
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.idea.search.restrictByFileType
import org.jetbrains.kotlin.idea.util.projectStructure.module
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.utils.ifEmpty
import org.jetbrains.kotlin.utils.keysToMap
import java.util.*
interface Mover : (KtNamedDeclaration, KtElement) -> KtNamedDeclaration {
object Default : Mover {
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
return when (targetContainer) {
is KtFile -> {
val declarationContainer: KtElement =
if (targetContainer.isScript()) targetContainer.script!!.blockExpression else targetContainer
declarationContainer.add(originalElement) as KtNamedDeclaration
}
is KtClassOrObject -> targetContainer.addDeclaration(originalElement)
else -> error("Unexpected element: ${targetContainer.getElementTextWithContext()}")
}.apply {
val container = originalElement.containingClassOrObject
if (container is KtObjectDeclaration && container.isCompanion() && container.declarations.singleOrNull() == originalElement) {
container.deleteSingle()
}
else {
originalElement.deleteSingle()
}
}
}
}
}
sealed class MoveSource {
abstract val elementsToMove: Collection<KtNamedDeclaration>
class Elements(override val elementsToMove: Collection<KtNamedDeclaration>) : MoveSource()
class File(val file: KtFile) : MoveSource() {
override val elementsToMove: Collection<KtNamedDeclaration>
get() = file.declarations.filterIsInstance<KtNamedDeclaration>()
}
}
fun MoveSource(declaration: KtNamedDeclaration) = MoveSource.Elements(listOf(declaration))
fun MoveSource(declarations: Collection<KtNamedDeclaration>) = MoveSource.Elements(declarations)
fun MoveSource(file: KtFile) = MoveSource.File(file)
class MoveDeclarationsDescriptor @JvmOverloads constructor(
val project: Project,
val moveSource: MoveSource,
val moveTarget: KotlinMoveTarget,
val delegate: MoveDeclarationsDelegate,
val searchInCommentsAndStrings: Boolean = true,
val searchInNonCode: Boolean = true,
val deleteSourceFiles: Boolean = false,
val moveCallback: MoveCallback? = null,
val openInEditor: Boolean = false,
val allElementsToMove: List<PsiElement>? = null,
val analyzeConflicts: Boolean = true,
val searchReferences: Boolean = true
)
class ConflictUsageInfo(element: PsiElement, val messages: Collection<String>) : UsageInfo(element)
private object ElementHashingStrategy : TObjectHashingStrategy<PsiElement> {
override fun equals(e1: PsiElement?, e2: PsiElement?): Boolean {
if (e1 === e2) return true
// Name should be enough to distinguish different light elements based on the same original declaration
if (e1 is KtLightDeclaration<*, *> && e2 is KtLightDeclaration<*, *>) {
return e1.kotlinOrigin == e2.kotlinOrigin && e1.name == e2.name
}
return e1 == e2
}
override fun computeHashCode(e: PsiElement?): Int {
return when (e) {
null -> 0
is KtLightDeclaration<*, *> -> (e.kotlinOrigin?.hashCode() ?: 0) * 31 + (e.name?.hashCode() ?: 0)
else -> e.hashCode()
}
}
}
class MoveKotlinDeclarationsProcessor(
val descriptor: MoveDeclarationsDescriptor,
val mover: Mover = Mover.Default) : BaseRefactoringProcessor(descriptor.project) {
companion object {
private val REFACTORING_NAME = "Move declarations"
val REFACTORING_ID = "move.kotlin.declarations"
}
val project get() = descriptor.project
private var nonCodeUsages: Array<NonCodeUsageInfo>? = null
private val moveEntireFile = descriptor.moveSource is MoveSource.File
private val elementsToMove = descriptor.moveSource.elementsToMove.filter { e -> e.parent != descriptor.moveTarget.getTargetPsiIfExists(e) }
private val kotlinToLightElementsBySourceFile = elementsToMove
.groupBy { it.containingKtFile }
.mapValues { it.value.keysToMap { it.toLightElements().ifEmpty { listOf(it) } } }
private val conflicts = MultiMap<PsiElement, String>()
override fun getRefactoringId() = REFACTORING_ID
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>): UsageViewDescriptor {
val targetContainerFqName = descriptor.moveTarget.targetContainerFqName?.let {
if (it.isRoot) UsageViewBundle.message("default.package.presentable.name") else it.asString()
}
return MoveMultipleElementsViewDescriptor(elementsToMove.toTypedArray(), targetContainerFqName)
}
fun getConflictsAsUsages(): List<UsageInfo> = conflicts.entrySet().map { ConflictUsageInfo(it.key, it.value) }
public override fun findUsages(): Array<UsageInfo> {
if (!descriptor.searchReferences || elementsToMove.isEmpty()) return UsageInfo.EMPTY_ARRAY
val newContainerName = descriptor.moveTarget.targetContainerFqName?.asString() ?: ""
fun getSearchScope(element: PsiElement): GlobalSearchScope? {
val projectScope = project.projectScope()
val ktDeclaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return projectScope
if (ktDeclaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) return projectScope
val moveTarget = descriptor.moveTarget
val (oldContainer, newContainer) = descriptor.delegate.getContainerChangeInfo(ktDeclaration, moveTarget)
val targetModule = moveTarget.getTargetModule(project) ?: return projectScope
if (oldContainer != newContainer || ktDeclaration.module != targetModule) return projectScope
// Check if facade class may change
if (newContainer is ContainerInfo.Package) {
val javaScope = projectScope.restrictByFileType(JavaFileType.INSTANCE)
val currentFile = ktDeclaration.containingKtFile
val newFile = when (moveTarget) {
is KotlinMoveTargetForExistingElement -> moveTarget.targetElement as? KtFile ?: return null
is KotlinMoveTargetForDeferredFile -> return javaScope
else -> return null
}
val currentFacade = currentFile.findFacadeClass()
val newFacade = newFile.findFacadeClass()
return if (currentFacade?.qualifiedName != newFacade?.qualifiedName) javaScope else null
}
return null
}
fun collectUsages(kotlinToLightElements: Map<KtNamedDeclaration, List<PsiNamedElement>>, result: MutableCollection<UsageInfo>) {
kotlinToLightElements.values.flatten().flatMapTo(result) { lightElement ->
val searchScope = getSearchScope(lightElement) ?: return@flatMapTo emptyList()
val newFqName = StringUtil.getQualifiedName(newContainerName, lightElement.name)
val newFqNameForKt = StringUtil.getQualifiedName(
newContainerName,
lightElement.namedUnwrappedElement?.name?: lightElement.name
)
val foundReferences = HashSet<PsiReference>()
val results = ReferencesSearch
.search(lightElement, searchScope)
.mapNotNullTo(ArrayList()) { ref ->
if (foundReferences.add(ref) && elementsToMove.none { it.isAncestor(ref.element)}) {
createMoveUsageInfoIfPossible(ref, lightElement, true, false)
}
else null
}
val name = lightElement.getKotlinFqName()?.quoteIfNeeded()?.asString()
if (name != null) {
TextOccurrencesUtil.findNonCodeUsages(
lightElement,
name,
descriptor.searchInCommentsAndStrings,
descriptor.searchInNonCode,
FqName(newFqName).quoteIfNeeded().asString(),
results
)
}
MoveClassHandler.EP_NAME.extensions.forEach { handler ->
if (handler !is MoveKotlinClassHandler) handler.preprocessUsages(results)
}
results
.filter { it is NonCodeUsageInfo && it.file is KtFile }
.forEach {
val newText = NonCodeUsageInfo::class.java.getField("newText")
// A 'newText' is marked as final initially, but here we need to change it to prevent
// light-class names in kotlin files.
val oldAccessibility = newText.isAccessible
newText.isAccessible = true
newText.set(it, newFqNameForKt)
// Restore initial accessibility of 'newText' field.
newText.isAccessible = oldAccessibility
}
results
}
}
val usages = ArrayList<UsageInfo>()
val conflictChecker = MoveConflictChecker(
project,
elementsToMove,
descriptor.moveTarget,
elementsToMove.first(),
allElementsToMove = descriptor.allElementsToMove
)
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
val internalUsages = LinkedHashSet<UsageInfo>()
val externalUsages = LinkedHashSet<UsageInfo>()
if (moveEntireFile) {
val changeInfo = ContainerChangeInfo(
ContainerInfo.Package(sourceFile.packageFqName),
descriptor.moveTarget.targetContainerFqName?.let { ContainerInfo.Package(it) } ?: ContainerInfo.UnknownPackage
)
internalUsages += sourceFile.getInternalReferencesToUpdateOnPackageNameChange(changeInfo)
}
else {
kotlinToLightElements.keys.forEach {
val packageNameInfo = descriptor.delegate.getContainerChangeInfo(it, descriptor.moveTarget)
internalUsages += it.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo)
}
}
internalUsages += descriptor.delegate.findInternalUsages(descriptor)
collectUsages(kotlinToLightElements, externalUsages)
if (descriptor.analyzeConflicts) {
conflictChecker.checkAllConflicts(externalUsages, internalUsages, conflicts)
descriptor.delegate.collectConflicts(descriptor, internalUsages, conflicts)
}
usages += internalUsages
usages += externalUsages
}
return UsageViewUtil.removeDuplicatedUsages(usages.toTypedArray())
}
override fun preprocessUsages(refUsages: Ref<Array<UsageInfo>>): Boolean {
return showConflicts(conflicts, refUsages.get())
}
override fun performRefactoring(usages: Array<out UsageInfo>) = doPerformRefactoring(usages.toList())
internal fun doPerformRefactoring(usages: List<UsageInfo>) {
fun moveDeclaration(declaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): KtNamedDeclaration {
val targetContainer = moveTarget.getOrCreateTargetPsi(declaration)
?: throw AssertionError("Couldn't create Kotlin file for: ${declaration::class.java}: ${declaration.text}")
descriptor.delegate.preprocessDeclaration(descriptor, declaration)
if (moveEntireFile) return declaration
return mover(declaration, targetContainer).apply {
addToBeShortenedDescendantsToWaitingSet()
}
}
val (oldInternalUsages, externalUsages) = usages.partition { it is KotlinMoveUsage && it.isInternal }
val newInternalUsages = ArrayList<UsageInfo>()
markInternalUsages(oldInternalUsages)
val usagesToProcess = ArrayList(externalUsages)
try {
descriptor.delegate.preprocessUsages(descriptor, usages)
val oldToNewElementsMapping = THashMap<PsiElement, PsiElement>(ElementHashingStrategy)
val newDeclarations = ArrayList<KtNamedDeclaration>()
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
for ((oldDeclaration, oldLightElements) in kotlinToLightElements) {
val elementListener = transaction?.getElementListener(oldDeclaration)
val newDeclaration = moveDeclaration(oldDeclaration, descriptor.moveTarget)
newDeclarations += newDeclaration
oldToNewElementsMapping[oldDeclaration] = newDeclaration
oldToNewElementsMapping[sourceFile] = newDeclaration.containingKtFile
elementListener?.elementMoved(newDeclaration)
for ((oldElement, newElement) in oldLightElements.asSequence().zip(newDeclaration.toLightElements().asSequence())) {
oldToNewElementsMapping[oldElement] = newElement
}
if (descriptor.openInEditor) {
EditorHelper.openInEditor(newDeclaration)
}
}
if (descriptor.deleteSourceFiles) {
sourceFile.delete()
}
}
val internalUsageScopes: List<KtElement> = if (moveEntireFile) {
newDeclarations.asSequence().map { it.containingKtFile }.distinct().toList()
} else {
newDeclarations
}
internalUsageScopes.forEach { newInternalUsages += restoreInternalUsages(it, oldToNewElementsMapping) }
usagesToProcess += newInternalUsages
nonCodeUsages = postProcessMoveUsages(usagesToProcess, oldToNewElementsMapping).toTypedArray()
}
catch (e: IncorrectOperationException) {
nonCodeUsages = null
RefactoringUIUtil.processIncorrectOperation(myProject, e)
}
finally {
cleanUpInternalUsages(newInternalUsages + oldInternalUsages)
}
}
override fun performPsiSpoilingRefactoring() {
nonCodeUsages?.let { nonCodeUsages -> RenameUtil.renameNonCodeUsages(myProject, nonCodeUsages) }
descriptor.moveCallback?.refactoringCompleted()
}
fun execute(usages: List<UsageInfo>) {
execute(usages.toTypedArray())
}
override fun doRun() {
try {
super.doRun()
} finally {
broadcastRefactoringExit(myProject, refactoringId)
}
}
override fun getCommandName(): String = REFACTORING_NAME
}

View File

@@ -100,7 +100,7 @@ class KotlinTargetElementEvaluator : TargetElementEvaluatorEx, TargetElementUtil
val calleeExpression = refExpression?.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
if (calleeExpression != null) {
(ref.resolve() as? KtConstructor<*>)?.let {
return if (flags and JavaTargetElementEvaluator.NEW_AS_CONSTRUCTOR != 0) it else it.containingClassOrObject
return if (flags and JavaTargetElementEvaluator().additionalReferenceSearchFlags != 0) it else it.containingClassOrObject
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.codeInsight.JavaTargetElementEvaluator
import com.intellij.codeInsight.TargetElementEvaluatorEx
import com.intellij.codeInsight.TargetElementUtil
import com.intellij.codeInsight.TargetElementUtilExtender
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiReference
import com.intellij.util.BitUtil
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.idea.intentions.isAutoCreatedItUsage
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.source.getPsi
class KotlinTargetElementEvaluator : TargetElementEvaluatorEx, TargetElementUtilExtender {
companion object {
const val DO_NOT_UNWRAP_LABELED_EXPRESSION = 0x100
const val BYPASS_IMPORT_ALIAS = 0x200
// Place caret after the open curly brace in lambda for generated 'it'
fun findLambdaOpenLBraceForGeneratedIt(ref: PsiReference): PsiElement? {
val element: PsiElement = ref.element
if (element.text != "it") return null
if (element !is KtNameReferenceExpression || !isAutoCreatedItUsage(element)) return null
val itDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() ?: return null
val descriptorWithSource = itDescriptor.containingDeclaration as? DeclarationDescriptorWithSource ?: return null
val lambdaExpression = descriptorWithSource.source.getPsi()?.parent as? KtLambdaExpression ?: return null
return lambdaExpression.leftCurlyBrace.treeNext?.psi
}
// Navigate to receiver element for this in extension declaration
fun findReceiverForThisInExtensionFunction(ref: PsiReference): PsiElement? {
val element: PsiElement = ref.element
if (element.text != "this") return null
if (element !is KtNameReferenceExpression) return null
val callableDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() as? CallableDescriptor ?: return null
if (!callableDescriptor.isExtension) return null
val callableDeclaration = callableDescriptor.source.getPsi() as? KtCallableDeclaration ?: return null
return callableDeclaration.receiverTypeReference
}
}
override fun getAdditionalDefinitionSearchFlags() = 0
override fun getAdditionalReferenceSearchFlags() = DO_NOT_UNWRAP_LABELED_EXPRESSION or BYPASS_IMPORT_ALIAS
override fun getAllAdditionalFlags() = additionalDefinitionSearchFlags + additionalReferenceSearchFlags
override fun includeSelfInGotoImplementation(element: PsiElement): Boolean = !(element is KtClass && element.isAbstract())
override fun getElementByReference(ref: PsiReference, flags: Int): PsiElement? {
if (ref is KtSimpleNameReference && ref.expression is KtLabelReferenceExpression) {
val refTarget = ref.resolve() as? KtExpression ?: return null
if (!BitUtil.isSet(flags, DO_NOT_UNWRAP_LABELED_EXPRESSION)) {
return refTarget.getLabeledParent(ref.expression.getReferencedName()) ?: refTarget
}
return refTarget
}
if (!BitUtil.isSet(flags, BYPASS_IMPORT_ALIAS)) {
(ref.element as? KtSimpleNameExpression)?.mainReference?.getImportAlias()?.let { return it }
}
// prefer destructing declaration entry to its target if element name is accepted
if (ref is KtDestructuringDeclarationReference && BitUtil.isSet(flags, TargetElementUtil.ELEMENT_NAME_ACCEPTED)) {
return ref.element
}
val refExpression = ref.element as? KtSimpleNameExpression
val calleeExpression = refExpression?.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
if (calleeExpression != null) {
(ref.resolve() as? KtConstructor<*>)?.let {
return if (flags and JavaTargetElementEvaluator.NEW_AS_CONSTRUCTOR != 0) it else it.containingClassOrObject
}
}
if (BitUtil.isSet(flags, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED)) {
return findLambdaOpenLBraceForGeneratedIt(ref)
?: findReceiverForThisInExtensionFunction(ref)
}
return null
}
override fun isIdentifierPart(file: PsiFile, text: CharSequence?, offset: Int): Boolean {
val elementAtCaret = file.findElementAt(offset)
if (elementAtCaret?.node?.elementType == KtTokens.IDENTIFIER) return true
// '(' is considered identifier part if it belongs to primary constructor without 'constructor' keyword
return elementAtCaret?.getNonStrictParentOfType<KtPrimaryConstructor>()?.textOffset == offset
}
}

View File

@@ -75,9 +75,9 @@ class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer
return listOf(KotlinSliceUsage(usage.element, usage.parent, 0, false))
}
override fun getExpressionAtCaret(atCaret: PsiElement?, dataFlowToThis: Boolean): KtExpression? {
override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtExpression? {
val element =
atCaret?.parentsWithSelf
atCaret.parentsWithSelf
?.firstOrNull {
it is KtProperty ||
it is KtParameter ||

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.slicer
import com.intellij.codeInspection.dataFlow.Nullness
import com.intellij.ide.util.treeView.AbstractTreeStructure
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.psi.PsiElement
import com.intellij.slicer.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isPlainWithEscapes
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.isNullabilityFlexible
class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer {
companion object {
val LEAF_ELEMENT_EQUALITY = object : SliceLeafEquality() {
override fun substituteElement(element: PsiElement) = (element as? KtReference)?.resolve() ?: element
}
}
class KotlinGroupByNullnessAction(treeBuilder: SliceTreeBuilder) : GroupByNullnessActionBase(treeBuilder) {
override fun isAvailable() = true
}
val leafAnalyzer by lazy { SliceLeafAnalyzer(LEAF_ELEMENT_EQUALITY, this) }
val nullnessAnalyzer: SliceNullnessAnalyzerBase by lazy {
object : SliceNullnessAnalyzerBase(LEAF_ELEMENT_EQUALITY, this) {
override fun checkNullness(element: PsiElement?): Nullness {
val types = when (element) {
is KtCallableDeclaration -> listOfNotNull((element.resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType)
is KtDeclaration -> emptyList()
is KtExpression -> listOfNotNull(element.analyze(BodyResolveMode.PARTIAL).getType(element))
else -> emptyList()
}
return when {
types.isEmpty() -> return Nullness.UNKNOWN
types.all { KotlinBuiltIns.isNullableNothing(it) } -> Nullness.NULLABLE
types.any { it.isError || TypeUtils.isNullableType(it) || it.isNullabilityFlexible() } -> Nullness.UNKNOWN
else -> Nullness.NOT_NULL
}
}
}
}
override fun createRootUsage(element: PsiElement, params: SliceAnalysisParams) = KotlinSliceUsage(element, params)
override fun transform(usage: SliceUsage): Collection<SliceUsage>? {
if (usage is KotlinSliceUsage) return null
return listOf(KotlinSliceUsage(usage.element, usage.parent, 0, false))
}
override fun getExpressionAtCaret(atCaret: PsiElement?, dataFlowToThis: Boolean): KtExpression? {
val element =
atCaret?.parentsWithSelf
?.firstOrNull {
it is KtProperty ||
it is KtParameter ||
it is KtDeclarationWithBody ||
(it is KtClass && !it.hasExplicitPrimaryConstructor()) ||
(it is KtExpression && it !is KtDeclaration)
}
?.let { KtPsiUtil.safeDeparenthesize(it as KtExpression) } ?: return null
if (dataFlowToThis) {
if (element is KtConstantExpression) return null
if (element is KtStringTemplateExpression && element.isPlainWithEscapes()) return null
if (element is KtClassLiteralExpression) return null
if (element is KtCallableReferenceExpression) return null
}
return element
}
override fun getElementForDescription(element: PsiElement): PsiElement {
return (element as? KtSimpleNameExpression)?.mainReference?.resolve() ?: element
}
override fun getRenderer() = KotlinSliceUsageCellRenderer
override fun startAnalyzeLeafValues(structure: AbstractTreeStructure, finalRunnable: Runnable) {
leafAnalyzer.startAnalyzeValues(structure, finalRunnable)
}
override fun startAnalyzeNullness(structure: AbstractTreeStructure, finalRunnable: Runnable) {
nullnessAnalyzer.startAnalyzeNullness(structure, finalRunnable)
}
override fun registerExtraPanelActions(group: DefaultActionGroup, builder: SliceTreeBuilder) {
if (builder.dataFlowToThis) {
group.add(GroupByLeavesAction(builder))
group.add(KotlinGroupByNullnessAction(builder))
}
}
}

View File

@@ -1,14 +1,21 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2018 JetBrains s.r.o. 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.idea.statistics
import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger
import com.intellij.internal.statistic.eventLog.FeatureUsageData
import org.jetbrains.kotlin.idea.KotlinPluginUtil
open class KotlinStatisticsTrigger {
companion object {
public fun trigger(trigger: KotlinEventTrigger, event: String) {
// Not whitelisted for 183
private val context = FeatureUsageData().addData("plugin_version", KotlinPluginUtil.getPluginVersion())
fun trigger(trigger: KotlinEventTrigger, event: String) {
FUCounterUsageLogger.getInstance().logEvent(trigger.GROUP_ID, event, context)
}
}
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.idea.statistics
open class KotlinStatisticsTrigger {
companion object {
public fun trigger(trigger: KotlinEventTrigger, event: String) {
// Not whitelisted for 183
}
}
}

View File

@@ -5,8 +5,11 @@
package org.jetbrains.kotlin.idea.highlighter
import com.intellij.testFramework.ExpectedHighlightingData
// Idea 191 has an additional check for duplicate highlighting
// BUNCH: 183
fun expectedDuplicatedHighlighting(runnable: Runnable) {
runnable.run()
@Suppress("DEPRECATION")
ExpectedHighlightingData.expectedDuplicatedHighlighting(runnable)
}

View File

@@ -0,0 +1,12 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.idea.highlighter
// Idea 191 has an additional check for duplicate highlighting
// BUNCH: 183
fun expectedDuplicatedHighlighting(runnable: Runnable) {
runnable.run()
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.idea.quickfix
import com.intellij.lang.jvm.actions.*
import com.intellij.lang.jvm.types.JvmType
import com.intellij.psi.PsiType
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.uast.UMethod
class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTestCase() {
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
override fun setUp() {
super.setUp()
myFixture.configureByText("Anno.kt", "annotation class Anno(val i: Int)")
}
fun testSetParameters() {
myFixture.configureByText(
"foo.kt",
"""
class Foo {
fun ba<caret>r() {}
}
""".trimIndent()
)
myFixture.launchAction(
createChangeParametersActions(
myFixture.atCaret<UMethod>().javaPsi,
setMethodParametersRequest(
linkedMapOf<String, JvmType>(
"i" to PsiType.INT,
"file" to PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope)
).entries
)
).findWithText("Change method parameters to '(i: Int, file: File)'")
)
myFixture.checkResult(
"""
import java.io.File
class Foo {
fun bar(i: Int, file: File) {}
}
""".trimIndent(),
true
)
}
fun testAddParameterToTheEnd() {
myFixture.configureByText(
"foo.kt",
"""
class Foo {
fun ba<caret>r(@Anno(3) a: Int) {}
}
""".trimIndent()
)
runParametersTransformation("Change method parameters to '(a: Int, file: File)'") { currentParameters ->
currentParameters + expectedParameter(
PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file",
listOf(annotationRequest("Anno", intAttribute("i", 8)))
)
}
myFixture.checkResult(
"""
import java.io.File
class Foo {
fun bar(@Anno(3) a: Int, @Anno(i = 8) file: File) {}
}
""".trimIndent(), true
)
}
fun testAddParameterToTheBeginning() {
myFixture.configureByText(
"foo.kt",
"""
class Foo {
fun ba<caret>r(@Anno(3) a: Int) {}
}
""".trimIndent()
)
runParametersTransformation("Change method parameters to '(file: File, a: Int)'") { currentParameters ->
listOf(
expectedParameter(
PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file",
listOf(annotationRequest("Anno", intAttribute("i", 8)))
)
) + currentParameters
}
myFixture.checkResult(
"""
import java.io.File
class Foo {
fun bar(@Anno(i = 8) file: File, @Anno(3) a: Int) {}
}
""".trimIndent(), true
)
}
fun testReplaceInTheMiddle() {
myFixture.configureByText(
"foo.kt",
"""
class Foo {
fun ba<caret>r(@Anno(1) a: Int, @Anno(2) b: Int, @Anno(3) c: Int) {}
}
""".trimIndent()
)
runParametersTransformation("Change method parameters to '(a: Int, file: File, c: Int)'") { currentParameters ->
ArrayList<ExpectedParameter>(currentParameters).apply {
this[1] = expectedParameter(
PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file",
listOf(annotationRequest("Anno", intAttribute("i", 8)))
)
}
}
myFixture.checkResult(
"""
import java.io.File
class Foo {
fun bar(@Anno(1) a: Int, @Anno(i = 8) file: File, @Anno(3) c: Int) {}
}
""".trimIndent(), true
)
}
private fun runParametersTransformation(
actionName: String,
transformation: (List<ChangeParametersRequest.ExistingParameterWrapper>) -> List<ExpectedParameter>
) {
val psiMethod = myFixture.atCaret<UMethod>().javaPsi
val currentParameters = psiMethod.parameters.map { ChangeParametersRequest.ExistingParameterWrapper(it) }
myFixture.launchAction(
createChangeParametersActions(
psiMethod,
SimpleChangeParametersRequest(
transformation(currentParameters)
)
).findWithText(actionName)
)
}
}
private class SimpleChangeParametersRequest(private val list: List<ExpectedParameter>) : ChangeParametersRequest {
override fun getExpectedParameters(): List<ExpectedParameter> = list
override fun isValid(): Boolean = true
}

View File

@@ -11,11 +11,9 @@ import com.intellij.lang.jvm.JvmElement
import com.intellij.lang.jvm.JvmModifier
import com.intellij.lang.jvm.actions.*
import com.intellij.lang.jvm.types.JvmSubstitutor
import com.intellij.lang.jvm.types.JvmType
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pair.pair
import com.intellij.psi.*
import com.intellij.psi.codeStyle.SuggestedNameInfo
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
import junit.framework.TestCase
@@ -23,9 +21,6 @@ import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.idea.search.allScope
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.UParameter
import org.jetbrains.uast.UastContext
import org.jetbrains.uast.toUElement
import org.junit.Assert
@@ -57,8 +52,6 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
}
private class NameInfo(vararg names: String) : SuggestedNameInfo(names)
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
fun testMakeNotFinal() {
@@ -279,7 +272,7 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
import pkg.myannotation.JavaAnnotation
class Foo {
@field:JavaAnnotation()
@field:JavaAnnotation
val bar: String = null
}
""".trimIndent(), true
@@ -331,7 +324,7 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
import pkg.myannotation.JavaAnnotation
class Foo {
@JavaAnnotation()
@JavaAnnotation
val bar: String = null
}
""".trimIndent(), true
@@ -632,57 +625,12 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
""".trim().trimMargin(), true)
}
fun testSetParameters() {
myFixture.configureByText(
"foo.kt", """
|class Foo {
| fun ba<caret>r() {}
|}
""".trim().trimMargin()
)
myFixture.launchAction(
com.intellij.lang.jvm.actions.createChangeParametersActions(
myFixture.atCaret<UMethod>().javaPsi,
setMethodParametersRequest(
linkedMapOf<String, JvmType>(
"i" to PsiType.INT,
"file" to PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope)
).entries
)
).findWithText("Change method parameters to '(i: Int, file: File)'")
)
myFixture.checkResult(
"""
import java.io.File
class Foo {
fun bar(i: Int, file: File) {}
}
""".trimIndent(), true
)
}
private fun makeParams(vararg psyTypes: PsiType): List<UParameter> {
val uastContext = UastContext(myFixture.project)
val factory = JavaPsiFacade.getElementFactory(myFixture.project)
val parameters = psyTypes.mapIndexed { index, psiType -> factory.createParameter("param$index", psiType) }
return parameters.map { uastContext.convertElement(it, null, UParameter::class.java) as UParameter }
}
private fun expectedTypes(vararg psiTypes: PsiType) = psiTypes.map { expectedType(it) }
private fun expectedParams(vararg psyTypes: PsiType) =
psyTypes.mapIndexed { index, psiType -> expectedParameter(expectedTypes(psiType), "param$index") }
private inline fun <reified T : JvmElement> CodeInsightTestFixture.atCaret() = elementAtCaret.toUElement() as T
@Suppress("CAST_NEVER_SUCCEEDS")
private fun List<IntentionAction>.findWithText(text: String): IntentionAction =
this.firstOrNull { it.text == text } ?:
Assert.fail("intention with text '$text' was not found, only ${this.joinToString { "\"${it.text}\"" }} available") as Nothing
class FieldRequest(
private val project: Project,
val modifiers: List<JvmModifier>,
@@ -703,7 +651,14 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
override fun isValid(): Boolean = true
}
}
internal inline fun <reified T : JvmElement> CodeInsightTestFixture.atCaret() = elementAtCaret.toUElement() as T
@Suppress("CAST_NEVER_SUCCEEDS")
internal fun List<IntentionAction>.findWithText(text: String): IntentionAction =
this.firstOrNull { it.text == text } ?:
Assert.fail("intention with text '$text' was not found, only ${this.joinToString { "\"${it.text}\"" }} available") as Nothing

View File

@@ -8,7 +8,7 @@ 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.android.tools.idea.res.ResourceRepositoryManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.android.facet.AndroidFacet
@@ -36,7 +36,7 @@ class AndroidModuleInfoProviderImpl(override val module: Module) : AndroidModule
}
override fun getApplicationResourceDirectories(createIfNecessary: Boolean): Collection<VirtualFile> {
return AppResourceRepository.getOrCreateInstance(module)?.resourceDirs ?: emptyList()
return ResourceRepositoryManager.getOrCreateInstance(module)?.getAppResources(createIfNecessary)?.resourceDirs ?: emptyList()
}
override fun getAllSourceProviders(): List<AndroidModuleInfoProvider.SourceProviderMirror> {

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
}
}

View File

@@ -16,7 +16,6 @@
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
@@ -80,8 +79,6 @@ class KaptProjectResolverExtension : AbstractProjectResolverExtension() {
if (kaptModel.isEnabled) {
for (sourceSet in kaptModel.sourceSets) {
populateAndroidModuleModelIfNeeded(ideModule, sourceSet)
val sourceSetDataNode = ideModule.findGradleSourceSet(sourceSet.sourceSetName) ?: continue
fun addSourceSet(path: String, type: ExternalSystemSourceType) {
@@ -106,42 +103,6 @@ class KaptProjectResolverExtension : AbstractProjectResolverExtension() {
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) {

View File

@@ -0,0 +1,200 @@
/*
* 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) ?: return
if (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 kotlinCompileTaskClasses) 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 ?: ""
}
}

View File

@@ -79,10 +79,14 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : Kotl
parent = parent.parent
}
while (parent is KtStringTemplateEntryWithExpression ||
parent is KtStringTemplateExpression && parent.entries.size == 1) {
parent = parent.parent
}
if (KotlinConverter.forceUInjectionHost) {
if (parent is KtBlockStringTemplateEntry) {
parent = parent.parent
}
} else
while (parent is KtStringTemplateEntryWithExpression || parent is KtStringTemplateExpression && parent.entries.size == 1) {
parent = parent.parent
}
if (parent is KtWhenConditionWithExpression) {
parent = parent.parent
@@ -110,7 +114,7 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : Kotl
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}]")
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

View File

@@ -0,0 +1,229 @@
/*
* 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.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration
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.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? {
val psi = psi
var parent = psi?.parent ?: psi?.containingFile
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}]")
}
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 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()
}
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 sourcePsi
get() = psi
override val annotations: List<UAnnotation>
get() {
val annotatedExpression = psi?.parent as? KtAnnotatedExpression ?: return emptyList()
return annotatedExpression.annotationEntries.map { KotlinUAnnotation(it, this) }
}
}

View File

@@ -19,13 +19,16 @@ 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.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.annotations.TestOnly
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
@@ -39,6 +42,7 @@ 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.expressions.UInjectionHost
import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclaration
import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclarationOrElement
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
@@ -75,15 +79,15 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
if (!element.isJvmElement) return null
return convertDeclarationOrElement(element, parent, requiredType)
return convertDeclarationOrElement(element, parent, elementTypes(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)
if (element is PsiFile) return convertDeclaration(element, null, elementTypes(requiredType))
if (element is KtLightClassForFacade) return convertDeclaration(element, null, elementTypes(requiredType))
return convertDeclarationOrElement(element, null, requiredType)
return convertDeclarationOrElement(element, null, elementTypes(requiredType))
}
override fun getMethodCallExpression(
@@ -136,16 +140,42 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
else -> false
}
}
@Suppress("UNCHECKED_CAST")
fun <T : UElement> convertElement(element: PsiElement, parent: UElement?, expectedTypes: Array<out Class<out T>>): T? {
val nonEmptyExpectedTypes = expectedTypes.nonEmptyOr(DEFAULT_TYPES_LIST)
return (convertDeclaration(element, parent, nonEmptyExpectedTypes)
?: KotlinConverter.convertPsiElement(element, parent, nonEmptyExpectedTypes)) as? T
}
override fun <T : UElement> convertElementWithParent(element: PsiElement, requiredTypes: Array<out Class<out T>>): T? {
return convertElement(element, null, requiredTypes)
}
@Suppress("UNCHECKED_CAST")
override fun <T : UElement> convertToAlternatives(element: PsiElement, requiredTypes: Array<out Class<out T>>): Sequence<T> = when {
element is KtFile -> KotlinConverter.convertKtFile(element, null, requiredTypes) as Sequence<T>
(element is KtProperty && !element.isLocal) -> KotlinConverter.convertNonLocalProperty(element, null, requiredTypes) as Sequence<T>
element is KtParameter -> KotlinConverter.convertParameter(element, null, requiredTypes) as Sequence<T>
element is KtClassOrObject -> KotlinConverter.convertClassOrObject(element, null, requiredTypes) as Sequence<T>
else -> sequenceOf(convertElementWithParent(element, requiredTypes.nonEmptyOr(DEFAULT_TYPES_LIST)) as? T).filterNotNull()
}
}
internal inline fun <reified ActualT : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? {
internal inline fun <reified ActualT : UElement> Class<*>?.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 inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.el(f: () -> UElement?): UElement? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
internal inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.expr(f: () -> UExpression?): UExpression? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
internal fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
internal object KotlinConverter {
@@ -166,12 +196,13 @@ internal object KotlinConverter {
internal fun convertPsiElement(element: PsiElement?,
givenParent: UElement?,
requiredType: Class<out UElement>?): UElement? {
expectedTypes: Array<out Class<out UElement>>
): UElement? {
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? {
return { ctor(element as P, givenParent) }
}
return with (requiredType) { when (element) {
return with (expectedTypes) { when (element) {
is KtParameterList -> el<UDeclarationsExpression> {
val declarationsExpression = KotlinUDeclarationsExpression(givenParent)
declarationsExpression.apply {
@@ -184,11 +215,7 @@ internal object KotlinConverter {
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
is KtVariableDeclaration ->
if (element is KtProperty && !element.isLocal) {
el<UField> {
LightClassUtil.getLightClassBackingField(element)?.let {
KotlinUField(it, element, givenParent)
}
}
convertNonLocalProperty(element, givenParent, this).firstOrNull()
}
else {
el<UVariable> {
@@ -196,19 +223,19 @@ internal object KotlinConverter {
}
}
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, requiredType)
is KtLambdaArgument -> element.getLambdaExpression()?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, expectedTypes)
is KtLambdaArgument -> element.getLambdaExpression()?.let { KotlinConverter.convertExpression(it, givenParent, expectedTypes) }
is KtLightElementBase -> {
val expression = element.kotlinOrigin
when (expression) {
is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, requiredType)
is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, expectedTypes)
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 KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, expectedTypes) } ?: expr<UExpression> { UastEmptyExpression }
is KtWhenEntry -> el<USwitchClauseExpressionWithBody>(build(::KotlinUSwitchEntry))
is KtWhenCondition -> convertWhenCondition(element, givenParent, requiredType)
is KtWhenCondition -> convertWhenCondition(element, givenParent, expectedTypes)
is KtTypeReference -> el<UTypeReferenceExpression> { LazyKotlinUTypeReferenceExpression(element, givenParent) }
is KtConstructorDelegationCall ->
el<UCallExpression> { KotlinUFunctionCallExpression(element, givenParent) }
@@ -246,7 +273,8 @@ internal object KotlinConverter {
internal fun convertEntry(entry: KtStringTemplateEntry,
givenParent: UElement?,
requiredType: Class<out UElement>? = null): UExpression? {
requiredType: Array<out Class<out UElement>>
): UExpression? {
return with(requiredType) {
if (entry is KtStringTemplateEntryWithExpression) {
expr<UExpression> {
@@ -264,9 +292,16 @@ internal object KotlinConverter {
}
}
var forceUInjectionHost = Registry.`is`("kotlin.uast.force.uinjectionhost", false)
@TestOnly
set(value) {
field = value
}
internal fun convertExpression(expression: KtExpression,
givenParent: UElement?,
requiredType: Class<out UElement>? = null): UExpression? {
requiredType: Array<out Class<out UElement>>
): UExpression? {
fun <P : PsiElement> build(ctor: (P, UElement?) -> UExpression): () -> UExpression? {
return { ctor(expression as P, givenParent) }
}
@@ -276,13 +311,16 @@ internal object KotlinConverter {
is KtStringTemplateExpression -> {
when {
forceUInjectionHost || requiredType.contains(UInjectionHost::class.java) ->
expr<UInjectionHost> { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
expression.entries.isEmpty() -> {
expr<ULiteralExpression> { KotlinStringULiteralExpression(expression, givenParent, "") }
}
expression.entries.size == 1 -> convertEntry(expression.entries[0], givenParent, requiredType)
else -> {
expr<UExpression> { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
}
else ->
expr<KotlinStringTemplateUPolyadicExpression> { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
}
}
is KtDestructuringDeclaration -> expr<UDeclarationsExpression> {
@@ -355,7 +393,7 @@ internal object KotlinConverter {
internal fun convertWhenCondition(condition: KtWhenCondition,
givenParent: UElement?,
requiredType: Class<out UElement>? = null
requiredType: Array<out Class<out UElement>>
): UExpression? {
return with(requiredType) {
when (condition) {
@@ -405,7 +443,7 @@ internal object KotlinConverter {
internal fun convertDeclaration(
element: PsiElement,
givenParent: UElement?,
requiredType: Class<out UElement>?
expectedTypes: Array<out Class<out UElement>>
): UElement? {
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? = { ctor(element as P, givenParent) }
@@ -416,7 +454,7 @@ internal object KotlinConverter {
{ ctor(element as P, ktElement, givenParent) }
val original = element.originalElement
return with(requiredType) {
return with(expectedTypes) {
when (original) {
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
is KtLightClass -> when (original.kotlinOrigin) {
@@ -434,11 +472,7 @@ internal object KotlinConverter {
is KtEnumEntry -> el<UEnumConstant> {
convertEnumEntry(original, givenParent)
}
is KtClassOrObject -> el<UClass> {
original.toLightClass()?.let { lightClass ->
KotlinUClass.create(lightClass, givenParent)
}
}
is KtClassOrObject -> convertClassOrObject(original, givenParent, this).firstOrNull()
is KtFunction ->
if (original.isLocal) {
el<ULambdaExpression> {
@@ -447,49 +481,41 @@ internal object KotlinConverter {
KotlinULambdaExpression(parent, givenParent) // your parent is the ULambdaExpression
} else if (original.name.isNullOrEmpty()) {
createLocalFunctionLambdaExpression(original, givenParent)
}
else {
} else {
val uDeclarationsExpression = createLocalFunctionDeclaration(original, givenParent)
val localFunctionVar = uDeclarationsExpression.declarations.single() as KotlinLocalFunctionUVariable
localFunctionVar.uastInitializer
}
}
}
else {
} else {
el<UMethod> {
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
convertDeclaration(lightMethod, givenParent, requiredType)
convertDeclaration(lightMethod, givenParent, expectedTypes)
}
}
is KtPropertyAccessor -> el<UMethod> {
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
convertDeclaration(lightMethod, givenParent, requiredType)
convertDeclaration(lightMethod, givenParent, expectedTypes)
}
is KtProperty ->
if (original.isLocal) {
KotlinConverter.convertPsiElement(element, givenParent, requiredType)
}
else {
convertNonLocalProperty(original, givenParent, requiredType)
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
} else {
convertNonLocalProperty(original, givenParent, expectedTypes).firstOrNull()
}
is KtParameter -> el<UParameter> {
val ownerFunction = original.ownerFunction as? KtFunction ?: return null
val lightMethod = LightClassUtil.getLightClassMethod(ownerFunction) ?: return null
val lightParameter = lightMethod.parameterList.parameters.find { it.name == original.name } ?: return null
KotlinUParameter(lightParameter, original, givenParent)
}
is KtParameter -> convertParameter(original, givenParent, this).firstOrNull()
is KtFile -> el<UFile> { KotlinUFile(original) }
is KtFile -> convertKtFile(original, givenParent, this).firstOrNull()
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement) }
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
is KtCallExpression ->
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
if (expectedTypes.isAssignableFrom(KotlinUNestedAnnotation::class.java) && !expectedTypes.isAssignableFrom(UCallExpression::class.java)) {
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
} else null
is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, requiredType)
is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, expectedTypes)
is KtDelegatedSuperTypeEntry -> el<KotlinSupertypeDelegationUExpression> {
KotlinSupertypeDelegationUExpression(original, givenParent)
}
@@ -499,17 +525,21 @@ internal object KotlinConverter {
}
fun convertDeclarationOrElement(element: PsiElement, givenParent: UElement?, requiredType: Class<out UElement>?): UElement? {
fun convertDeclarationOrElement(
element: PsiElement,
givenParent: UElement?,
expectedTypes: Array<out 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
return if (expectedTypes.isAssignableFrom(cachedUElement.javaClass)) cachedUElement else null
}
}
val uElement = convertDeclaration(element, givenParent, requiredType)
?: KotlinConverter.convertPsiElement(element, givenParent, requiredType)
val uElement = convertDeclaration(element, givenParent, expectedTypes)
?: KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
/*
if (uElement != null) {
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, WeakReference(uElement))
@@ -518,27 +548,71 @@ internal object KotlinConverter {
return uElement
}
private fun convertNonLocalProperty(
private fun convertToPropertyAlternatives(
methods: LightClassUtil.PropertyAccessorsPsiMethods?,
givenParent: UElement?
): Array<UElementAlternative<*>> = if (methods != null) arrayOf(
alternative { methods.backingField?.let { KotlinUField(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, givenParent) } },
alternative { methods.getter?.let { convertDeclaration(it, givenParent, arrayOf(UMethod::class.java)) as? UMethod } },
alternative { methods.setter?.let { convertDeclaration(it, givenParent, arrayOf(UMethod::class.java)) as? UMethod } }
) else emptyArray()
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) }
expectedTypes: Array<out Class<out UElement>>
): Sequence<UElement> =
expectedTypes.accommodate(*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(property), givenParent))
fun convertParameter(
element: KtParameter,
givenParent: UElement?,
expectedTypes: Array<out Class<out UElement>>
): Sequence<UElement> = expectedTypes.accommodate(
alternative uParam@{
val ownerFunction = element.ownerFunction as? KtFunction ?: return@uParam null
val lightMethod = LightClassUtil.getLightClassMethod(ownerFunction) ?: return@uParam null
val lightParameter = lightMethod.parameterList.parameters.find { it.name == element.name } ?: return@uParam null
KotlinUParameter(lightParameter, element, givenParent)
},
*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(element), givenParent)
)
fun convertClassOrObject(
element: KtClassOrObject,
givenParent: UElement?,
expectedTypes: Array<out Class<out UElement>>
): Sequence<UElement> {
val ktLightClass = element.toLightClass() ?: return emptySequence()
val uClass = KotlinUClass.create(ktLightClass, givenParent)
return expectedTypes.accommodate(
alternative { uClass },
alternative primaryConstructor@{
val primaryConstructor = element.primaryConstructor ?: return@primaryConstructor null
uClass.methods.asSequence()
.filter { it.sourcePsi == primaryConstructor }
.firstOrNull()
}
} ?: methods.getter?.let { getter ->
convertDeclaration(getter, givenParent, requiredType)
}
)
}
fun convertKtFile(
element: KtFile,
givenParent: UElement?,
requiredTypes: Array<out Class<out UElement>>
): Sequence<UElement> = requiredTypes.accommodate(
alternative { KotlinUFile(element) },
alternative { element.findFacadeClass()?.let { KotlinUClass.create(it, givenParent) } }
)
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
return expression?.let { convertExpression(it, parent, DEFAULT_EXPRESSION_TYPES_LIST) } ?: UastEmptyExpression
}
internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
return if (expression != null) convertExpression(expression, parent, null) else null
return if (expression != null) convertExpression(expression, parent, DEFAULT_EXPRESSION_TYPES_LIST) else null
}
internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression =
@@ -571,3 +645,22 @@ private fun convertVariablesDeclaration(
}
val kotlinUastPlugin get() = UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin()
private fun expressionTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST
private fun elementTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST
private fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) = takeIf { it.isNotEmpty() }
?: default
private fun <U : UElement> Array<out Class<out UElement>>.accommodate(vararg makers: UElementAlternative<out U>): Sequence<UElement> {
val makersSeq = makers.asSequence()
return this.asSequence()
.flatMap { requiredType -> makersSeq.filter { requiredType.isAssignableFrom(it.uType) } }
.distinct()
.mapNotNull { it.make.invoke() }
}
private inline fun <reified U : UElement> alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make)
private class UElementAlternative<U : UElement>(val uType: Class<U>, val make: () -> U?)

View File

@@ -0,0 +1,573 @@
/*
* 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.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.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.psi 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 { 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 { 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.psi, 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>(build(::KotlinUBlockExpression))
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
}
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 }
}
}
}
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? = { ctor(element as P, givenParent) }
fun <P : PsiElement, K : KtElement> buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? =
{ ctor(element as P, ktElement, givenParent) }
fun <P : PsiElement, K : KtElement> buildKtOpt(ktElement: K?, ctor: (P, K?, UElement?) -> UElement): () -> UElement? =
{ 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) ?: return null
convertDeclaration(lightMethod, givenParent, requiredType)
}
}
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 ownerFunction = original.ownerFunction as? KtFunction ?: return null
val lightMethod = LightClassUtil.getLightClassMethod(ownerFunction) ?: return null
val lightParameter = lightMethod.parameterList.parameters.find { it.name == original.name } ?: return null
KotlinUParameter(lightParameter, original, givenParent)
}
is KtFile -> el<UFile> { KotlinUFile(original) }
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)
}
}
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" }
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?.psi
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()

View File

@@ -107,7 +107,7 @@ open class KotlinUMethod(
KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block ->
val implicitReturn = KotlinUImplicitReturnExpression(block)
val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression
?: return@KotlinLazyUBlockExpression emptyList()
?: return@KotlinLazyUBlockExpression emptyList()
listOf(implicitReturn.apply { returnExpression = uBody })
})
@@ -123,6 +123,12 @@ open class KotlinUMethod(
override fun getOriginalElement(): PsiElement? = super<UAnnotationMethod>.getOriginalElement()
override val returnTypeReference: UTypeReferenceExpression? by lz {
(sourcePsi as? KtCallableDeclaration)?.typeReference?.let {
LazyKotlinUTypeReferenceExpression(it, this) { javaPsi.returnType ?: UastErrorType }
}
}
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
companion object {

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.uast.kotlin.declarations
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.isGetter
import org.jetbrains.kotlin.asJava.elements.isSetter
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.uast.*
import org.jetbrains.uast.java.internal.JavaUElementWithComments
import org.jetbrains.uast.kotlin.*
open class KotlinUMethod(
psi: KtLightMethod,
givenParent: UElement?
) : KotlinAbstractUElement(givenParent), UAnnotationMethod, UMethodTypeSpecific, UAnchorOwner, JavaUElementWithComments, PsiMethod by psi {
override val comments: List<UComment>
get() = super<KotlinAbstractUElement>.comments
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
override val javaPsi = psi
override val sourcePsi = psi.kotlinOrigin
override fun getSourceElement() = sourcePsi ?: this
override val uastDefaultValue by lz {
val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null
val defaultValue = annotationParameter.defaultValue ?: return@lz null
getLanguagePlugin().convertElement(defaultValue, this) as? UExpression
}
private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
override val annotations by lz {
psi.annotations
.mapNotNull { (it as? KtLightElement<*, *>)?.kotlinOrigin as? KtAnnotationEntry }
.map { KotlinUAnnotation(it, this) }
}
private val receiver by lz { (sourcePsi as? KtCallableDeclaration)?.receiverTypeReference }
override val uastParameters by lz {
val lightParams = psi.parameterList.parameters
val receiver = receiver ?: return@lz lightParams.map {
KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this)
}
val receiverLight = lightParams.firstOrNull() ?: return@lz emptyList<UParameter>()
val uParameters = SmartList<UParameter>(KotlinReceiverUParameter(receiverLight, receiver, this))
lightParams.drop(1).mapTo(uParameters) { KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) }
uParameters
}
override val uastAnchor 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.isGetter -> kotlinOrigin.getter?.bodyExpression
psi.isSetter -> kotlinOrigin.setter?.bodyExpression
else -> null
}
else -> null
} ?: return@lz null
when (bodyExpression) {
!is KtBlockExpression -> {
KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block ->
val implicitReturn = KotlinUImplicitReturnExpression(block)
val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression
?: return@KotlinLazyUBlockExpression emptyList()
listOf(implicitReturn.apply { returnExpression = uBody })
})
}
else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression
}
}
override val isOverride: Boolean
get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false
override fun getBody(): PsiCodeBlock? = super<UAnnotationMethod>.getBody()
override fun getOriginalElement(): PsiElement? = super<UAnnotationMethod>.getOriginalElement()
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
companion object {
fun create(psi: KtLightMethod, containingElement: UElement?) =
if (psi.kotlinOrigin is KtConstructor<*>) {
KotlinConstructorUMethod(
psi.kotlinOrigin?.containingClassOrObject,
psi, containingElement
)
}
else
KotlinUMethod(psi, containingElement)
}
}

View File

@@ -9,6 +9,7 @@ import org.jetbrains.uast.evaluation.UEvaluationState
import org.jetbrains.uast.kotlin.KotlinBinaryOperators
import org.jetbrains.uast.kotlin.KotlinPostfixOperators
import org.jetbrains.uast.values.*
import org.jetbrains.uast.evaluation.to
class KotlinEvaluatorExtension : AbstractEvaluatorExtension(KotlinLanguage.INSTANCE) {

View File

@@ -0,0 +1,56 @@
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
}
}

View File

@@ -67,7 +67,7 @@ private fun createElvisExpressions(
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 elseExpression: UExpression? by lz { KotlinConverter.convertExpression(right, this, DEFAULT_EXPRESSION_TYPES_LIST) }
override val isTernary: Boolean = false
override val annotations: List<UAnnotation> = emptyList()
override val ifIdentifier: UIdentifier = KotlinUIdentifier(null, this)

View File

@@ -0,0 +1,121 @@
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
val right = elvisExpression.right ?: return UastEmptyExpression
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)
}
}

View File

@@ -16,19 +16,33 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiLanguageInjectionHost
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
import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UInjectionHost
class KotlinStringTemplateUPolyadicExpression(
override val psi: KtStringTemplateExpression,
givenParent: UElement?
override val psi: KtStringTemplateExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent),
UPolyadicExpression,
KotlinUElementWithType,
KotlinEvaluatableUElement {
override val operands: List<UExpression> by lz { psi.entries.map { KotlinConverter.convertEntry(it, this)!! } }
UPolyadicExpression,
KotlinUElementWithType,
KotlinEvaluatableUElement,
UInjectionHost {
override val operands: List<UExpression> by lz {
psi.entries.map {
KotlinConverter.convertEntry(
it,
this,
DEFAULT_EXPRESSION_TYPES_LIST
)!!
}
}
override val operator = UastBinaryOperator.PLUS
override val psiLanguageInjectionHost: PsiLanguageInjectionHost get() = psi
override val isString: Boolean get() = true
override fun asRenderString(): String = if (operands.isEmpty()) "\"\"" else super<UPolyadicExpression>.asRenderString()
override fun asLogString(): String = if (operands.isEmpty()) "UPolyadicExpression (value = \"\")" else super.asLogString()
}

View File

@@ -0,0 +1,34 @@
/*
* 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 psi: KtStringTemplateExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent),
UPolyadicExpression,
KotlinUElementWithType,
KotlinEvaluatableUElement {
override val operands: List<UExpression> by lz { psi.entries.map { KotlinConverter.convertEntry(it, this)!! } }
override val operator = UastBinaryOperator.PLUS
}

View File

@@ -20,10 +20,7 @@ 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.*
import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
class KotlinUCallableReferenceExpression(
@@ -34,7 +31,7 @@ class KotlinUCallableReferenceExpression(
get() {
if (qualifierType != null) return null
val receiverExpression = psi.receiverExpression ?: return null
return KotlinConverter.convertExpression(receiverExpression, this)
return KotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST)
}
override val qualifierType by lz {

View File

@@ -0,0 +1,55 @@
/*
* 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 psi: KtCallableReferenceExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, UMultiResolvable, KotlinUElementWithType {
override val qualifierExpression: UExpression?
get() {
if (qualifierType != null) return null
val receiverExpression = psi.receiverExpression ?: return null
return KotlinConverter.convertExpression(receiverExpression, this)
}
override val qualifierType by lz {
val ktType = psi.analyze()[DOUBLE_COLON_LHS, psi.receiverExpression]?.type ?: return@lz null
ktType.toPsiType(this, psi, boxed = true)
}
override val callableName: String
get() = psi.callableReference.getReferencedName()
override val resolvedName: String?
get() = (resolve() as? PsiNamedElement)?.name
override fun resolve() = psi.callableReference.resolveCallToDeclaration(this)
override fun multiResolve(): Iterable<ResolveResult> = getResolveResultVariants(psi.callableReference)
}

View File

@@ -18,6 +18,7 @@ package org.jetbrains.uast.kotlin
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
import org.jetbrains.uast.DEFAULT_EXPRESSION_TYPES_LIST
import org.jetbrains.uast.UClassLiteralExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
@@ -35,6 +36,6 @@ class KotlinUClassLiteralExpression(
get() {
if (type != null) return null
val receiverExpression = psi.receiverExpression ?: return null
return KotlinConverter.convertExpression(receiverExpression, this)
return KotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST)
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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 psi: KtClassLiteralExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UClassLiteralExpression, KotlinUElementWithType {
override val type by lz {
val ktType = psi.analyze()[DOUBLE_COLON_LHS, psi.receiverExpression]?.type ?: return@lz null
ktType.toPsiType(this, psi, boxed = true)
}
override val expression: UExpression?
get() {
if (type != null) return null
val receiverExpression = psi.receiverExpression ?: return null
return KotlinConverter.convertExpression(receiverExpression, this)
}
}

View File

@@ -18,6 +18,7 @@ package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.UastQualifiedExpressionAccessType
@@ -36,4 +37,10 @@ class KotlinUQualifiedReferenceExpression(
override val resolvedName: String?
get() = (resolve() as? PsiNamedElement)?.name
override val referenceNameElement: UElement?
get() = when (val selector = selector) {
is UCallExpression -> selector.methodIdentifier
else -> super.referenceNameElement
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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 psi: KtDotQualifiedExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression, DelegatedMultiResolve,
KotlinUElementWithType, KotlinEvaluatableUElement {
override val receiver by lz { KotlinConverter.convertOrEmpty(psi.receiverExpression, this) }
override val selector by lz { KotlinConverter.convertOrEmpty(psi.selectorExpression, this) }
override val accessType = UastQualifiedExpressionAccessType.SIMPLE
override fun resolve() = psi.selectorExpression?.resolveCallToDeclaration(this)
override val resolvedName: String?
get() = (resolve() as? PsiNamedElement)?.name
}

View File

@@ -69,6 +69,8 @@ open class KotlinUSimpleReferenceExpression(
visitor.afterVisitSimpleNameReferenceExpression(this)
}
override val referenceNameElement: UElement? by lz { psi.getIdentifier()?.toUElement() }
private fun visitAccessorCalls(visitor: UastVisitor) {
// Visit Kotlin get-set synthetic Java property calls as function calls
val bindingContext = psi.analyze()

View File

@@ -0,0 +1,242 @@
/*
* 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.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
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.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
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 psi: KtSimpleNameExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
private val resolvedDeclaration by lz {
(psi.parents.dropWhile { it is KtTypeElement }.firstOrNull() as? KtTypeReference)
?.toPsiType(this, true)
?.let { return@lz PsiTypesUtil.getPsiClass(it) }
psi.resolveCallToDeclaration(this)
}
override val identifier get() = psi.getReferencedName()
override fun resolve() = resolvedDeclaration
override val resolvedName: String?
get() = (resolvedDeclaration as? PsiNamedElement)?.name
override fun accept(visitor: UastVisitor) {
visitor.visitSimpleNameReferenceExpression(this)
if (psi.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 = psi.analyze()
val access = psi.readWriteAccess()
val resolvedCall = psi.getResolvedCall(bindingContext)
val resultingDescriptor = resolvedCall?.resultingDescriptor as? SyntheticJavaPropertyDescriptor
if (resultingDescriptor != null) {
val setterValue = if (access.isWrite) {
findAssignment(psi, psi.parent)?.right ?: run {
visitor.afterVisitSimpleNameReferenceExpression(this)
return
}
} else {
null
}
if (resolvedCall != null) {
if (access.isRead) {
val getDescriptor = resultingDescriptor.getMethod
KotlinAccessorCallExpression(psi, this, resolvedCall, getDescriptor, null).accept(visitor)
}
if (access.isWrite && setterValue != null) {
val setDescriptor = resultingDescriptor.setMethod
if (setDescriptor != null) {
KotlinAccessorCallExpression(psi, 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 psi: 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? = null
override val sourcePsi: PsiElement? = psi
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, psi, boxed = true)
}
override val methodIdentifier: UIdentifier? by lazy { KotlinUIdentifier(psi.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, psi, true) }
}
override val returnType by lz {
(accessorDescriptor as? CallableDescriptor)?.returnType?.toPsiType(this, psi, boxed = false)
}
override val kind: UastCallKind
get() = UastCallKind.METHOD_CALL
override fun resolve(): PsiMethod? {
val source = accessorDescriptor.toSource()
return resolveSource(psi, accessorDescriptor, source)
}
}
enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) {
READ(true, false), WRITE(false, true), READ_WRITE(true, true)
}
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 psi: 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 = psi.getResolvedCall(psi.analyze())?.resultingDescriptor) {
is ConstructorDescriptor -> {
resultingDescriptor.constructedClass.toSource()?.getMaybeLightElement()
?: (resultingDescriptor as? DeserializedCallableMemberDescriptor)?.let { resolveContainingDeserializedClass(psi, it) }
}
is SamConstructorDescriptor ->
(resultingDescriptor.returnType?.getFunctionalInterfaceType(this, psi) as? PsiClassType)?.resolve()
else -> null
}
}
override fun resolve(): PsiElement? = resolved
override fun asLogString(): String = log<USimpleNameReferenceExpression>("identifier = $identifier, resolvesTo = $resolvedName")
}
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
}

View File

@@ -54,7 +54,7 @@ class KotlinUSwitchEntry(
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
override val caseValues by lz {
psi.conditions.map { KotlinConverter.convertWhenCondition(it, this) ?: UastEmptyExpression }
psi.conditions.map { KotlinConverter.convertWhenCondition(it, this, DEFAULT_EXPRESSION_TYPES_LIST) ?: UastEmptyExpression }
}
override val body: UExpressionList by lz {

View File

@@ -0,0 +1,94 @@
/*
* 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 psi: KtWhenExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), USwitchExpression, KotlinUElementWithType {
override val expression by lz { KotlinConverter.convertOrNull(psi.subjectExpression, this) }
override val body: UExpressionList by lz {
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN, this@KotlinUSwitchExpression) {
override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin }
}.apply {
expressions = this@KotlinUSwitchExpression.psi.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 psi: KtWhenEntry,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
override val caseValues by lz {
psi.conditions.map { KotlinConverter.convertWhenCondition(it, this) ?: UastEmptyExpression }
}
override val body: UExpressionList by lz {
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this@KotlinUSwitchEntry) {
override fun asRenderString() = buildString {
appendln("{")
expressions.forEach { appendln(it.asRenderString().withMargin) }
appendln("}")
}
}.apply {
val exprPsi = this@KotlinUSwitchEntry.psi.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(psi.parent)?.let { parentUnwrapped ->
KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
}
return (result as? KotlinUSwitchExpression)?.body ?: result
}
}

View File

@@ -17,10 +17,7 @@
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.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
class KotlinUTryExpression(
@@ -29,7 +26,15 @@ class KotlinUTryExpression(
) : KotlinAbstractUExpression(givenParent), UTryExpression, KotlinUElementWithType {
override val tryClause by lz { KotlinConverter.convertOrEmpty(psi.tryBlock, this) }
override val catchClauses by lz { psi.catchClauses.map { KotlinUCatchClause(it, this) } }
override val finallyClause by lz { psi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, this) } }
override val finallyClause by lz {
psi.finallyBlock?.finalExpression?.let {
KotlinConverter.convertExpression(
it,
this,
DEFAULT_EXPRESSION_TYPES_LIST
)
}
}
override val resourceVariables: List<UVariable>
get() = emptyList()

View File

@@ -0,0 +1,45 @@
/*
* 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 psi: KtTryExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UTryExpression, KotlinUElementWithType {
override val tryClause by lz { KotlinConverter.convertOrEmpty(psi.tryBlock, this) }
override val catchClauses by lz { psi.catchClauses.map { KotlinUCatchClause(it, this) } }
override val finallyClause by lz { psi.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
}

View File

@@ -23,7 +23,7 @@ internal class KotlinLocalFunctionUVariable(
createLocalFunctionLambdaExpression(function, this)
}
override val typeReference: UTypeReferenceExpression? = null
override val uastAnchor: UElement? = null
override val uastAnchor: UIdentifier? = null
override val annotations: List<UAnnotation> = emptyList()
}

View File

@@ -0,0 +1,24 @@
Closeable -> USimpleNameReferenceExpression (identifier = Closeable) from KtDotQualifiedExpression
io -> USimpleNameReferenceExpression (identifier = io) from KtDotQualifiedExpression
java -> USimpleNameReferenceExpression (identifier = java) from KtNameReferenceExpression
io -> USimpleNameReferenceExpression (identifier = io) from KtNameReferenceExpression
Closeable -> USimpleNameReferenceExpression (identifier = Closeable) from KtNameReferenceExpression
InputStream -> USimpleNameReferenceExpression (identifier = InputStream) from KtDotQualifiedExpression
io -> USimpleNameReferenceExpression (identifier = io) from KtDotQualifiedExpression
java -> USimpleNameReferenceExpression (identifier = java) from KtNameReferenceExpression
io -> USimpleNameReferenceExpression (identifier = io) from KtNameReferenceExpression
InputStream -> USimpleNameReferenceExpression (identifier = InputStream) from KtNameReferenceExpression
Runnable -> USimpleNameReferenceExpression (identifier = Runnable) from KtNameReferenceExpression
run -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
runnable -> USimpleNameReferenceExpression (identifier = runnable) from KtNameReferenceExpression
run -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Runnable -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
run -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
runnable2 -> USimpleNameReferenceExpression (identifier = runnable2) from KtNameReferenceExpression
run -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Runnable -> USimpleNameReferenceExpression (identifier = Runnable) from KtNameReferenceExpression
Closeable -> USimpleNameReferenceExpression (identifier = Closeable) from KtNameReferenceExpression
InputStream -> UObjectLiteralExpression from KtNameReferenceExpression
Runnable -> USimpleNameReferenceExpression (identifier = Runnable) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression

View File

@@ -0,0 +1,10 @@
UFile (package = ) [public final class AssertionKt {...]
UClass (name = AssertionKt) [public final class AssertionKt {...}]
UAnnotationMethod (name = foo) [public static final fun foo() : java.lang.String {...}]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [var s: java.lang.String = "Not Null"] = Undetermined
ULocalVariable (name = s) [var s: java.lang.String = "Not Null"]
ULiteralExpression (value = "Not Null") ["Not Null"] = "Not Null"
UReturnExpression [return s!!] = Nothing
UPostfixExpression (operator = !!) [s!!] = (var s = "Not Null")
USimpleNameReferenceExpression (identifier = s) [s] = (var s = "Not Null")

View File

@@ -0,0 +1,56 @@
[1]:[UFile (package = )]
[1]:[UClass (name = A)]
[1]:[UAnnotation (fqName = null)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = <ErrorType>)]
[1]:[USimpleNameReferenceExpression (identifier = Test)]
[1]:[UIdentifier (Identifier (Test))]
[1]:[UIdentifier (Identifier (A))]
[1]:[UClass (name = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[UDeclarationsExpression]
[1]:[UDeclarationsExpression]
[1]:[UAnnotationMethod (name = text)]
[1]:[UIdentifier (Identifier (text))]
[1]:[UTypeReferenceExpression (name = java.lang.String)]
[1]:[USimpleNameReferenceExpression (identifier = String)]
[1]:[UIdentifier (Identifier (String))]
[1]:[UClass (name = B)]
[1]:[UAnnotation (fqName = MyAnnotation)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[ULiteralExpression (value = "class")]
[1]:[ULiteralExpression (value = "class")]
[1]:[UIdentifier (Identifier (B))]
[1]:[UExpressionList (class_body)]
[1]:[UClass (name = InB)]
[1]:[UAnnotation (fqName = MyAnnotation)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[ULiteralExpression (value = "inB class")]
[1]:[ULiteralExpression (value = "inB class")]
[1]:[UIdentifier (Identifier (InB))]
[1]:[UExpressionList (class_body)]
[1]:[UClass (name = Companion)]
[1]:[UAnnotation (fqName = MyAnnotation)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[ULiteralExpression (value = "companion")]
[1]:[ULiteralExpression (value = "companion")]
[1]:[UIdentifier (Identifier (object))]
[1]:[UExpressionList (class_body)]
[1]:[UClass (name = Obj)]
[1]:[UAnnotation (fqName = MyAnnotation)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[ULiteralExpression (value = "object")]
[1]:[ULiteralExpression (value = "object")]
[1]:[UIdentifier (Identifier (Obj))]

View File

@@ -1,7 +1,7 @@
Test -> UAnnotation (fqName = null)
A -> UClass (name = A)
MyAnnotation -> UClass (name = MyAnnotation)
text -> [!] UnknownKotlinExpression (VALUE_PARAMETER)
text -> UAnnotationMethod (name = text)
String -> USimpleNameReferenceExpression (identifier = String)
MyAnnotation -> UAnnotation (fqName = MyAnnotation)
B -> UClass (name = B)

View File

@@ -0,0 +1,13 @@
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)

View File

@@ -0,0 +1,6 @@
Test -> UAnnotation (fqName = null) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
MyAnnotation -> UAnnotation (fqName = MyAnnotation) from KtNameReferenceExpression
MyAnnotation -> UAnnotation (fqName = MyAnnotation) from KtNameReferenceExpression
MyAnnotation -> UAnnotation (fqName = MyAnnotation) from KtNameReferenceExpression
MyAnnotation -> UAnnotation (fqName = MyAnnotation) from KtNameReferenceExpression

View File

@@ -0,0 +1,44 @@
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
a -> USimpleNameReferenceExpression (identifier = a) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
a -> USimpleNameReferenceExpression (identifier = a) from KtNameReferenceExpression
s -> USimpleNameReferenceExpression (identifier = s) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
a -> USimpleNameReferenceExpression (identifier = a) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
a -> USimpleNameReferenceExpression (identifier = a) from KtNameReferenceExpression
s -> USimpleNameReferenceExpression (identifier = s) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
s -> USimpleNameReferenceExpression (identifier = s) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
local -> USimpleNameReferenceExpression (identifier = local) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression

View File

@@ -0,0 +1,37 @@
[1]:[UFile (package = )]
[1]:[UClass (name = Foo)]
[1]:[UIdentifier (Identifier (Foo))]
[1]:[UExpressionList (class_body)]
[2]:[UClass (name = Bar), UAnnotationMethod (name = Bar)]
[1]:[UIdentifier (Identifier (Bar))]
[1]:[UAnnotationMethod (name = Bar)]
[1]:[UDeclarationsExpression]
[3]:[UParameter (name = a), UField (name = a), UAnnotationMethod (name = getA)]
[1]:[UIdentifier (Identifier (a))]
[1]:[UTypeReferenceExpression (name = int)]
[1]:[USimpleNameReferenceExpression (identifier = Int)]
[1]:[UIdentifier (Identifier (Int))]
[3]:[UParameter (name = b), UField (name = b), UAnnotationMethod (name = getB)]
[1]:[UIdentifier (Identifier (b))]
[1]:[UTypeReferenceExpression (name = int)]
[1]:[USimpleNameReferenceExpression (identifier = Int)]
[1]:[UIdentifier (Identifier (Int))]
[1]:[UExpressionList (class_body)]
[1]:[UAnnotationMethod (name = getAPlusB)]
[1]:[UIdentifier (Identifier (getAPlusB))]
[1]:[UDeclarationsExpression]
[1]:[UBinaryExpression (operator = +)]
[1]:[USimpleNameReferenceExpression (identifier = a)]
[1]:[UIdentifier (Identifier (a))]
[1]:[USimpleNameReferenceExpression (identifier = +)]
[1]:[UIdentifier (Identifier (+))]
[1]:[USimpleNameReferenceExpression (identifier = b)]
[1]:[UIdentifier (Identifier (b))]
[1]:[UClass (name = Baz)]
[1]:[UIdentifier (Identifier (Baz))]
[1]:[UExpressionList (class_body)]
[1]:[UAnnotationMethod (name = doNothing)]
[1]:[UIdentifier (Identifier (doNothing))]
[1]:[UDeclarationsExpression]
[1]:[USimpleNameReferenceExpression (identifier = Unit)]
[1]:[UIdentifier (Identifier (Unit))]

View File

@@ -0,0 +1,9 @@
UFile (package = )
UClass (name = Foo)
UClass (name = Bar)
UAnnotationMethod (name = Bar)
UField (name = a)
UField (name = b)
UAnnotationMethod (name = getAPlusB)
UClass (name = Baz)
UAnnotationMethod (name = doNothing)

View File

@@ -0,0 +1,47 @@
[2]:[UFile (package = ), UClass (name = LocalDeclarationsKt)]
[1]:[UAnnotationMethod (name = foo)]
[1]:[UIdentifier (Identifier (foo))]
[1]:[UDeclarationsExpression]
[1]:[UTypeReferenceExpression (name = boolean)]
[1]:[USimpleNameReferenceExpression (identifier = Boolean)]
[1]:[UIdentifier (Identifier (Boolean))]
[1]:[UBlockExpression]
[1]:[UClass (name = Local)]
[1]:[UIdentifier (Identifier (Local))]
[1]:[ULambdaExpression]
[1]:[UIdentifier (Identifier (bar))]
[1]:[UDeclarationsExpression]
[1]:[UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))]
[1]:[USimpleNameReferenceExpression (identifier = Local)]
[1]:[UIdentifier (Identifier (Local))]
[1]:[ULocalVariable (name = baz)]
[1]:[UIdentifier (Identifier (baz))]
[1]:[ULambdaExpression]
[1]:[UDeclarationsExpression]
[1]:[UBlockExpression]
[1]:[UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))]
[1]:[USimpleNameReferenceExpression (identifier = Local)]
[1]:[UIdentifier (Identifier (Local))]
[1]:[ULambdaExpression]
[1]:[UTypeReferenceExpression (name = int)]
[1]:[USimpleNameReferenceExpression (identifier = Int)]
[1]:[UIdentifier (Identifier (Int))]
[1]:[UIdentifier (Identifier (someLocalFun))]
[1]:[UDeclarationsExpression]
[1]:[UIdentifier (Identifier (text))]
[1]:[UTypeReferenceExpression (name = java.lang.String)]
[1]:[USimpleNameReferenceExpression (identifier = String)]
[1]:[UIdentifier (Identifier (String))]
[1]:[ULiteralExpression (value = 42)]
[1]:[UClass (name = LocalObject)]
[1]:[UIdentifier (Identifier (LocalObject))]
[1]:[UReturnExpression]
[1]:[UBinaryExpression (operator = ==)]
[1]:[UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))]
[1]:[USimpleNameReferenceExpression (identifier = bar)]
[1]:[UIdentifier (Identifier (bar))]
[1]:[USimpleNameReferenceExpression (identifier = ==)]
[1]:[UIdentifier (Identifier (==))]
[1]:[UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))]
[1]:[USimpleNameReferenceExpression (identifier = Local)]
[1]:[UIdentifier (Identifier (Local))]

View File

@@ -0,0 +1,7 @@
Boolean -> USimpleNameReferenceExpression (identifier = Boolean) from KtNameReferenceExpression
Local -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) from KtNameReferenceExpression
Local -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
bar -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Local -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) from KtNameReferenceExpression

View File

@@ -0,0 +1,5 @@
class ClassA(justParam: Int, val paramAndProp: String) {
var writebleProp: Int = 0
}

View File

View File

@@ -0,0 +1,59 @@
[1]:[UFile (package = )]
[1]:[UClass (name = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[UClass (name = MyAnnotation2)]
[1]:[UIdentifier (Identifier (MyAnnotation2))]
[1]:[UClass (name = MyAnnotation3)]
[1]:[UIdentifier (Identifier (MyAnnotation3))]
[1]:[UClass (name = MyAnnotation4)]
[1]:[UIdentifier (Identifier (MyAnnotation4))]
[1]:[UClass (name = MyAnnotation5)]
[1]:[UIdentifier (Identifier (MyAnnotation5))]
[2]:[UClass (name = Test1), UAnnotationMethod (name = Test1)]
[1]:[UIdentifier (Identifier (Test1))]
[1]:[UAnnotationMethod (name = Test1)]
[1]:[UDeclarationsExpression]
[4]:[UParameter (name = bar), UField (name = bar), UAnnotationMethod (name = getBar), UAnnotationMethod (name = setBar)]
[1]:[UAnnotation (fqName = MyAnnotation)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[UIdentifier (Identifier (bar))]
[1]:[UTypeReferenceExpression (name = int)]
[1]:[USimpleNameReferenceExpression (identifier = Int)]
[1]:[UIdentifier (Identifier (Int))]
[2]:[UClass (name = Test2), UAnnotationMethod (name = Test2)]
[1]:[UIdentifier (Identifier (Test2))]
[1]:[UAnnotationMethod (name = Test2)]
[1]:[UDeclarationsExpression]
[4]:[UParameter (name = bar), UField (name = bar), UAnnotationMethod (name = getBar), UAnnotationMethod (name = setBar)]
[1]:[UAnnotation (fqName = MyAnnotation)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation)]
[1]:[UIdentifier (Identifier (MyAnnotation))]
[1]:[UAnnotation (fqName = MyAnnotation2)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation2)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation2)]
[1]:[UIdentifier (Identifier (MyAnnotation2))]
[1]:[UAnnotation (fqName = MyAnnotation3)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation3)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation3)]
[1]:[UIdentifier (Identifier (MyAnnotation3))]
[1]:[UAnnotation (fqName = MyAnnotation4)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation4)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation4)]
[1]:[UIdentifier (Identifier (MyAnnotation4))]
[1]:[UAnnotation (fqName = MyAnnotation5)]
[1]:[[!] UnknownKotlinExpression (CONSTRUCTOR_CALLEE)]
[1]:[UTypeReferenceExpression (name = MyAnnotation5)]
[1]:[USimpleNameReferenceExpression (identifier = MyAnnotation5)]
[1]:[UIdentifier (Identifier (MyAnnotation5))]
[1]:[UIdentifier (Identifier (bar))]
[1]:[UTypeReferenceExpression (name = int)]
[1]:[USimpleNameReferenceExpression (identifier = Int)]
[1]:[UIdentifier (Identifier (Int))]

View File

@@ -0,0 +1,5 @@
Suppress -> UAnnotation (fqName = kotlin.Suppress) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
kotlin -> USimpleNameReferenceExpression (identifier = kotlin) from KtNameReferenceExpression
SinceKotlin -> UAnnotation (fqName = kotlin.SinceKotlin) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression

Some files were not shown because too many files have changed in this diff Show More