Compare commits

...

9 Commits

Author SHA1 Message Date
Vadim Brilyantov
2ce9e58e87 tmp 2018-12-05 20:04:16 +03:00
Vadim Brilyantov
fad8a85886 report stats for pullUp/pushDown refactorings 2018-12-05 17:27:52 +03:00
Vadim Brilyantov
9e5b69eb23 report stats for all renaming refactorings 2018-12-05 16:27:24 +03:00
Vadim Brilyantov
41f635dd48 add target reporting 2018-12-05 16:27:23 +03:00
Vadim Brilyantov
efeb9e2fef fix build for idea plugin with usage statistics 2018-12-05 16:27:22 +03:00
Vadim Brilyantov
2057c80252 trigger intentions, quickFixes and most of rename refactorings 2018-12-05 16:27:21 +03:00
Vadim Brilyantov
1789895eb2 update 2018-12-05 16:27:20 +03:00
Vadim Brilyantov
d2d8cd10b3 create usages-statistics module 2018-12-05 16:27:19 +03:00
Vadim Brilyantov
2d7682ff62 ~~~~ switch 183 ~~~~ 2018-12-05 15:18:19 +03:00
110 changed files with 5562 additions and 129 deletions

View File

@@ -12,9 +12,6 @@
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="72" />
</MarkdownNavigatorCodeStyleSettings>
@@ -97,7 +94,6 @@
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
</codeStyleSettings>
</code_scheme>

1
.idea/vcs.xml generated
View File

@@ -24,5 +24,6 @@
</component>
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

0
LOG_helloApp_.alive.txt Normal file
View File

View File

@@ -7,4 +7,7 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.org.objectweb.asm.MethodVisitor
internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {}
internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {
mv.visitAnnotableParameterCount(paramCount, true)
mv.visitAnnotableParameterCount(paramCount, false)
}

View File

@@ -0,0 +1,10 @@
/*
* 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.codegen
import org.jetbrains.org.objectweb.asm.MethodVisitor
internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {}

View File

@@ -0,0 +1,24 @@
/*
* 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.cli.jvm.compiler
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.lang.jvm.facade.JvmElementProvider
import com.intellij.openapi.extensions.ExtensionsArea
import com.intellij.psi.JavaModuleSystem
import com.intellij.psi.impl.compiled.ClsCustomNavigationPolicy
internal object IdeaExtensionPoints {
fun registerVersionSpecificAppExtensionPoints(area: ExtensionsArea) {
@Suppress("DEPRECATION")
CoreApplicationEnvironment.registerExtensionPoint(area, ClsCustomNavigationPolicy.EP_NAME, ClsCustomNavigationPolicy::class.java)
CoreApplicationEnvironment.registerExtensionPoint(area, JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
}
fun registerVersionSpecificProjectExtensionPoints(area: ExtensionsArea) {
CoreApplicationEnvironment.registerExtensionPoint(area, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
}
}

View File

@@ -22,11 +22,10 @@ import com.intellij.psi.PsiModifierListOwner
class MockInferredAnnotationsManager : InferredAnnotationsManager() {
override fun findInferredAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String): PsiAnnotation? = null
override fun ignoreInference(owner: PsiModifierListOwner, annotationFQN: String?): Boolean = true
override fun findInferredAnnotations(listOwner: PsiModifierListOwner): Array<out PsiAnnotation> = EMPTY_PSI_ANNOTATION_ARRAY
override fun isInferredAnnotation(annotation: PsiAnnotation): Boolean = false
companion object {
val EMPTY_PSI_ANNOTATION_ARRAY = arrayOf<PsiAnnotation>()
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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.InferredAnnotationsManager
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiModifierListOwner
class MockInferredAnnotationsManager : InferredAnnotationsManager() {
override fun findInferredAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String): PsiAnnotation? = null
override fun ignoreInference(owner: PsiModifierListOwner, annotationFQN: String?): Boolean = true
override fun findInferredAnnotations(listOwner: PsiModifierListOwner): Array<out PsiAnnotation> = EMPTY_PSI_ANNOTATION_ARRAY
override fun isInferredAnnotation(annotation: PsiAnnotation): Boolean = false
companion object {
val EMPTY_PSI_ANNOTATION_ARRAY = arrayOf<PsiAnnotation>()
}
}

View File

@@ -18,6 +18,6 @@ import com.intellij.util.AstLoadingFilter
object AstLoadingFilter {
@JvmStatic
fun <T, E : Throwable> forceAllowTreeLoading(psiFile: PsiFile, computable: ThrowableComputable<out T, E>): T {
return AstLoadingFilter.forceEnableTreeLoading(psiFile, computable)
return AstLoadingFilter.forceAllowTreeLoading(psiFile, computable)
}
}

View File

@@ -0,0 +1,23 @@
/*
* 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.util
import com.intellij.openapi.util.ThrowableComputable
import com.intellij.psi.PsiFile
import com.intellij.util.AstLoadingFilter
/**
* Absent in 181. Methods were renamed in 183.
*
* BUNCH: 183
*/
@Suppress("IncompatibleAPI")
object AstLoadingFilter {
@JvmStatic
fun <T, E : Throwable> forceAllowTreeLoading(psiFile: PsiFile, computable: ThrowableComputable<out T, E>): T {
return AstLoadingFilter.forceEnableTreeLoading(psiFile, computable)
}
}

View File

@@ -2,10 +2,10 @@ public final class AnnotatedParameterInInnerClassConstructor {
public AnnotatedParameterInInnerClassConstructor() { /* compiled code */ }
public final class Inner {
public Inner(@test.Anno(x = "a") @org.jetbrains.annotations.NotNull java.lang.String $outer, @test.Anno(x = "b") @org.jetbrains.annotations.NotNull java.lang.String a) { /* compiled code */ }
public Inner(@test.Anno(x = "a") @org.jetbrains.annotations.NotNull java.lang.String a, @test.Anno(x = "b") @org.jetbrains.annotations.NotNull java.lang.String b) { /* compiled code */ }
}
public final class InnerGeneric <T> {
public InnerGeneric(@test.Anno(x = "a") T $outer, @test.Anno(x = "b") @org.jetbrains.annotations.NotNull java.lang.String a) { /* compiled code */ }
public InnerGeneric(@test.Anno(x = "a") T a, @test.Anno(x = "b") @org.jetbrains.annotations.NotNull java.lang.String b) { /* compiled code */ }
}
}

View File

@@ -0,0 +1,11 @@
public final class AnnotatedParameterInInnerClassConstructor {
public AnnotatedParameterInInnerClassConstructor() { /* compiled code */ }
public final class Inner {
public Inner(@test.Anno(x = "a") @org.jetbrains.annotations.NotNull java.lang.String $outer, @test.Anno(x = "b") @org.jetbrains.annotations.NotNull java.lang.String a) { /* compiled code */ }
}
public final class InnerGeneric <T> {
public InnerGeneric(@test.Anno(x = "a") T $outer, @test.Anno(x = "b") @org.jetbrains.annotations.NotNull java.lang.String a) { /* compiled code */ }
}
}

View File

@@ -14,7 +14,7 @@ public final class Sealed$Inner {
synthetic final field this$0: Sealed
private final field z2: int
inner class Sealed$Inner
public synthetic @Ann method <init>(@java.lang.Synthetic p0: Sealed, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic @Ann method <init>(p0: Sealed, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
private method <init>(p0: Sealed, p1: int, p2: int, p3: java.lang.String): void
public final method getZ2(): int
}
@@ -34,7 +34,7 @@ public final class Test$Inner {
synthetic final field this$0: Test
private final field z2: int
inner class Test$Inner
public synthetic @Ann method <init>(@java.lang.Synthetic p0: Test, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic @Ann method <init>(p0: Test, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
private method <init>(p0: Test, p1: int, p2: int, p3: java.lang.String): void
public final method getZ2(): int
}

View File

@@ -0,0 +1,69 @@
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Ann
@kotlin.Metadata
public final class Sealed$Derived {
inner class Sealed$Derived
private method <init>(p0: int): void
public synthetic @Ann method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
}
@kotlin.Metadata
public final class Sealed$Inner {
synthetic final field this$0: Sealed
private final field z2: int
inner class Sealed$Inner
public synthetic @Ann method <init>(@java.lang.Synthetic p0: Sealed, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
private method <init>(p0: Sealed, p1: int, p2: int, p3: java.lang.String): void
public final method getZ2(): int
}
@kotlin.Metadata
public abstract class Sealed {
private final field z: int
inner class Sealed$Derived
inner class Sealed$Inner
private @Ann method <init>(@Ann p0: int): void
public synthetic method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
public final method getZ(): int
}
@kotlin.Metadata
public final class Test$Inner {
synthetic final field this$0: Test
private final field z2: int
inner class Test$Inner
public synthetic @Ann method <init>(@java.lang.Synthetic p0: Test, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
private method <init>(p0: Test, p1: int, p2: int, p3: java.lang.String): void
public final method getZ2(): int
}
@kotlin.Metadata
public final class Test {
private final field z: int
inner class Test$Inner
public synthetic @Ann method <init>(@Ann p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
private method <init>(p0: int): void
public synthetic @Ann method <init>(p0: int, @Ann p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
private @Ann method <init>(p0: int, @Ann p1: java.lang.String): void
private method <init>(p0: int, p1: int): void
public final method getZ(): int
}
@kotlin.Metadata
public final class Z {
private final field x: int
private synthetic method <init>(p0: int): void
public synthetic final static @org.jetbrains.annotations.NotNull method box-impl(p0: int): Z
public static method constructor-impl(p0: int): int
public method equals(p0: java.lang.Object): boolean
public static method equals-impl(p0: int, @org.jetbrains.annotations.Nullable p1: java.lang.Object): boolean
public final static method equals-impl0(p0: int, p1: int): boolean
public final method getX(): int
public method hashCode(): int
public static method hashCode-impl(p0: int): int
public method toString(): java.lang.String
public static @org.jetbrains.annotations.NotNull method toString-impl(p0: int): java.lang.String
public synthetic final method unbox-impl(): int
}

View File

@@ -81,11 +81,11 @@ public final class CClassWithCompanion {
public final class DClassConstuctors$InnerClass {
synthetic final field this$0: DClassConstuctors
inner class DClassConstuctors$InnerClass
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic @java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, @LongRes p2: long): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, p2: int): void
public @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, @StringRes p1: int): void
public @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, @StringRes p1: int, @LongRes p2: long): void
public @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, @StringRes p1: int, p2: int): void
public synthetic @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, p1: int, p2: int, p3: int, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, p1: int, p2: int, p3: long, p4: java.lang.String, p5: int, p6: kotlin.jvm.internal.DefaultConstructorMarker): void
}

View File

@@ -0,0 +1,133 @@
@kotlin.Metadata
public final class ASimpleClass {
public method <init>(): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbar$default(p0: ASimpleClass, p1: java.lang.String, p2: int, p3: int, p4: int, p5: java.lang.Object): void
public final @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int): void
public final @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, p2: int): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbarLong$default(p0: ASimpleClass, p1: java.lang.String, p2: int, p3: int, p4: long, p5: java.lang.String, p6: int, p7: java.lang.Object): void
public final @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public final @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public final @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @LongRes p2: long): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension$default(p0: ASimpleClass, p1: int, p2: int, p3: long, p4: java.lang.String, p5: int, p6: java.lang.Object): void
public final @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long): void
public final @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long, @org.jetbrains.annotations.NotNull p3: java.lang.String): void
public final @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @LongRes p1: long): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbarNoExtension$default(p0: ASimpleClass, p1: int, p2: int, p3: int, p4: java.lang.Object): void
public final @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int): void
public final @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int, p1: int): void
}
@kotlin.Metadata
public final class BSimpleObject {
public final static field INSTANCE: BSimpleObject
static method <clinit>(): void
private method <init>(): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar$default(p0: java.lang.String, p1: int, p2: int, p3: int, p4: java.lang.Object): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, p2: int): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong$default(p0: java.lang.String, p1: int, p2: int, p3: long, p4: java.lang.String, p5: int, p6: java.lang.Object): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @LongRes p2: long): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension$default(p0: int, p1: int, p2: long, p3: java.lang.String, p4: int, p5: java.lang.Object): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long, @org.jetbrains.annotations.NotNull p3: java.lang.String): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @LongRes p1: long): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension$default(p0: int, p1: int, p2: int, p3: java.lang.Object): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int, p1: int): void
}
@kotlin.Metadata
public final class CClassWithCompanion$Companion {
inner class CClassWithCompanion$Companion
private method <init>(): void
public synthetic method <init>(p0: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar$default(p0: CClassWithCompanion$Companion, p1: java.lang.String, p2: int, p3: int, p4: int, p5: java.lang.Object): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, p2: int): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong$default(p0: CClassWithCompanion$Companion, p1: java.lang.String, p2: int, p3: int, p4: long, p5: java.lang.String, p6: int, p7: java.lang.Object): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @LongRes p2: long): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension$default(p0: CClassWithCompanion$Companion, p1: int, p2: int, p3: long, p4: java.lang.String, p5: int, p6: java.lang.Object): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long, @org.jetbrains.annotations.NotNull p3: java.lang.String): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @LongRes p1: long): void
public synthetic static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension$default(p0: CClassWithCompanion$Companion, p1: int, p2: int, p3: int, p4: java.lang.Object): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int): void
public final @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int, p1: int): void
}
@kotlin.Metadata
public final class CClassWithCompanion {
public final static field Companion: CClassWithCompanion$Companion
inner class CClassWithCompanion$Companion
static method <clinit>(): void
public method <init>(): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, p2: int): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @LongRes p2: long): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long, @org.jetbrains.annotations.NotNull p3: java.lang.String): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @LongRes p1: long): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int): void
public final static @kotlin.jvm.JvmStatic @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int, p1: int): void
}
@kotlin.Metadata
public final class DClassConstuctors$InnerClass {
synthetic final field this$0: DClassConstuctors
inner class DClassConstuctors$InnerClass
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic @java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, @LongRes p2: long): void
public @kotlin.jvm.JvmOverloads method <init>(@java.lang.Synthetic p0: DClassConstuctors, @StringRes p1: int, p2: int): void
public synthetic @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, p1: int, p2: int, p3: int, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic @kotlin.jvm.JvmOverloads method <init>(p0: DClassConstuctors, p1: int, p2: int, p3: long, p4: java.lang.String, p5: int, p6: kotlin.jvm.internal.DefaultConstructorMarker): void
}
@kotlin.Metadata
public final class DClassConstuctors {
inner class DClassConstuctors$InnerClass
public @kotlin.jvm.JvmOverloads method <init>(@StringRes p0: int): void
public @kotlin.jvm.JvmOverloads method <init>(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long): void
public @kotlin.jvm.JvmOverloads method <init>(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long, @org.jetbrains.annotations.NotNull p3: java.lang.String): void
public @kotlin.jvm.JvmOverloads method <init>(@StringRes p0: int, @LongRes p1: long): void
public @kotlin.jvm.JvmOverloads method <init>(@StringRes p0: int, p1: int): void
public synthetic @kotlin.jvm.JvmOverloads method <init>(p0: int, p1: int, p2: int, p3: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic @kotlin.jvm.JvmOverloads method <init>(p0: int, p1: int, p2: long, p3: java.lang.String, p4: int, p5: kotlin.jvm.internal.DefaultConstructorMarker): void
}
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class DefRes
@kotlin.Metadata
public final class JvmOverloadsAndParametersAnnotationsKt {
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbar$default(p0: java.lang.String, p1: int, p2: int, p3: int, p4: java.lang.Object): void
public final static @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int): void
public final static @kotlin.jvm.JvmOverloads method showSnackbar(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, p2: int): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbarLong$default(p0: java.lang.String, p1: int, p2: int, p3: long, p4: java.lang.String, p5: int, p6: java.lang.Object): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @DefRes p2: int, @LongRes p3: long, @org.jetbrains.annotations.NotNull p4: java.lang.String): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarLong(@org.jetbrains.annotations.NotNull p0: java.lang.String, @StringRes p1: int, @LongRes p2: long): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension$default(p0: int, p1: int, p2: long, p3: java.lang.String, p4: int, p5: java.lang.Object): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @DefRes p1: int, @LongRes p2: long, @org.jetbrains.annotations.NotNull p3: java.lang.String): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarLongNoExtension(@StringRes p0: int, @LongRes p1: long): void
public synthetic static @kotlin.jvm.JvmOverloads method showSnackbarNoExtension$default(p0: int, p1: int, p2: int, p3: java.lang.Object): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int): void
public final static @kotlin.jvm.JvmOverloads method showSnackbarNoExtension(@StringRes p0: int, p1: int): void
}
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class LongRes
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class StringRes

View File

@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInspection.IntentionWrapper
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.containsInside
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.statistics.KotlinIdeIntentionTrigger
@Suppress("EqualsOrHashCode")
abstract class SelfTargetingIntention<TElement : PsiElement>(
@@ -101,6 +103,10 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
final override fun invoke(project: Project, editor: Editor?, file: PsiFile) {
editor ?: return
FUSApplicationUsageTrigger.getInstance().trigger(
KotlinIdeIntentionTrigger::class.java,
this::class.java.simpleName
)
PsiDocumentManager.getInstance(project).commitAllDocuments()
val target = getTarget(editor, file) ?: return
if (!FileModificationService.getInstance().preparePsiElementForWrite(target)) return

View File

@@ -21,9 +21,7 @@ import com.android.tools.idea.rendering.RenderSecurityManager;
import com.android.tools.idea.startup.AndroidCodeStyleSettingsModifier;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.GlobalInspectionTool;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.InspectionManagerEx;
import com.intellij.facet.FacetManager;
import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.Disposable;
@@ -41,13 +39,13 @@ import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.testFramework.InspectionTestUtil;
import com.intellij.testFramework.InspectionsKt;
import com.intellij.testFramework.ThreadTracker;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.testFramework.fixtures.JavaTestFixtureFactory;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.testFramework.fixtures.impl.GlobalInspectionContextForTests;
import com.intellij.util.ArrayUtil;
import org.jetbrains.android.facet.AndroidFacet;
@@ -61,6 +59,7 @@ import org.picocontainer.MutablePicoContainer;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -343,9 +342,8 @@ public abstract class AndroidTestCase extends AndroidTestBase {
scope.invalidate();
InspectionManagerEx inspectionManager = (InspectionManagerEx)InspectionManager.getInstance(getProject());
GlobalInspectionContextForTests globalContext =
CodeInsightTestFixtureImpl.createGlobalContextForTool(scope, getProject(), inspectionManager, wrapper);
InspectionsKt.createGlobalContextForTool(scope, getProject(), Collections.singletonList(wrapper));
InspectionTestUtil.runTool(wrapper, scope, globalContext);
InspectionTestUtil.compareToolResults(globalContext, wrapper, false, getTestDataPath() + globalTestDir);

View File

@@ -0,0 +1,388 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android;
import com.android.SdkConstants;
import com.android.tools.idea.rendering.RenderSecurityManager;
import com.android.tools.idea.startup.AndroidCodeStyleSettingsModifier;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.GlobalInspectionTool;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.InspectionManagerEx;
import com.intellij.facet.FacetManager;
import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.testFramework.InspectionTestUtil;
import com.intellij.testFramework.ThreadTracker;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.testFramework.fixtures.JavaTestFixtureFactory;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.testFramework.fixtures.impl.GlobalInspectionContextForTests;
import com.intellij.util.ArrayUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.formatter.AndroidXmlCodeStyleSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.picocontainer.MutablePicoContainer;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Copied from AS 2.3 sources
*/
@SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
public abstract class AndroidTestCase extends AndroidTestBase {
protected Module myModule;
protected List<Module> myAdditionalModules;
protected AndroidFacet myFacet;
protected CodeStyleSettings mySettings;
private List<String> myAllowedRoots = new ArrayList<>();
private boolean myUseCustomSettings;
@Override
protected void setUp() throws Exception {
super.setUp();
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName());
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture());
JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class);
File moduleRoot = new File(myFixture.getTempDirPath());
if (!moduleRoot.exists()) {
assertTrue(moduleRoot.mkdirs());
}
initializeModuleFixtureBuilderWithSrcAndGen(moduleFixtureBuilder, moduleRoot.toString());
ArrayList<MyAdditionalModuleData> modules = new ArrayList<>();
configureAdditionalModules(projectBuilder, modules);
myFixture.setUp();
myFixture.setTestDataPath(getTestDataPath());
myModule = moduleFixtureBuilder.getFixture().getModule();
// Must be done before addAndroidFacet, and must always be done, even if a test provides
// its own custom manifest file. However, in that case, we will delete it shortly below.
createManifest();
myFacet = addAndroidFacet(myModule);
LanguageLevel languageLevel = getLanguageLevel();
if (languageLevel != null) {
LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myModule.getProject());
if (extension != null) {
extension.setLanguageLevel(languageLevel);
}
}
// TODO: myFixture.copyDirectoryToProject(getResDir(), "res");
myAdditionalModules = new ArrayList<>();
for (MyAdditionalModuleData data : modules) {
Module additionalModule = data.myModuleFixtureBuilder.getFixture().getModule();
myAdditionalModules.add(additionalModule);
AndroidFacet facet = addAndroidFacet(additionalModule);
facet.getProperties().PROJECT_TYPE = data.myProjectType;
String rootPath = getAdditionalModulePath(data.myDirName);
myFixture.copyDirectoryToProject(getResDir(), rootPath + "/res");
myFixture.copyFileToProject(SdkConstants.FN_ANDROID_MANIFEST_XML, rootPath + '/' + SdkConstants.FN_ANDROID_MANIFEST_XML);
if (data.myIsMainModuleDependency) {
ModuleRootModificationUtil.addDependency(myModule, additionalModule);
}
}
if (providesCustomManifest()) {
deleteManifest();
}
if (RenderSecurityManager.RESTRICT_READS) {
// Unit test class loader includes disk directories which security manager does not allow access to
RenderSecurityManager.sEnabled = false;
}
ArrayList<String> allowedRoots = new ArrayList<>();
collectAllowedRoots(allowedRoots);
// TODO: registerAllowedRoots(allowedRoots, myTestRootDisposable);
mySettings = CodeStyleSettingsManager.getSettings(getProject()).clone();
AndroidCodeStyleSettingsModifier.modify(mySettings);
CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(mySettings);
myUseCustomSettings = getAndroidCodeStyleSettings().USE_CUSTOM_SETTINGS;
getAndroidCodeStyleSettings().USE_CUSTOM_SETTINGS = true;
// Layoutlib rendering thread will be shutdown when the app is closed so do not report it as a leak
ThreadTracker.longRunningThreadCreated(ApplicationManager.getApplication(), "Layoutlib");
}
@Override
protected void tearDown() throws Exception {
try {
Sdk androidSdk = ProjectJdkTable.getInstance().findJdk(ANDROID_SDK_NAME);
if (androidSdk != null) {
ApplicationManager.getApplication().runWriteAction(() -> ProjectJdkTable.getInstance().removeJdk(androidSdk));
}
CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings();
myModule = null;
myAdditionalModules = null;
myFixture.tearDown();
myFixture = null;
myFacet = null;
getAndroidCodeStyleSettings().USE_CUSTOM_SETTINGS = myUseCustomSettings;
if (RenderSecurityManager.RESTRICT_READS) {
RenderSecurityManager.sEnabled = true;
}
}
finally {
super.tearDown();
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
}
}
private static void initializeModuleFixtureBuilderWithSrcAndGen(JavaModuleFixtureBuilder moduleFixtureBuilder, String moduleRoot) {
moduleFixtureBuilder.addContentRoot(moduleRoot);
//noinspection ResultOfMethodCallIgnored
new File(moduleRoot + "/src/").mkdir();
moduleFixtureBuilder.addSourceRoot("src");
//noinspection ResultOfMethodCallIgnored
new File(moduleRoot + "/gen/").mkdir();
moduleFixtureBuilder.addSourceRoot("gen");
}
/**
* Returns the path that any additional modules registered by
* {@link #configureAdditionalModules(TestFixtureBuilder, List)} or
* {@link #addModuleWithAndroidFacet(TestFixtureBuilder, List, String, int, boolean)} are
* installed into.
*/
protected static String getAdditionalModulePath(@NotNull String moduleName) {
return "/additionalModules/" + moduleName;
}
/**
* Indicates whether this class provides its own {@code AndroidManifest.xml} for its tests. If
* {@code true}, then {@link #setUp()} calls {@link #deleteManifest()} before finishing.
*/
protected boolean providesCustomManifest() {
return false;
}
/**
* Get the "res" directory for this SDK. Children classes can override this if they need to
* provide a custom "res" location for tests.
*/
protected String getResDir() {
return "res";
}
/**
* Defines the project level to set for the test project, or null to get the default language
* level associated with the test project.
*/
@Nullable
protected LanguageLevel getLanguageLevel() {
return null;
}
protected static AndroidXmlCodeStyleSettings getAndroidCodeStyleSettings() {
return AndroidXmlCodeStyleSettings.getInstance(CodeStyleSchemes.getInstance().getDefaultScheme().getCodeStyleSettings());
}
/**
* Hook point for child test classes to register directories that can be safely accessed by all
* of its tests.
*
* @see {@link VfsRootAccess}
*/
protected void collectAllowedRoots(List<String> roots) throws IOException {
}
private void registerAllowedRoots(List<String> roots, @NotNull Disposable disposable) {
List<String> newRoots = new ArrayList<>(roots);
newRoots.removeAll(myAllowedRoots);
String[] newRootsArray = ArrayUtil.toStringArray(newRoots);
VfsRootAccess.allowRootAccess(newRootsArray);
myAllowedRoots.addAll(newRoots);
Disposer.register(disposable, () -> {
VfsRootAccess.disallowRootAccess(newRootsArray);
myAllowedRoots.removeAll(newRoots);
});
}
public static AndroidFacet addAndroidFacet(Module module) {
return addAndroidFacet(module, true);
}
private static AndroidFacet addAndroidFacet(Module module, boolean attachSdk) {
FacetManager facetManager = FacetManager.getInstance(module);
AndroidFacet facet = facetManager.createFacet(AndroidFacet.getFacetType(), "Android", null);
if (attachSdk) {
addLatestAndroidSdk(module);
}
ModifiableFacetModel facetModel = facetManager.createModifiableModel();
facetModel.addFacet(facet);
ApplicationManager.getApplication().runWriteAction(facetModel::commit);
return facet;
}
protected void configureAdditionalModules(
@NotNull TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder, @NotNull List<MyAdditionalModuleData> modules) {
}
protected final void addModuleWithAndroidFacet(
@NotNull TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder,
@NotNull List<MyAdditionalModuleData> modules,
@NotNull String dirName,
int projectType) {
// By default, created module is declared as a main module's dependency
addModuleWithAndroidFacet(projectBuilder, modules, dirName, projectType, true);
}
protected final void addModuleWithAndroidFacet(
@NotNull TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder,
@NotNull List<MyAdditionalModuleData> modules,
@NotNull String dirName,
int projectType,
boolean isMainModuleDependency) {
JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class);
String moduleDirPath = myFixture.getTempDirPath() + getAdditionalModulePath(dirName);
//noinspection ResultOfMethodCallIgnored
new File(moduleDirPath).mkdirs();
initializeModuleFixtureBuilderWithSrcAndGen(moduleFixtureBuilder, moduleDirPath);
modules.add(new MyAdditionalModuleData(moduleFixtureBuilder, dirName, projectType, isMainModuleDependency));
}
protected void createManifest() throws IOException {
myFixture.copyFileToProject(SdkConstants.FN_ANDROID_MANIFEST_XML, SdkConstants.FN_ANDROID_MANIFEST_XML);
}
protected final void createProjectProperties() throws IOException {
myFixture.copyFileToProject(SdkConstants.FN_PROJECT_PROPERTIES, SdkConstants.FN_PROJECT_PROPERTIES);
}
protected final void deleteManifest() throws IOException {
deleteManifest(myModule);
}
protected final void deleteManifest(final Module module) throws IOException {
AndroidFacet facet = AndroidFacet.getInstance(module);
assertNotNull(facet);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
String manifestRelativePath = facet.getProperties().MANIFEST_FILE_RELATIVE_PATH;
VirtualFile manifest = AndroidRootUtil.getFileByRelativeModulePath(module, manifestRelativePath, true);
if (manifest != null) {
try {
manifest.delete(this);
}
catch (IOException e) {
fail("Could not delete default manifest");
}
}
}
});
}
protected final void doGlobalInspectionTest(
@NotNull GlobalInspectionTool inspection, @NotNull String globalTestDir, @NotNull AnalysisScope scope) {
doGlobalInspectionTest(new GlobalInspectionToolWrapper(inspection), globalTestDir, scope);
}
/**
* Given an inspection and a path to a directory that contains an "expected.xml" file, run the
* inspection on the current test project and verify that its output matches that of the
* expected file.
*/
protected final void doGlobalInspectionTest(
@NotNull GlobalInspectionToolWrapper wrapper, @NotNull String globalTestDir, @NotNull AnalysisScope scope) {
myFixture.enableInspections(wrapper.getTool());
scope.invalidate();
InspectionManagerEx inspectionManager = (InspectionManagerEx)InspectionManager.getInstance(getProject());
GlobalInspectionContextForTests globalContext =
CodeInsightTestFixtureImpl.createGlobalContextForTool(scope, getProject(), inspectionManager, wrapper);
InspectionTestUtil.runTool(wrapper, scope, globalContext);
InspectionTestUtil.compareToolResults(globalContext, wrapper, false, getTestDataPath() + globalTestDir);
}
protected static class MyAdditionalModuleData {
final JavaModuleFixtureBuilder myModuleFixtureBuilder;
final String myDirName;
final int myProjectType;
final boolean myIsMainModuleDependency;
private MyAdditionalModuleData(
@NotNull JavaModuleFixtureBuilder moduleFixtureBuilder, @NotNull String dirName, int projectType, boolean isMainModuleDependency) {
myModuleFixtureBuilder = moduleFixtureBuilder;
myDirName = dirName;
myProjectType = projectType;
myIsMainModuleDependency = isMainModuleDependency;
}
}
@NotNull
protected <T> T registerApplicationComponent(@NotNull Class<T> key, @NotNull T instance) throws Exception {
MutablePicoContainer picoContainer = (MutablePicoContainer)ApplicationManager.getApplication().getPicoContainer();
@SuppressWarnings("unchecked")
T old = (T)picoContainer.getComponentInstance(key.getName());
picoContainer.unregisterComponent(key.getName());
picoContainer.registerComponentInstance(key.getName(), instance);
return old;
}
@NotNull
protected <T> T registerProjectComponent(@NotNull Class<T> key, @NotNull T instance) {
MutablePicoContainer picoContainer = (MutablePicoContainer)getProject().getPicoContainer();
@SuppressWarnings("unchecked")
T old = (T)picoContainer.getComponentInstance(key.getName());
picoContainer.unregisterComponent(key.getName());
picoContainer.registerComponentInstance(key.getName(), instance);
return old;
}
}

View File

@@ -17,6 +17,7 @@ dependencies {
compile(project(":j2k"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-jps-common"))
compile(project(":usage-statistics"))
compile(project(":plugins:android-extensions-compiler"))
compile(project(":kotlin-scripting-compiler"))
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }

View File

@@ -6,12 +6,18 @@
package org.jetbrains.kotlin.git
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Couple
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vcs.FilePath
import git4idea.checkin.GitCheckinExplicitMovementProvider
import org.jetbrains.kotlin.idea.actions.pathBeforeJ2K
import java.util.*
class KotlinExplicitMovementProvider : GitCheckinExplicitMovementProvider() {
init {
Registry.get("git.explicit.commit.renames.prohibit.multiple.calls").setValue(false)
}
override fun isEnabled(project: Project): Boolean {
return true
}
@@ -36,11 +42,14 @@ class KotlinExplicitMovementProvider : GitCheckinExplicitMovementProvider() {
val before = beforePaths.firstOrNull { it.path == pathBeforeJ2K }
if (before != null) {
movedChanges.add(GitCheckinExplicitMovementProvider.Movement(before, after))
after.virtualFile?.pathBeforeJ2K = null
}
}
}
return movedChanges
}
override fun afterMovementsCommitted(project: Project, movedPaths: MutableList<Couple<FilePath>>) {
movedPaths.forEach { it.second.virtualFile?.pathBeforeJ2K = null }
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.git
import com.intellij.openapi.project.Project
import com.intellij.openapi.vcs.FilePath
import git4idea.checkin.GitCheckinExplicitMovementProvider
import org.jetbrains.kotlin.idea.actions.pathBeforeJ2K
import java.util.*
class KotlinExplicitMovementProvider : GitCheckinExplicitMovementProvider() {
override fun isEnabled(project: Project): Boolean {
return true
}
override fun getDescription(): String {
return "Extra commit for .java > .kt renames"
}
override fun getCommitMessage(oldCommitMessage: String): String {
return "Rename .java to .kt"
}
override fun collectExplicitMovements(
project: Project,
beforePaths: List<FilePath>,
afterPaths: List<FilePath>
): Collection<GitCheckinExplicitMovementProvider.Movement> {
val movedChanges = ArrayList<GitCheckinExplicitMovementProvider.Movement>()
for (after in afterPaths) {
val pathBeforeJ2K = after.virtualFile?.pathBeforeJ2K
if (pathBeforeJ2K != null) {
val before = beforePaths.firstOrNull { it.path == pathBeforeJ2K }
if (before != null) {
movedChanges.add(GitCheckinExplicitMovementProvider.Movement(before, after))
after.virtualFile?.pathBeforeJ2K = null
}
}
}
return movedChanges
}
}

View File

@@ -14,16 +14,16 @@ import org.jdom.Element
// Generalized in 183
// BUNCH: 183
typealias RunConfigurationBaseAny = RunConfigurationBase
typealias RunConfigurationBaseAny = RunConfigurationBase<*>
// Generalized in 183
// BUNCH: 183
typealias ModuleBasedConfigurationAny = ModuleBasedConfiguration<*>
typealias ModuleBasedConfigurationAny = ModuleBasedConfiguration<*, *>
// Generalized in 183
// BUNCH: 183
typealias LocatableConfigurationBaseAny = LocatableConfigurationBase
typealias LocatableConfigurationBaseAny = LocatableConfigurationBase<Any>
// Generalized in 183
// BUNCH: 183
typealias ModuleBasedConfigurationElement<T> = ModuleBasedConfiguration<T>
typealias ModuleBasedConfigurationElement<T> = ModuleBasedConfiguration<T, Element>

View File

@@ -0,0 +1,29 @@
/*
* 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.
*/
@file:Suppress("IncompatibleAPI")
package org.jetbrains.kotlin.idea.run
import com.intellij.execution.configurations.LocatableConfigurationBase
import com.intellij.execution.configurations.ModuleBasedConfiguration
import com.intellij.execution.configurations.RunConfigurationBase
import org.jdom.Element
// Generalized in 183
// BUNCH: 183
typealias RunConfigurationBaseAny = RunConfigurationBase
// Generalized in 183
// BUNCH: 183
typealias ModuleBasedConfigurationAny = ModuleBasedConfiguration<*>
// Generalized in 183
// BUNCH: 183
typealias LocatableConfigurationBaseAny = LocatableConfigurationBase
// Generalized in 183
// BUNCH: 183
typealias ModuleBasedConfigurationElement<T> = ModuleBasedConfiguration<T>

View File

@@ -46,7 +46,6 @@ import org.jetbrains.idea.maven.execution.*;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenExplicitProfiles;
import org.jetbrains.idea.maven.project.*;
import org.jetbrains.idea.maven.server.MavenServerManager;
import org.jetbrains.jps.model.java.JavaResourceRootType;
import org.jetbrains.jps.model.java.JavaSourceRootProperties;
import org.jetbrains.jps.model.java.JavaSourceRootType;
@@ -389,32 +388,14 @@ public abstract class MavenImportingTestCase extends MavenTestCase {
}
protected void importProjectWithProfiles(String... profiles) {
doImportProjects(true, Collections.singletonList(myProjectPom), profiles);
}
protected void importProject(VirtualFile file) {
importProjects(file);
doImportProjects(Collections.singletonList(myProjectPom), profiles);
}
protected void importProjects(VirtualFile... files) {
doImportProjects(true, Arrays.asList(files));
doImportProjects(Arrays.asList(files));
}
protected void importProjectWithMaven3(@NonNls String xml) throws IOException {
createProjectPom(xml);
importProjectWithMaven3();
}
protected void importProjectWithMaven3() {
importProjectWithMaven3WithProfiles();
}
protected void importProjectWithMaven3WithProfiles(String... profiles) {
doImportProjects(false, Collections.singletonList(myProjectPom), profiles);
}
private void doImportProjects(boolean useMaven2, final List<VirtualFile> files, String... profiles) {
MavenServerManager.getInstance().setUseMaven2(useMaven2);
private void doImportProjects(List<VirtualFile> files, String... profiles) {
initProjectsManager(false);
readProjects(files, profiles);

View File

@@ -0,0 +1,591 @@
/*
* 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.maven;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TestDialog;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.util.Consumer;
import com.intellij.util.PathUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.execution.*;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenExplicitProfiles;
import org.jetbrains.idea.maven.project.*;
import org.jetbrains.idea.maven.server.MavenServerManager;
import org.jetbrains.jps.model.java.JavaResourceRootType;
import org.jetbrains.jps.model.java.JavaSourceRootProperties;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class MavenImportingTestCase extends MavenTestCase {
protected MavenProjectsTree myProjectsTree;
protected MavenProjectsManager myProjectsManager;
private File myGlobalSettingsFile;
@Override
protected void setUp() throws Exception {
VfsRootAccess.allowRootAccess(PathManager.getConfigPath());
super.setUp();
myGlobalSettingsFile =
MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().generalSettings.getEffectiveGlobalSettingsIoFile();
if (myGlobalSettingsFile != null) {
VfsRootAccess.allowRootAccess(myGlobalSettingsFile.getAbsolutePath());
}
}
@Override
protected void setUpInWriteAction() throws Exception {
super.setUpInWriteAction();
myProjectsManager = MavenProjectsManager.getInstance(myProject);
removeFromLocalRepository("test");
}
@Override
protected void tearDown() throws Exception {
try {
if (myGlobalSettingsFile != null) {
VfsRootAccess.disallowRootAccess(myGlobalSettingsFile.getAbsolutePath());
}
VfsRootAccess.disallowRootAccess(PathManager.getConfigPath());
Messages.setTestDialog(TestDialog.DEFAULT);
removeFromLocalRepository("test");
FileUtil.delete(BuildManager.getInstance().getBuildSystemDirectory().toFile());
}
finally {
super.tearDown();
}
}
protected void assertModules(String... expectedNames) {
Module[] actual = ModuleManager.getInstance(myProject).getModules();
List<String> actualNames = new ArrayList<String>();
for (Module m : actual) {
actualNames.add(m.getName());
}
assertUnorderedElementsAreEqual(actualNames, expectedNames);
}
protected void assertContentRoots(String moduleName, String... expectedRoots) {
List<String> actual = new ArrayList<String>();
for (ContentEntry e : getContentRoots(moduleName)) {
actual.add(e.getUrl());
}
for (int i = 0; i < expectedRoots.length; i++) {
expectedRoots[i] = VfsUtil.pathToUrl(expectedRoots[i]);
}
assertUnorderedPathsAreEqual(actual, Arrays.asList(expectedRoots));
}
protected void assertSources(String moduleName, String... expectedSources) {
assertContentFolders(moduleName, JavaSourceRootType.SOURCE, expectedSources);
}
protected void assertGeneratedSources(String moduleName, String... expectedSources) {
ContentEntry contentRoot = getContentRoot(moduleName);
List<ContentFolder> folders = new ArrayList<ContentFolder>();
for (SourceFolder folder : contentRoot.getSourceFolders(JavaSourceRootType.SOURCE)) {
JavaSourceRootProperties properties = folder.getJpsElement().getProperties(JavaSourceRootType.SOURCE);
assertNotNull(properties);
if (properties.isForGeneratedSources()) {
folders.add(folder);
}
}
doAssertContentFolders(contentRoot, folders, expectedSources);
}
protected void assertResources(String moduleName, String... expectedSources) {
assertContentFolders(moduleName, JavaResourceRootType.RESOURCE, expectedSources);
}
protected void assertTestSources(String moduleName, String... expectedSources) {
assertContentFolders(moduleName, JavaSourceRootType.TEST_SOURCE, expectedSources);
}
protected void assertTestResources(String moduleName, String... expectedSources) {
assertContentFolders(moduleName, JavaResourceRootType.TEST_RESOURCE, expectedSources);
}
protected void assertExcludes(String moduleName, String... expectedExcludes) {
ContentEntry contentRoot = getContentRoot(moduleName);
doAssertContentFolders(contentRoot, Arrays.asList(contentRoot.getExcludeFolders()), expectedExcludes);
}
protected void assertContentRootExcludes(String moduleName, String contentRoot, String... expectedExcudes) {
ContentEntry root = getContentRoot(moduleName, contentRoot);
doAssertContentFolders(root, Arrays.asList(root.getExcludeFolders()), expectedExcudes);
}
protected void assertContentFolders(String moduleName, @NotNull JpsModuleSourceRootType<?> rootType, String... expected) {
ContentEntry contentRoot = getContentRoot(moduleName);
doAssertContentFolders(contentRoot, contentRoot.getSourceFolders(rootType), expected);
}
private static void doAssertContentFolders(ContentEntry e, final List<? extends ContentFolder> folders, String... expected) {
List<String> actual = new ArrayList<String>();
for (ContentFolder f : folders) {
String rootUrl = e.getUrl();
String folderUrl = f.getUrl();
if (folderUrl.startsWith(rootUrl)) {
int length = rootUrl.length() + 1;
folderUrl = folderUrl.substring(Math.min(length, folderUrl.length()));
}
actual.add(folderUrl);
}
assertOrderedElementsAreEqual(actual, Arrays.asList(expected));
}
protected void assertModuleOutput(String moduleName, String output, String testOutput) {
CompilerModuleExtension e = getCompilerExtension(moduleName);
assertFalse(e.isCompilerOutputPathInherited());
assertEquals(output, getAbsolutePath(e.getCompilerOutputUrl()));
assertEquals(testOutput, getAbsolutePath(e.getCompilerOutputUrlForTests()));
}
private static String getAbsolutePath(String path) {
path = VfsUtil.urlToPath(path);
path = PathUtil.getCanonicalPath(path);
return FileUtil.toSystemIndependentName(path);
}
protected void assertProjectOutput(String module) {
assertTrue(getCompilerExtension(module).isCompilerOutputPathInherited());
}
protected CompilerModuleExtension getCompilerExtension(String module) {
ModuleRootManager m = getRootManager(module);
return CompilerModuleExtension.getInstance(m.getModule());
}
protected void assertModuleLibDep(String moduleName, String depName) {
assertModuleLibDep(moduleName, depName, null);
}
protected void assertModuleLibDep(String moduleName, String depName, String classesPath) {
assertModuleLibDep(moduleName, depName, classesPath, null, null);
}
protected void assertModuleLibDep(String moduleName, String depName, String classesPath, String sourcePath, String javadocPath) {
LibraryOrderEntry lib = getModuleLibDep(moduleName, depName);
assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPath == null ? null : Collections.singletonList(classesPath));
assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePath == null ? null : Collections.singletonList(sourcePath));
assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(),
javadocPath == null ? null : Collections.singletonList(javadocPath));
}
protected void assertModuleLibDep(
String moduleName,
String depName,
List<String> classesPaths,
List<String> sourcePaths,
List<String> javadocPaths
) {
LibraryOrderEntry lib = getModuleLibDep(moduleName, depName);
assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPaths);
assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePaths);
assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), javadocPaths);
}
private static void assertModuleLibDepPath(LibraryOrderEntry lib, OrderRootType type, List<String> paths) {
if (paths == null) return;
assertUnorderedPathsAreEqual(Arrays.asList(lib.getRootUrls(type)), paths);
// also check the library because it may contain slight different set of urls (e.g. with duplicates)
assertUnorderedPathsAreEqual(Arrays.asList(lib.getLibrary().getUrls(type)), paths);
}
protected void assertModuleLibDepScope(String moduleName, String depName, DependencyScope scope) {
LibraryOrderEntry dep = getModuleLibDep(moduleName, depName);
assertEquals(scope, dep.getScope());
}
private LibraryOrderEntry getModuleLibDep(String moduleName, String depName) {
return getModuleDep(moduleName, depName, LibraryOrderEntry.class);
}
protected void assertModuleLibDeps(String moduleName, String... expectedDeps) {
assertModuleDeps(moduleName, LibraryOrderEntry.class, expectedDeps);
}
protected void assertExportedDeps(String moduleName, String... expectedDeps) {
final List<String> actual = new ArrayList<String>();
getRootManager(moduleName).orderEntries().withoutSdk().withoutModuleSourceEntries().exportedOnly()
.process(new RootPolicy<Object>() {
@Override
public Object visitModuleOrderEntry(ModuleOrderEntry e, Object value) {
actual.add(e.getModuleName());
return null;
}
@Override
public Object visitLibraryOrderEntry(LibraryOrderEntry e, Object value) {
actual.add(e.getLibraryName());
return null;
}
}, null);
assertOrderedElementsAreEqual(actual, expectedDeps);
}
protected void assertModuleModuleDeps(String moduleName, String... expectedDeps) {
assertModuleDeps(moduleName, ModuleOrderEntry.class, expectedDeps);
}
private void assertModuleDeps(String moduleName, Class clazz, String... expectedDeps) {
assertOrderedElementsAreEqual(collectModuleDepsNames(moduleName, clazz), expectedDeps);
}
protected void assertModuleModuleDepScope(String moduleName, String depName, DependencyScope scope) {
ModuleOrderEntry dep = getModuleModuleDep(moduleName, depName);
assertEquals(scope, dep.getScope());
}
private ModuleOrderEntry getModuleModuleDep(String moduleName, String depName) {
return getModuleDep(moduleName, depName, ModuleOrderEntry.class);
}
private List<String> collectModuleDepsNames(String moduleName, Class clazz) {
List<String> actual = new ArrayList<String>();
for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) {
if (clazz.isInstance(e)) {
actual.add(e.getPresentableName());
}
}
return actual;
}
private <T> T getModuleDep(String moduleName, String depName, Class<T> clazz) {
T dep = null;
for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) {
if (clazz.isInstance(e) && e.getPresentableName().equals(depName)) {
dep = (T) e;
}
}
assertNotNull("Dependency not found: " + depName
+ "\namong: " + collectModuleDepsNames(moduleName, clazz),
dep);
return dep;
}
public void assertProjectLibraries(String... expectedNames) {
List<String> actualNames = new ArrayList<String>();
for (Library each : ProjectLibraryTable.getInstance(myProject).getLibraries()) {
String name = each.getName();
actualNames.add(name == null ? "<unnamed>" : name);
}
assertUnorderedElementsAreEqual(actualNames, expectedNames);
}
protected void assertModuleGroupPath(String moduleName, String... expected) {
String[] path = ModuleManager.getInstance(myProject).getModuleGroupPath(getModule(moduleName));
if (expected.length == 0) {
assertNull(path);
}
else {
assertNotNull(path);
assertOrderedElementsAreEqual(Arrays.asList(path), expected);
}
}
protected Module getModule(final String name) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
assertNotNull("Module " + name + " not found", m);
return m;
}
finally {
accessToken.finish();
}
}
private ContentEntry getContentRoot(String moduleName) {
ContentEntry[] ee = getContentRoots(moduleName);
List<String> roots = new ArrayList<String>();
for (ContentEntry e : ee) {
roots.add(e.getUrl());
}
String message = "Several content roots found: [" + StringUtil.join(roots, ", ") + "]";
assertEquals(message, 1, ee.length);
return ee[0];
}
private ContentEntry getContentRoot(String moduleName, String path) {
for (ContentEntry e : getContentRoots(moduleName)) {
if (e.getUrl().equals(VfsUtil.pathToUrl(path))) return e;
}
throw new AssertionError("content root not found");
}
public ContentEntry[] getContentRoots(String moduleName) {
return getRootManager(moduleName).getContentEntries();
}
private ModuleRootManager getRootManager(String module) {
return ModuleRootManager.getInstance(getModule(module));
}
protected void importProject(@NonNls String xml) throws IOException {
createProjectPom(xml);
importProject();
}
protected void importProject() {
importProjectWithProfiles();
}
protected void importProjectWithProfiles(String... profiles) {
doImportProjects(true, Collections.singletonList(myProjectPom), profiles);
}
protected void importProject(VirtualFile file) {
importProjects(file);
}
protected void importProjects(VirtualFile... files) {
doImportProjects(true, Arrays.asList(files));
}
protected void importProjectWithMaven3(@NonNls String xml) throws IOException {
createProjectPom(xml);
importProjectWithMaven3();
}
protected void importProjectWithMaven3() {
importProjectWithMaven3WithProfiles();
}
protected void importProjectWithMaven3WithProfiles(String... profiles) {
doImportProjects(false, Collections.singletonList(myProjectPom), profiles);
}
private void doImportProjects(boolean useMaven2, final List<VirtualFile> files, String... profiles) {
MavenServerManager.getInstance().setUseMaven2(useMaven2);
initProjectsManager(false);
readProjects(files, profiles);
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
myProjectsManager.waitForResolvingCompletion();
myProjectsManager.scheduleImportInTests(files);
myProjectsManager.importProjects();
}
});
for (MavenProject each : myProjectsTree.getProjects()) {
if (each.hasReadingProblems()) {
System.out.println(each + " has problems: " + each.getProblems());
}
}
}
protected void readProjects(List<VirtualFile> files, String... profiles) {
myProjectsManager.resetManagedFilesAndProfilesInTests(files, new MavenExplicitProfiles(Arrays.asList(profiles)));
waitForReadingCompletion();
}
protected void updateProjectsAndImport(VirtualFile... files) {
readProjects(files);
myProjectsManager.performScheduledImportInTests();
}
protected void initProjectsManager(boolean enableEventHandling) {
myProjectsManager.initForTests();
myProjectsTree = myProjectsManager.getProjectsTreeForTests();
if (enableEventHandling) myProjectsManager.listenForExternalChanges();
}
protected void scheduleResolveAll() {
myProjectsManager.scheduleResolveAllInTests();
}
protected void waitForReadingCompletion() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
try {
myProjectsManager.waitForReadingCompletion();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
protected void readProjects() {
readProjects(myProjectsManager.getProjectsFiles());
}
protected void readProjects(VirtualFile... files) {
List<MavenProject> projects = new ArrayList<MavenProject>();
for (VirtualFile each : files) {
projects.add(myProjectsManager.findProject(each));
}
myProjectsManager.forceUpdateProjects(projects);
waitForReadingCompletion();
}
protected void resolveDependenciesAndImport() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
myProjectsManager.waitForResolvingCompletion();
myProjectsManager.performScheduledImportInTests();
}
});
}
protected void resolveFoldersAndImport() {
myProjectsManager.scheduleFoldersResolveForAllProjects();
myProjectsManager.waitForFoldersResolvingCompletion();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
myProjectsManager.performScheduledImportInTests();
}
});
}
protected void resolvePlugins() {
myProjectsManager.waitForPluginsResolvingCompletion();
}
protected void downloadArtifacts() {
downloadArtifacts(myProjectsManager.getProjects(), null);
}
protected MavenArtifactDownloader.DownloadResult downloadArtifacts(
Collection<MavenProject> projects,
List<MavenArtifact> artifacts
) {
final MavenArtifactDownloader.DownloadResult[] unresolved = new MavenArtifactDownloader.DownloadResult[1];
AsyncResult<MavenArtifactDownloader.DownloadResult> result = new AsyncResult<MavenArtifactDownloader.DownloadResult>();
result.doWhenDone(new Consumer<MavenArtifactDownloader.DownloadResult>() {
@Override
public void consume(MavenArtifactDownloader.DownloadResult unresolvedArtifacts) {
unresolved[0] = unresolvedArtifacts;
}
});
myProjectsManager.scheduleArtifactsDownloading(projects, artifacts, true, true, result);
myProjectsManager.waitForArtifactsDownloadingCompletion();
return unresolved[0];
}
protected void performPostImportTasks() {
myProjectsManager.waitForPostImportTasksCompletion();
}
protected void executeGoal(String relativePath, String goal) {
VirtualFile dir = myProjectRoot.findFileByRelativePath(relativePath);
MavenRunnerParameters rp = new MavenRunnerParameters(true, dir.getPath(), Arrays.asList(goal), Collections.<String>emptyList());
MavenRunnerSettings rs = new MavenRunnerSettings();
MavenExecutor e = new MavenExternalExecutor(myProject, rp, getMavenGeneralSettings(), rs, new SoutMavenConsole());
e.execute(new EmptyProgressIndicator());
}
protected void removeFromLocalRepository(String relativePath) throws IOException {
FileUtil.delete(new File(getRepositoryPath(), relativePath));
}
protected void setupJdkForModules(String... moduleNames) {
for (String each : moduleNames) {
setupJdkForModule(each);
}
}
protected Sdk setupJdkForModule(final String moduleName) {
final Sdk sdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk);
return sdk;
}
protected static Sdk createJdk(String versionName) {
return IdeaTestUtil.getMockJdk17(versionName);
}
protected static AtomicInteger configConfirmationForYesAnswer() {
final AtomicInteger counter = new AtomicInteger();
Messages.setTestDialog(new TestDialog() {
@Override
public int show(String message) {
counter.set(counter.get() + 1);
return 0;
}
});
return counter;
}
protected static AtomicInteger configConfirmationForNoAnswer() {
final AtomicInteger counter = new AtomicInteger();
Messages.setTestDialog(new TestDialog() {
@Override
public int show(String message) {
counter.set(counter.get() + 1);
return 1;
}
});
return counter;
}
}

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.perf
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.toLightClass
@@ -64,4 +65,9 @@ class WholeProjectLightClassTest : WholeProjectPerformanceTest(), WholeProjectKo
return PerFileTestResult(results, totalNs, errors)
}
fun testUltraLightPerformance() {
Registry.get("kotlin.use.ultra.light.classes").setValue(true, testRootDisposable)
testWholeProjectPerformance()
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.perf
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtVisitorVoid
import java.util.*
import kotlin.system.measureNanoTime
class WholeProjectLightClassTest : WholeProjectPerformanceTest(), WholeProjectKotlinFileProvider {
override fun doTest(file: VirtualFile): PerFileTestResult {
val results = mutableMapOf<String, Long>()
var totalNs = 0L
val psiFile = file.toPsiFile(project) ?: run {
return WholeProjectPerformanceTest.PerFileTestResult(results, totalNs, listOf(AssertionError("PsiFile not found for $file")))
}
val errors = mutableListOf<Throwable>()
fun buildAllLightClasses(name: String, predicate: (KtClassOrObject) -> Boolean) {
val result = measureNanoTime {
try {
// Build light class by PsiFile
psiFile.acceptRecursively(object : KtVisitorVoid() {
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
if (!predicate(classOrObject)) return
val lightClass = classOrObject.toLightClass() as? KtLightClassForSourceDeclaration ?: return
Arrays.hashCode(lightClass.superTypes)
Arrays.hashCode(lightClass.fields)
Arrays.hashCode(lightClass.methods)
// Just to be sure: access types
lightClass.fields.map { it.type }.hashCode()
lightClass.methods.map { it.returnType }.hashCode()
lightClass.hashCode()
}
})
} catch (t: Throwable) {
t.printStackTrace()
errors += t
}
}
results[name] = result
totalNs += result
}
buildAllLightClasses("LightClasses_Top") {
it.containingDeclarationForPseudocode == null
}
buildAllLightClasses("LightClasses_Members") {
!it.isLocal && it.containingDeclarationForPseudocode is KtClassOrObject
}
return PerFileTestResult(results, totalNs, errors)
}
}

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="182.4323.46" until-build="182.*"/>
<idea-version since-build="183.1" until-build="191.*"/>
<depends>com.intellij.modules.platform</depends>
@@ -55,13 +55,6 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<xi:include href="kotlinx-serialization.xml" xpointer="xpointer(/idea-plugin/*)"/>
<project-components>
<component>
<!-- This is a workaround for IDEA < 183. For details, see IDEA-200525. -->
<implementation-class>org.jetbrains.kotlin.idea.caches.ProjectRootModificationTrackerFixer</implementation-class>
</component>
</project-components>
<extensionPoints>
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
@@ -74,4 +67,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<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

@@ -0,0 +1,77 @@
<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="182.4323.46" until-build="182.*"/>
<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/*)"/>
<project-components>
<component>
<!-- This is a workaround for IDEA < 183. For details, see IDEA-200525. -->
<implementation-class>org.jetbrains.kotlin.idea.caches.ProjectRootModificationTrackerFixer</implementation-class>
</component>
</project-components>
<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>
</idea-plugin>

View File

@@ -0,0 +1,73 @@
/*
* 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.inspections.blockingCallsDetection
import com.intellij.codeInspection.blockingCallsDetection.NonBlockingContextChecker
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class CoroutineNonBlockingContextChecker : NonBlockingContextChecker {
override fun isApplicable(file: PsiFile): Boolean {
val languageVersionSettings = file.project.getLanguageVersionSettings()
return languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
}
override fun isContextNonBlockingFor(element: PsiElement): Boolean {
if (element !is KtCallExpression)
return false
val containingLambda = element.parents
.firstOrNull { it is KtLambdaExpression && it.analyze().get(BindingContext.LAMBDA_INVOCATIONS, it) == null }
val containingArgument = PsiTreeUtil.getParentOfType(containingLambda, KtValueArgument::class.java)
if (containingArgument != null) {
val callExpression = PsiTreeUtil.getParentOfType(containingArgument, KtCallExpression::class.java) ?: return false
val call = callExpression.resolveToCall(BodyResolveMode.PARTIAL) ?: return false
val hasBlockingAnnotation = call.getFirstArgument()?.resolveToCall()
?.resultingDescriptor?.annotations?.hasAnnotation(FqName(BLOCKING_CONTEXT_ANNOTATION))
if (hasBlockingAnnotation == true)
return false
val parameterForArgument = call.getParameterForArgument(containingArgument) ?: return false
val type = parameterForArgument.returnType ?: return false
val hasRestrictSuspensionAnnotation = if (type.isBuiltinFunctionalType) {
type.getReceiverTypeFromFunctionType()?.isRestrictsSuspensionReceiver(element.project.getLanguageVersionSettings())
} else null
return hasRestrictSuspensionAnnotation != true && type.isSuspendFunctionType
}
val callingMethod = PsiTreeUtil.getParentOfType(element, KtNamedFunction::class.java) ?: return false
return callingMethod.hasModifier(KtTokens.SUSPEND_KEYWORD)
}
private fun ResolvedCall<*>.getFirstArgument(): KtExpression? =
valueArgumentsByIndex?.firstOrNull()?.arguments?.firstOrNull()?.getArgumentExpression()
companion object {
private const val BLOCKING_CONTEXT_ANNOTATION = "org.jetbrains.annotations.BlockingContext"
}
}

View File

@@ -17,11 +17,13 @@
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.FileModificationService
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.statistics.KotlinIdeQuickfixTrigger
abstract class KotlinQuickFixAction<out T : PsiElement>(element: T) : QuickFixActionBase<T>(element) {
protected open fun isAvailable(project: Project, editor: Editor?, file: KtFile) = true
@@ -34,6 +36,10 @@ abstract class KotlinQuickFixAction<out T : PsiElement>(element: T) : QuickFixAc
final override fun invoke(project: Project, editor: Editor?, file: PsiFile) {
val element = element ?: return
if (file is KtFile && FileModificationService.getInstance().prepareFileForWrite(element.containingFile)) {
FUSApplicationUsageTrigger.getInstance().trigger(
KotlinIdeQuickfixTrigger::class.java,
this::class.java.simpleName
)
invoke(project, editor, file)
}
}

View File

@@ -20,9 +20,11 @@ import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.statistics.KotlinIdeQuickfixTrigger
open class QuickFixWithDelegateFactory(
private val delegateFactory: () -> IntentionAction?
@@ -54,6 +56,11 @@ open class QuickFixWithDelegateFactory(
return
}
FUSApplicationUsageTrigger.getInstance().trigger(
KotlinIdeQuickfixTrigger::class.java,
this::class.java.simpleName
)
val action = delegateFactory() ?: return
assert(action.detectPriority() == this.detectPriority()) {

View File

@@ -0,0 +1,100 @@
/*
* 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.quickfix.crossLanguage
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtil
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.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.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
) : 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 shortenParameterString = StringUtil.shortenTextWithEllipsis(parametersString, 30, 5)
return QuickFixBundle.message("change.method.parameters.text", shortenParameterString)
}
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 invoke(project: Project, editor: Editor?, file: KtFile) {
val target = element ?: return
val functionDescriptor = target.resolveToDescriptorIfAny(BodyResolveMode.FULL) ?: return
val newFunctionDescriptor = SimpleFunctionDescriptorImpl.create(
functionDescriptor.containingDeclaration,
functionDescriptor.annotations,
functionDescriptor.name,
functionDescriptor.kind,
SourceElement.NO_SOURCE
).apply {
initialize(
functionDescriptor.extensionReceiverParameter?.copy(this),
functionDescriptor.dispatchReceiverParameter,
functionDescriptor.typeParameters,
request.withIndex().map { (index, parameter) ->
ValueParameterDescriptorImpl(
this, null, index, Annotations.EMPTY,
Name.identifier(parameter.first.toString()),
parameter.second, false,
false, false, null, SourceElement.NO_SOURCE
)
},
functionDescriptor.returnType,
functionDescriptor.modality,
functionDescriptor.visibility
)
}
val renderer = IdeDescriptorRenderers.SOURCE_CODE.withOptions {
defaultParameterValueRenderer = null
}
val newFunction = KtPsiFactory(project).createFunction(renderer.render(newFunctionDescriptor)).apply {
valueParameters.forEach { param ->
param.annotationEntries.forEach { a ->
a.typeReference?.run {
val fqName = FqName(this.text)
if (fqName in (NULLABLE_ANNOTATIONS + NOT_NULL_ANNOTATIONS)) a.delete()
}
}
}
}
val newParameterList = target.valueParameterList!!.replace(newFunction.valueParameterList!!) as KtParameterList
ShortenReferences.DEFAULT.process(newParameterList)
}
}

View File

@@ -19,11 +19,9 @@ package org.jetbrains.kotlin.idea.quickfix.crossLanguage
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.lang.java.beans.PropertyKind
import com.intellij.lang.jvm.JvmClass
import com.intellij.lang.jvm.JvmElement
import com.intellij.lang.jvm.JvmModifier
import com.intellij.lang.jvm.JvmModifiersOwner
import com.intellij.lang.jvm.*
import com.intellij.lang.jvm.actions.*
import com.intellij.lang.jvm.types.JvmType
import com.intellij.openapi.editor.Editor
@@ -75,6 +73,7 @@ import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.statistics.KotlinIdeIntentionTrigger
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
@@ -147,7 +146,7 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
}
class CreatePropertyFix(
contextElement: KtElement,
contextElement: KtElement,
propertyInfo: PropertyInfo,
private val classOrFileName: String?
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
@@ -350,16 +349,17 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
val ktType = (propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val propertyInfo = PropertyInfo(
propertyName,
TypeInfo.Empty,
TypeInfo(ktType, Variance.INVARIANT),
TypeInfo.Empty,
TypeInfo(ktType, Variance.INVARIANT),
setterRequired,
listOf(targetContainer),
modifierList = modifierBuilder.modifierList,
withInitializer = true
listOf(targetContainer),
modifierList = modifierBuilder.modifierList,
withInitializer = true
)
val propertyInfos = if (setterRequired) {
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
} else {
}
else {
listOf(propertyInfo)
}
return propertyInfos.map { CreatePropertyFix(targetContainer, it, classOrFileName) }
@@ -426,7 +426,6 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
preferEmptyBody = true
)
val targetClassName = targetClass.name
val action = object : CreateCallableFromUsageFix<KtElement>(targetContainer, listOf(functionInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add method '$methodName' to '$targetClassName'"
@@ -473,6 +472,11 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
FUSApplicationUsageTrigger.getInstance().trigger(
KotlinIdeIntentionTrigger::class.java,
this::class.java.simpleName
)
val target = pointer.element ?: return
val kotlinAnnotation = JavaPsiFacade.getInstance(project).findClass(
request.qualifiedName,
@@ -503,6 +507,21 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
}
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 }))
}
}
private fun JvmPsiConversionHelper.asPsiType(param: Pair<SuggestedNameInfo, List<ExpectedType>>): PsiType? =

View File

@@ -0,0 +1,509 @@
/*
* 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.quickfix.crossLanguage
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.lang.java.beans.PropertyKind
import com.intellij.lang.jvm.JvmClass
import com.intellij.lang.jvm.JvmElement
import com.intellij.lang.jvm.JvmModifier
import com.intellij.lang.jvm.JvmModifiersOwner
import com.intellij.lang.jvm.actions.*
import com.intellij.lang.jvm.types.JvmType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtilRt
import com.intellij.psi.*
import com.intellij.psi.codeStyle.SuggestedNameInfo
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
import com.intellij.psi.util.PropertyUtilBase
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.appendModifier
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateCallableFromUsageFix
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.approximateFlexibleTypes
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
import org.jetbrains.kotlin.load.java.lazy.child
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeAttributes
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.supertypes
class KotlinElementActionsFactory : JvmElementActionsFactory() {
companion object {
val javaPsiModifiersMapping = mapOf(
JvmModifier.PRIVATE to KtTokens.PRIVATE_KEYWORD,
JvmModifier.PUBLIC to KtTokens.PUBLIC_KEYWORD,
JvmModifier.PROTECTED to KtTokens.PUBLIC_KEYWORD,
JvmModifier.ABSTRACT to KtTokens.ABSTRACT_KEYWORD
)
}
private class FakeExpressionFromParameter(private val psiParam: PsiParameter) : PsiReferenceExpressionImpl() {
override fun getText(): String = psiParam.name!!
override fun getProject(): Project = psiParam.project
override fun getParent(): PsiElement = psiParam.parent
override fun getType(): PsiType? = psiParam.type
override fun isValid(): Boolean = true
override fun getContainingFile(): PsiFile = psiParam.containingFile
override fun getReferenceName(): String? = psiParam.name
override fun resolve(): PsiElement? = psiParam
}
private class ModifierBuilder(
private val targetContainer: KtElement,
private val allowJvmStatic: Boolean = true
) {
private val psiFactory = KtPsiFactory(targetContainer.project)
val modifierList = psiFactory.createEmptyModifierList()
private fun JvmModifier.transformAndAppend(): Boolean {
javaPsiModifiersMapping[this]?.let {
modifierList.appendModifier(it)
return true
}
when (this) {
JvmModifier.STATIC -> {
if (allowJvmStatic && targetContainer is KtClassOrObject) {
addAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME)
}
}
JvmModifier.ABSTRACT -> modifierList.appendModifier(KtTokens.ABSTRACT_KEYWORD)
JvmModifier.FINAL -> modifierList.appendModifier(KtTokens.FINAL_KEYWORD)
else -> return false
}
return true
}
var isValid = true
private set
fun addJvmModifier(modifier: JvmModifier) {
isValid = isValid && modifier.transformAndAppend()
}
fun addJvmModifiers(modifiers: Iterable<JvmModifier>) {
modifiers.forEach { addJvmModifier(it) }
}
fun addAnnotation(fqName: FqName) {
if (!isValid) return
modifierList.add(psiFactory.createAnnotationEntry("@${fqName.asString()}"))
}
}
class CreatePropertyFix(
contextElement: KtElement,
propertyInfo: PropertyInfo,
private val classOrFileName: String?
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
override fun getFamilyName() = "Add property"
override fun getText(): String {
val info = callableInfos.first() as PropertyInfo
return buildString {
append("Add '")
if (info.isLateinitPreferred || info.modifierList?.hasModifier(KtTokens.LATEINIT_KEYWORD) == true) {
append("lateinit ")
}
append(if (info.writable) "var" else "val")
append("' property '${info.name}' to '$classOrFileName'")
}
}
}
private fun JvmClass.toKtClassOrFile(): KtElement? {
val psi = sourceElement
return when (psi) {
is KtClassOrObject -> psi
is KtLightClassForSourceDeclaration -> psi.kotlinOrigin
is KtLightClassForFacade -> psi.files.firstOrNull()
else -> null
}
}
private inline fun <reified T : KtElement> JvmElement.toKtElement() = sourceElement?.unwrapped as? T
private fun fakeParametersExpressions(parameters: List<Pair<SuggestedNameInfo, List<ExpectedType>>>, project: Project): Array<PsiExpression>? =
when {
parameters.isEmpty() -> emptyArray()
else -> JavaPsiFacade
.getElementFactory(project)
.createParameterList(
parameters.map { it.first.names.firstOrNull() }.toTypedArray(),
parameters.map { JvmPsiConversionHelper.getInstance(project).asPsiType(it) ?: return null }.toTypedArray()
)
.parameters
.map(::FakeExpressionFromParameter)
.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>()) {
val ktType = (it.theType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: return@flatMapTo emptyList()
when (it.theKind) {
ExpectedType.Kind.EXACT, ExpectedType.Kind.SUBTYPE -> listOf(ktType)
ExpectedType.Kind.SUPERTYPE -> listOf(ktType) + ktType.supertypes()
}
}
if (candidateTypes.isEmpty()) {
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
return TypeInfo(nullableAnyType, Variance.INVARIANT)
}
return TypeInfo.ByExplicitCandidateTypes(candidateTypes.toList())
}
override fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List<IntentionAction> {
val kModifierOwner = target.toKtElement<KtModifierListOwner>() ?: return emptyList()
val modifier = request.modifier
val shouldPresent = request.shouldPresent
//TODO: make similar to `createAddMethodActions`
val (kToken, shouldPresentMapped) = when {
modifier == JvmModifier.FINAL -> KtTokens.OPEN_KEYWORD to !shouldPresent
modifier == JvmModifier.PUBLIC && shouldPresent ->
kModifierOwner.visibilityModifierType()
?.takeIf { it != KtTokens.DEFAULT_VISIBILITY_KEYWORD }
?.let { it to false } ?: return emptyList()
else -> javaPsiModifiersMapping[modifier] to shouldPresent
}
if (kToken == null) return emptyList()
val action = if (shouldPresentMapped)
AddModifierFix.createIfApplicable(kModifierOwner, kToken)
else
RemoveModifierFix(kModifierOwner, kToken, false)
return listOfNotNull(action)
}
override fun createAddConstructorActions(targetClass: JvmClass, request: CreateConstructorRequest): List<IntentionAction> {
val targetKtClass = targetClass.toKtClassOrFile() as? KtClass ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetKtClass).apply { addJvmModifiers(request.modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetKtClass.getResolutionFacade()
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
val helper = JvmPsiConversionHelper.getInstance(targetKtClass.project)
val parameters = request.parameters as List<Pair<SuggestedNameInfo, List<ExpectedType>>>
val parameterInfos = parameters.mapIndexed { index, param: Pair<SuggestedNameInfo, List<ExpectedType>> ->
val ktType = helper.asPsiType(param)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val name = param.first.names.firstOrNull() ?: "arg${index + 1}"
ParameterInfo(TypeInfo(ktType, Variance.IN_VARIANCE), listOf(name))
}
val needPrimary = !targetKtClass.hasExplicitPrimaryConstructor()
val constructorInfo = ConstructorInfo(
parameterInfos,
targetKtClass,
isPrimary = needPrimary,
modifierList = modifierBuilder.modifierList,
withBody = true
)
val targetClassName = targetClass.name
val addConstructorAction = object : CreateCallableFromUsageFix<KtElement>(targetKtClass, listOf(constructorInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add ${if (needPrimary) "primary" else "secondary"} constructor to '$targetClassName'"
}
val changePrimaryConstructorAction = run {
val primaryConstructor = targetKtClass.primaryConstructor ?: return@run null
val lightMethod = primaryConstructor.toLightMethods().firstOrNull() ?: return@run null
val project = targetKtClass.project
val fakeParametersExpressions = fakeParametersExpressions(parameters, project) ?: return@run null
QuickFixFactory.getInstance()
.createChangeMethodSignatureFromUsageFix(
lightMethod,
fakeParametersExpressions,
PsiSubstitutor.EMPTY,
targetKtClass,
false,
2
).takeIf { it.isAvailable(project, null, targetKtClass.containingFile) }
}
return listOfNotNull(changePrimaryConstructorAction, addConstructorAction)
}
override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
return createAddPropertyActions(
targetContainer, listOf(request.visibilityModifier),
request.propertyType, request.propertyName, request.setterRequired, targetClass.name
)
}
private fun createAddPropertyActions(
targetContainer: KtElement,
modifiers: Iterable<JvmModifier>,
propertyType: JvmType,
propertyName: String,
setterRequired: Boolean,
classOrFileName: String?
): List<IntentionAction> {
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
val ktType = (propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val propertyInfo = PropertyInfo(
propertyName,
TypeInfo.Empty,
TypeInfo(ktType, Variance.INVARIANT),
setterRequired,
listOf(targetContainer),
modifierList = modifierBuilder.modifierList,
withInitializer = true
)
val propertyInfos = if (setterRequired) {
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
} else {
listOf(propertyInfo)
}
return propertyInfos.map { CreatePropertyFix(targetContainer, it, classOrFileName) }
}
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val typeInfo = request.fieldType.toKotlinTypeInfo(resolutionFacade)
val writable = JvmModifier.FINAL !in request.modifiers
fun propertyInfo(lateinit: Boolean) = PropertyInfo(
request.fieldName,
TypeInfo.Empty,
typeInfo,
writable,
listOf(targetContainer),
isLateinitPreferred = false, // Dont set it to `lateinit` because it works via templates that brings issues in batch field adding
isForCompanion = JvmModifier.STATIC in request.modifiers,
modifierList = ModifierBuilder(targetContainer, allowJvmStatic = false).apply {
addJvmModifiers(request.modifiers)
if (modifierList.children.none { it.node.elementType in KtTokens.VISIBILITY_MODIFIERS })
addJvmModifier(JvmModifier.PUBLIC)
if (lateinit)
modifierList.appendModifier(KtTokens.LATEINIT_KEYWORD)
if (!request.modifiers.contains(JvmModifier.PRIVATE) && !lateinit)
addAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME)
}.modifierList,
withInitializer = !lateinit
)
val propertyInfos = if (writable) {
listOf(propertyInfo(false), propertyInfo(true))
}
else {
listOf(propertyInfo(false))
}
return propertyInfos.map { CreatePropertyFix(targetContainer, it, targetClass.name) }
}
override fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(request.modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = KotlinCacheService.getInstance(targetContainer.project)
.getResolutionFacadeByFile(targetContainer.containingFile, JvmPlatform) ?: return emptyList()
val returnTypeInfo = request.returnType.toKotlinTypeInfo(resolutionFacade)
val parameters = request.parameters as List<Pair<SuggestedNameInfo, List<ExpectedType>>>
val parameterInfos = parameters.map { (suggestedNames, expectedTypes) ->
ParameterInfo(expectedTypes.toKotlinTypeInfo(resolutionFacade), suggestedNames.names.toList())
}
val methodName = request.methodName
val functionInfo = FunctionInfo(
methodName,
TypeInfo.Empty,
returnTypeInfo,
listOf(targetContainer),
parameterInfos,
isForCompanion = JvmModifier.STATIC in request.modifiers,
modifierList = modifierBuilder.modifierList,
preferEmptyBody = true
)
val targetClassName = targetClass.name
val action = object : CreateCallableFromUsageFix<KtElement>(targetContainer, listOf(functionInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add method '$methodName' to '$targetClassName'"
}
val nameAndKind = PropertyUtilBase.getPropertyNameAndKind(methodName) ?: return listOf(action)
val propertyType = (request.expectedParameters.singleOrNull()?.expectedTypes ?: request.returnType)
.firstOrNull { JvmPsiConversionHelper.getInstance(targetContainer.project).convertType(it.theType) != PsiType.VOID }
?: return listOf(action)
return createAddPropertyActions(
targetContainer,
request.modifiers,
propertyType.theType,
nameAndKind.first,
nameAndKind.second == PropertyKind.SETTER,
targetClass.name
)
}
override fun createAddAnnotationActions(target: JvmModifiersOwner, request: AnnotationRequest): List<IntentionAction> {
val declaration = (target as? KtLightElement<*, *>)?.kotlinOrigin as? KtModifierListOwner ?: return emptyList()
if (declaration.language != KotlinLanguage.INSTANCE) return emptyList()
return listOf(CreateAnnotationAction(declaration, request))
}
private class CreateAnnotationAction(
target: KtModifierListOwner,
val request: AnnotationRequest
) : IntentionAction {
private val pointer = target.createSmartPointer()
override fun startInWriteAction(): Boolean = true
override fun getText(): String =
QuickFixBundle.message("create.annotation.text", StringUtilRt.getShortName(request.qualifiedName))
override fun getFamilyName(): String = QuickFixBundle.message("create.annotation.family")
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean = pointer.element != null
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
val target = pointer.element ?: return
val kotlinAnnotation = JavaPsiFacade.getInstance(project).findClass(
request.qualifiedName,
target.resolveScope
)?.language == KotlinLanguage.INSTANCE
val entry = target.addAnnotationEntry(
KtPsiFactory(target)
.createAnnotationEntry(
"@${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(", ", "(", ")")
}"
)
)
ShortenReferences.DEFAULT.process(entry)
}
private fun renderAttributeValue(annotationAttributeRequest: AnnotationAttributeValueRequest) =
when (annotationAttributeRequest) {
is AnnotationAttributeValueRequest.PrimitiveValue -> annotationAttributeRequest.value
is AnnotationAttributeValueRequest.StringValue -> "\"" + annotationAttributeRequest.value + "\""
}
}
}
private fun JvmPsiConversionHelper.asPsiType(param: Pair<SuggestedNameInfo, List<ExpectedType>>): PsiType? =
param.second.firstOrNull()?.theType?.let { convertType(it) }

View File

@@ -16,11 +16,14 @@
package org.jetbrains.kotlin.idea.refactoring.pullUp
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiNamedElement
import com.intellij.refactoring.HelpID
import com.intellij.refactoring.RefactoringBundle
@@ -37,6 +40,7 @@ import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import org.jetbrains.kotlin.types.typeUtil.supertypes
class KotlinPullUpHandler : AbstractPullPushMembersHandler(
@@ -111,6 +115,16 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler(
KotlinPullUpDialog(project, classOrObject, superClasses, memberInfoStorage).show()
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
super.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
val PULL_MEMBERS_UP = "Pull Members Up"

View File

@@ -16,10 +16,13 @@
package org.jetbrains.kotlin.idea.refactoring.pushDown
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.refactoring.HelpID
import com.intellij.refactoring.RefactoringBundle
@@ -34,6 +37,7 @@ import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
val PUSH_MEMBERS_DOWN = "Push Members Down"
@@ -84,4 +88,14 @@ class KotlinPushDownHandler : AbstractPullPushMembersHandler(
KotlinPushDownDialog(project, members, classOrObject).show()
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
super.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
abstract class AbstractReferenceSubstitutionRenameHandler(
private val delegateHandler: RenameHandler = MemberInplaceRenameHandler()
@@ -63,6 +65,9 @@ abstract class AbstractReferenceSubstitutionRenameHandler(
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) {
val elementToRename = getElementToRename(dataContext) ?: return
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
val wrappingContext = DataContext { id ->
if (CommonDataKeys.PSI_ELEMENT.`is`(id)) return@DataContext elementToRename
dataContext.getData(id)
@@ -70,13 +75,13 @@ abstract class AbstractReferenceSubstitutionRenameHandler(
// Can't provide new name for inplace refactoring in unit test mode
if (!ApplicationManager.getApplication().isUnitTestMode && delegateHandler.isAvailableOnDataContext(wrappingContext)) {
delegateHandler.invoke(project, editor, file, wrappingContext)
}
else {
} else {
super.invoke(project, editor, file, wrappingContext)
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
// Can't be invoked outside of a text editor
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -16,17 +16,20 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
import com.intellij.refactoring.rename.naming.AutomaticRenamer
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class AutomaticInheritorRenamer(klass: KtClass, newName: String): AutomaticRenamer() {
init {
@@ -45,6 +48,21 @@ class AutomaticInheritorRenamer(klass: KtClass, newName: String): AutomaticRenam
override fun getDialogTitle() = RefactoringBundle.message("rename.inheritors.title")
override fun getDialogDescription() = RefactoringBundle.message("rename.inheritors.with.the.following.names.to")
override fun entityName() = RefactoringBundle.message("entity.name.inheritor")
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?, allRenames: MutableMap<PsiElement, String>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages, allRenames)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
class AutomaticInheritorRenamerFactory : AutomaticRenamerFactory {

View File

@@ -16,10 +16,12 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
import com.intellij.refactoring.rename.naming.AutomaticRenamer
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
import com.intellij.usageView.UsageInfo
@@ -36,6 +38,7 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.UserDataProperty
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class AutomaticOverloadsRenamer(function: KtNamedFunction, newName: String) : AutomaticRenamer() {
companion object {
@@ -58,6 +61,21 @@ class AutomaticOverloadsRenamer(function: KtNamedFunction, newName: String) : Au
override fun getDialogDescription() = "Rename overloads to:"
override fun entityName() = "Overload"
override fun isSelectedByDefault(): Boolean = true
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?, allRenames: MutableMap<PsiElement, String>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages, allRenames)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
private fun KtNamedFunction.getOverloads(): Collection<FunctionDescriptor> {

View File

@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
import com.intellij.refactoring.rename.naming.AutomaticRenamer
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
import com.intellij.usageView.UsageInfo
@@ -32,6 +34,7 @@ import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class AutomaticParameterRenamer(element: KtParameter, newName: String) : AutomaticRenamer() {
init {
@@ -62,6 +65,21 @@ class AutomaticParameterRenamer(element: KtParameter, newName: String) : Automat
override fun entityName() = "Parameter"
override fun isSelectedByDefault() = true
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?, allRenames: MutableMap<PsiElement, String>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages, allRenames)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
class AutomaticParameterRenamerFactory : AutomaticRenamerFactory {

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiClass
@@ -26,6 +27,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
import com.intellij.refactoring.rename.naming.AutomaticRenamer
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
import com.intellij.usageView.UsageInfo
@@ -42,6 +44,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.util.*
@@ -126,6 +129,21 @@ class AutomaticVariableRenamer(
companion object {
val LOG = Logger.getInstance(AutomaticVariableRenamer::class.java)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun findUsages(result: MutableList<UsageInfo>?, searchInStringsAndComments: Boolean, searchInNonJavaFiles: Boolean, unresolvedUsages: MutableList<UnresolvableCollisionUsageInfo>?, allRenames: MutableMap<PsiElement, String>?) {
super.findUsages(result, searchInStringsAndComments, searchInNonJavaFiles, unresolvedUsages, allRenames)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
private fun KotlinType.isCollectionLikeOf(classPsiElement: PsiNamedElement): Boolean {

View File

@@ -16,8 +16,11 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.command.impl.StartMarkAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiMember
@@ -30,6 +33,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class JavaMemberByKotlinReferenceInplaceRenameHandler : MemberInplaceRenameHandler() {
class Renamer(
@@ -54,4 +58,15 @@ class JavaMemberByKotlinReferenceInplaceRenameHandler : MemberInplaceRenameHandl
override fun createMemberRenamer(element: PsiElement, elementToRename: PsiNameIdentifierOwner, editor: Editor): MemberInplaceRenamer {
return Renamer(elementToRename, element, editor)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
super.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.idea.references.SyntheticPropertyAccessorReference
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.utils.ifEmpty
@@ -26,6 +28,7 @@ class KotlinAwareJavaGetterRenameProcessor : RenameJavaMethodProcessor() {
val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(Name.identifier(getter.name)) ?: return getterReferences
val setterName = JvmAbi.setterName(propertyName.asString())
val containingClass = getter.containingClass ?: return getterReferences
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
val setterReferences = containingClass
.findMethodsByName(setterName, true)
.filter { it.parameters.size == 1 && it.returnType == PsiType.VOID }

View File

@@ -16,11 +16,27 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.refactoring.rename.DirectoryAsPackageRenameHandler
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class KotlinDirectoryAsPackageRenameHandler : DirectoryAsPackageRenameHandler() {
override fun isIdentifier(name: String, project: Project): Boolean = name.quoteIfNeeded().isIdentifier()
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
super.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
}
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
}
}

View File

@@ -16,8 +16,11 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.lang.Language
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.refactoring.RefactoringActionHandler
import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler
@@ -27,6 +30,7 @@ import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class KotlinMemberInplaceRenameHandler : MemberInplaceRenameHandler() {
private class RenamerImpl(
@@ -86,4 +90,14 @@ class KotlinMemberInplaceRenameHandler : MemberInplaceRenameHandler() {
val currentElement = element?.substitute() as? KtNamedDeclaration ?: return false
return currentElement.nameIdentifier != null && !KotlinVariableInplaceRenameHandler.isInplaceRenameAvailable(currentElement)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
super.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
}
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
}
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.extensions.ExtensionPointName
@@ -24,6 +25,7 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.refactoring.rename.RenameHandler
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.util.*
@@ -47,9 +49,11 @@ class KotlinRenameDispatcherHandler : RenameHandler {
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) {
getRenameHandler(dataContext)?.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
getRenameHandler(dataContext)?.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -26,6 +26,8 @@ import com.intellij.psi.PsiFile
import com.intellij.refactoring.rename.RenameHandler
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.util.*
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class KotlinRenameDispatcherHandler : RenameHandler {
companion object {
@@ -47,9 +49,11 @@ class KotlinRenameDispatcherHandler : RenameHandler {
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
getRenameHandler(dataContext)?.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
getRenameHandler(dataContext)?.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.refactoring.RefactoringActionHandler
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer
import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
open class KotlinVariableInplaceRenameHandler : VariableInplaceRenameHandler() {
companion object {
@@ -68,4 +72,14 @@ open class KotlinVariableInplaceRenameHandler : VariableInplaceRenameHandler() {
override public fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile) =
editor.settings.isVariableInplaceRenameEnabled && element != null && isInplaceRenameAvailable(element)
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
super.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.refactoring.RefactoringActionHandler
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer
import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
open class KotlinVariableInplaceRenameHandler : VariableInplaceRenameHandler() {
companion object {
@@ -68,4 +72,14 @@ open class KotlinVariableInplaceRenameHandler : VariableInplaceRenameHandler() {
override public fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile) =
editor.settings.isVariableInplaceRenameEnabled && element != null && isInplaceRenameAvailable(element)
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext) {
getRenameHandler(dataContext)?.invoke(project, editor, file, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
getRenameHandler(dataContext)?.invoke(project, elements, dataContext)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -26,15 +26,18 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
class RenameBackingFieldReferenceHandler: KotlinVariableInplaceRenameHandler() {
class RenameBackingFieldReferenceHandler : KotlinVariableInplaceRenameHandler() {
override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean {
val refExpression = file.findElementForRename<KtSimpleNameExpression>(editor.caretModel.offset) ?: return false
if (refExpression.text != "field") return false
return refExpression.resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to backing field reference", "Rename", null)
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
editor?.let {
CodeInsightUtils.showErrorHint(project, it, "Rename is not applicable to backing field reference", "Rename", null)
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {

View File

@@ -33,11 +33,13 @@ class RenameBackingFieldReferenceHandler: KotlinVariableInplaceRenameHandler() {
return refExpression.resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to backing field reference", "Rename", null)
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
editor?.let {
CodeInsightUtils.showErrorHint(project, it, "Rename is not applicable to backing field reference", "Rename", null)
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
// Do nothing: this method is called not from editor
}
}

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -45,4 +46,5 @@ class RenameByLabeledReferenceInLambdaArgumentHandler :
DescriptorToSourceUtilsIde.getAnyDeclaration(dataContext.project, descriptor)
}
}
}

View File

@@ -36,8 +36,11 @@ class RenameDynamicMemberHandler: KotlinVariableInplaceRenameHandler() {
return calleeDescriptor.isDynamic()
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to dynamically invoked members", "Rename", null)
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
editor?.let {
CodeInsightUtils.showErrorHint(project, it, "Rename is not applicable to dynamically invoked members", "Rename", null)
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {

View File

@@ -36,11 +36,14 @@ class RenameDynamicMemberHandler: KotlinVariableInplaceRenameHandler() {
return calleeDescriptor.isDynamic()
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to dynamically invoked members", "Rename", null)
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
super.invoke(project, editor, file, dataContext)
editor?.let {
CodeInsightUtils.showErrorHint(project, it, "Rename is not applicable to dynamically invoked members", "Rename", null)
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
// Do nothing: this method is called not from editor
}
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
@@ -36,6 +37,7 @@ import org.jetbrains.kotlin.psi.psiUtil.plainContent
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class RenameJvmNameHandler : PsiElementRenameHandler() {
private fun getStringTemplate(dataContext: DataContext): KtStringTemplateExpression? {
@@ -75,9 +77,11 @@ class RenameJvmNameHandler : PsiElementRenameHandler() {
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext) {
super.invoke(project, editor, file, wrapDataContext(dataContext) ?: return)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext) {
super.invoke(project, elements, wrapDataContext(dataContext) ?: return)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}

View File

@@ -16,10 +16,12 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.refactoring.rename.RenamePsiFileProcessor
@@ -29,6 +31,7 @@ import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class RenameKotlinFileProcessor : RenamePsiFileProcessor() {
class FileRenamingPsiClassWrapper(
@@ -63,4 +66,16 @@ class RenameKotlinFileProcessor : RenamePsiFileProcessor() {
}
}
}
override fun findReferences(element: PsiElement): MutableCollection<PsiReference> {
return super.findReferences(element).also {
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
override fun findReferences(element: PsiElement, searchInCommentsAndStrings: Boolean): MutableCollection<PsiReference> {
return super.findReferences(element, searchInCommentsAndStrings).also {
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
}

View File

@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
class RenameKotlinFileProcessor : RenamePsiFileProcessor() {
class FileRenamingPsiClassWrapper(
@@ -63,4 +65,15 @@ class RenameKotlinFileProcessor : RenamePsiFileProcessor() {
}
}
}
override fun findReferences(element: PsiElement): MutableCollection<PsiReference> {
return super.findReferences(element).also {
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
override fun findReferences(element: PsiElement, searchInCommentsAndStrings: Boolean): MutableCollection<PsiReference> {
return super.findReferences(element, searchInCommentsAndStrings).also {
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
}

View File

@@ -33,10 +33,10 @@ class RenameKotlinImplicitLambdaParameter : KotlinVariableInplaceRenameHandler()
return nameExpression != null && isAutoCreatedItUsage(nameExpression)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
override fun invoke(project: Project, editor: Editor?, file: PsiFile?, dataContext: DataContext?) {
val intention = ReplaceItWithExplicitFunctionLiteralParamIntention()
project.executeWriteCommand("Convert 'it' to explicit lambda parameter") {
intention.invoke(project, editor, file)
if (file != null) intention.invoke(project, editor, file)
}
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.util.Key
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
@@ -46,6 +47,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import java.util.ArrayList
import kotlin.collections.*
@@ -67,6 +69,8 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
override fun canProcessElement(element: PsiElement): Boolean = element is KtNamedDeclaration
override fun findReferences(element: PsiElement): Collection<PsiReference> {
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
val searchParameters = KotlinReferencesSearchParameters(
element,
element.project.projectScope() or element.useScope,

View File

@@ -41,11 +41,15 @@ import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
override fun canProcessElement(element: PsiElement): Boolean = element is KtNamedDeclaration
override fun findReferences(element: PsiElement): Collection<PsiReference> {
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
val searchParameters = KotlinReferencesSearchParameters(
element,
element.project.projectScope() or element.useScope,

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
@@ -26,6 +27,7 @@ import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.rename.RenameHandler
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class RenameOnSecondaryConstructorHandler : RenameHandler {
@@ -44,6 +46,7 @@ class RenameOnSecondaryConstructorHandler : RenameHandler {
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to secondary constructors", "Rename", null)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class RenameSyntheticDeclarationByReferenceHandler : RenameHandler {
override fun isAvailableOnDataContext(dataContext: DataContext): Boolean {
@@ -29,6 +31,7 @@ class RenameSyntheticDeclarationByReferenceHandler : RenameHandler {
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to synthetic declaration", "Rename", null)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.internal.statistic.service.fus.collectors.FUSApplicationUsageTrigger
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
class RenameSyntheticDeclarationByReferenceHandler : RenameHandler {
override fun isAvailableOnDataContext(dataContext: DataContext?): Boolean {
@@ -30,6 +32,7 @@ class RenameSyntheticDeclarationByReferenceHandler : RenameHandler {
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
CodeInsightUtils.showErrorHint(project, editor, "Rename is not applicable to synthetic declaration", "Rename", null)
FUSApplicationUsageTrigger.getInstance().trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {

View File

@@ -0,0 +1,32 @@
@file:Suppress("UNUSED_PARAMETER")
import kotlin.coroutines.*
import org.jetbrains.annotations.BlockingContext
import kotlin.coroutines.experimental.buildSequence
import java.lang.Thread.sleep
suspend fun testFunction() {
@BlockingContext
val ctx = getContext()
// no warnings with @BlockingContext annotation on ctx object
withContext(ctx) {Thread.sleep (2)}
// no warnings with @BlockingContext annotation on getContext() method
withContext(getContext()) {Thread.sleep(3)}
withContext(getNonBlockingContext()) {
Thread.<warning descr="Inappropriate blocking method call">sleep</warning>(3);
}
}
@BlockingContext
fun getContext(): CoroutineContext = TODO()
fun getNonBlockingContext(): CoroutineContext = TODO()
suspend fun <T> withContext(
context: CoroutineContext,
f: suspend () -> T
) {
TODO()
}

View File

@@ -0,0 +1,10 @@
@file:Suppress("UNUSED_PARAMETER")
import kotlin.coroutines.*
import java.lang.Thread.sleep
class InsideCoroutine {
suspend fun example1() {
Thread.<warning descr="Inappropriate blocking method call">sleep</warning>(1);
}
}

View File

@@ -0,0 +1,20 @@
@file:Suppress("UNUSED_PARAMETER")
import java.lang.Thread.sleep
import kotlin.coroutines.RestrictsSuspension
suspend fun testFunction() {
// @RestrictsSuspension annotation allows blocking calls
withRestrictedReceiver({Thread.sleep(0)}, {Thread.sleep(1)})
withSimpleReceiver({Thread.<warning descr="Inappropriate blocking method call">sleep</warning>(2)})
}
fun withRestrictedReceiver(firstParam: suspend Test1.() -> Unit, secondParam: () -> Unit) {}
fun withSimpleReceiver(firstParam: suspend Test2.() -> Unit) {}
@RestrictsSuspension
class Test1
class Test2

View File

@@ -0,0 +1,11 @@
fun <T> runBlocking(<warning descr="[UNUSED_PARAMETER] Parameter 'block' is never used">block</warning>: suspend CoroutineScope.() -> T): T = TODO()
class CoroutineScope
fun test() {
runBlocking {
repeat(1) {
java.lang.Thread.<warning descr="Inappropriate blocking method call">sleep</warning>(2)
}
}
}

View File

@@ -59,7 +59,7 @@ object PsiElementChecker {
with(element) {
try {
Assert.assertEquals("Number of methods has changed. Please update test.", 54, PsiElement::class.java.methods.size)
Assert.assertEquals("Number of methods has changed. Please update test.", 55, PsiElement::class.java.methods.size)
project
Assert.assertTrue(language == KotlinLanguage.INSTANCE)
@@ -72,6 +72,7 @@ object PsiElementChecker {
prevSibling
containingFile
textRange
//textRangeInParent - throws an exception for non-physical elements, it is expected behaviour
startOffsetInParent
textLength
findElementAt(0)

View File

@@ -0,0 +1,130 @@
/*
* 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.caches.resolve
import com.intellij.openapi.util.Key
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.junit.Assert
object PsiElementChecker {
val TEST_DATA_KEY = Key.create<Int>("Test Key")
fun checkPsiElementStructure(lightClass: PsiClass) {
checkPsiElement(lightClass)
lightClass.methods.forEach {
it.parameterList.parameters.forEach { checkPsiElement(it) }
checkPsiElement(it)
}
lightClass.fields.forEach { checkPsiElement(it) }
lightClass.innerClasses.forEach { checkPsiElementStructure(it) }
}
private fun checkPsiElement(element: PsiElement) {
if (element !is KtLightElement<*, *> && element !is KtLightModifierList<*>) return
if (element is PsiModifierListOwner) {
val modifierList = element.modifierList
if (modifierList != null) {
checkPsiElement(modifierList)
}
}
if (element is PsiTypeParameterListOwner) {
val typeParameterList = element.typeParameterList
if (typeParameterList != null) {
checkPsiElement(typeParameterList)
typeParameterList.typeParameters.forEach { checkPsiElement(it) }
}
}
with(element) {
try {
Assert.assertEquals("Number of methods has changed. Please update test.", 54, PsiElement::class.java.methods.size)
project
Assert.assertTrue(language == KotlinLanguage.INSTANCE)
manager
children
parent
firstChild
lastChild
nextSibling
prevSibling
containingFile
textRange
startOffsetInParent
textLength
findElementAt(0)
findReferenceAt(0)
textOffset
text
textToCharArray()
navigationElement
originalElement
textMatches("")
Assert.assertTrue(textMatches(this))
textContains('a')
accept(PsiElementVisitor.EMPTY_VISITOR)
acceptChildren(PsiElementVisitor.EMPTY_VISITOR)
val copy = copy()
Assert.assertTrue(copy == null || copy::class.java == this::class.java)
// Modify methods:
// add(this)
// addBefore(this, lastChild)
// addAfter(firstChild, this)
// checkAdd(this)
// addRange(firstChild, lastChild)
// addRangeBefore(firstChild, lastChild, lastChild)
// addRangeAfter(firstChild, lastChild, firstChild)
// delete()
// checkDelete()
// deleteChildRange(firstChild, lastChild)
// replace(this)
Assert.assertTrue(isValid)
isWritable
reference
references
putCopyableUserData(TEST_DATA_KEY, 12)
Assert.assertTrue(getCopyableUserData(TEST_DATA_KEY) == 12)
// Assert.assertTrue(copy().getCopyableUserData(TEST_DATA_KEY) == 12) { this } Doesn't work
// processDeclarations(...)
context
isPhysical
resolveScope
useScope
node
toString()
Assert.assertTrue(isEquivalentTo(this))
}
catch (t: Throwable) {
throw AssertionErrorWithCause("Failed for ${this::class.java} ${this}", t)
}
}
}
}

View File

@@ -223,7 +223,9 @@ public abstract class AbstractHierarchyTest extends KotlinHierarchyViewTestBase
}
@Override
protected void doHierarchyTest(Computable<HierarchyTreeStructure> treeStructureComputable, String... fileNames) throws Exception {
protected void doHierarchyTest(
@NotNull Computable<? extends HierarchyTreeStructure> treeStructureComputable, @NotNull String... fileNames
) throws Exception {
try {
super.doHierarchyTest(treeStructureComputable, fileNames);
}

View File

@@ -0,0 +1,262 @@
/*
* 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.hierarchy;
import com.intellij.ide.hierarchy.*;
import com.intellij.ide.hierarchy.actions.BrowseHierarchyActionBase;
import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure;
import com.intellij.ide.hierarchy.type.SubtypesHierarchyTreeStructure;
import com.intellij.ide.hierarchy.type.SupertypesHierarchyTreeStructure;
import com.intellij.ide.hierarchy.type.TypeHierarchyTreeStructure;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.impl.text.TextEditorPsiDataProvider;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.*;
import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException;
import com.intellij.rt.execution.junit.ComparisonDetailsExtractor;
import com.intellij.testFramework.MapDataContext;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import junit.framework.ComparisonFailure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinHierarchyViewTestBase;
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCalleeTreeStructure;
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallerTreeStructure;
import org.jetbrains.kotlin.idea.hierarchy.overrides.KotlinOverrideTreeStructure;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.psi.KtCallableDeclaration;
import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Test Hierarchy view
Format: test build hierarchy for element at caret, file with caret should be the first in the sorted list of files.
Test accept more than one file, file extension should be .java or .kt
*/
public abstract class AbstractHierarchyTest extends KotlinHierarchyViewTestBase {
protected String folderName;
protected void doTypeClassHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getTypeHierarchyStructure(), getFilesToConfigure());
}
protected void doSuperClassHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getSuperTypesHierarchyStructure(), getFilesToConfigure());
}
protected void doSubClassHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getSubTypesHierarchyStructure(), getFilesToConfigure());
}
protected void doCallerHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getCallerHierarchyStructure(), getFilesToConfigure());
}
protected void doCallerJavaHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getCallerJavaHierarchyStructure(), getFilesToConfigure());
}
protected void doCalleeHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getCalleeHierarchyStructure(), getFilesToConfigure());
}
protected void doOverrideHierarchyTest(@NotNull String folderName) throws Exception {
this.folderName = folderName;
doHierarchyTest(getOverrideHierarchyStructure(), getFilesToConfigure());
}
private Computable<HierarchyTreeStructure> getSuperTypesHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new SupertypesHierarchyTreeStructure(
getProject(),
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE)
);
}
};
}
private Computable<HierarchyTreeStructure> getSubTypesHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new SubtypesHierarchyTreeStructure(
getProject(),
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE),
HierarchyBrowserBaseEx.SCOPE_PROJECT
);
}
};
}
private Computable<HierarchyTreeStructure> getTypeHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new TypeHierarchyTreeStructure(
getProject(),
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE),
HierarchyBrowserBaseEx.SCOPE_PROJECT
);
}
};
}
private Computable<HierarchyTreeStructure> getCallerHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new KotlinCallerTreeStructure(
(KtElement) getElementAtCaret(LanguageCallHierarchy.INSTANCE),
HierarchyBrowserBaseEx.SCOPE_PROJECT
);
}
};
}
private Computable<HierarchyTreeStructure> getCallerJavaHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new CallerMethodsTreeStructure(
getProject(),
(PsiMethod) getElementAtCaret(LanguageCallHierarchy.INSTANCE),
HierarchyBrowserBaseEx.SCOPE_PROJECT
);
}
};
}
private Computable<HierarchyTreeStructure> getCalleeHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new KotlinCalleeTreeStructure(
(KtElement) getElementAtCaret(LanguageCallHierarchy.INSTANCE),
HierarchyBrowserBaseEx.SCOPE_PROJECT
);
}
};
}
private Computable<HierarchyTreeStructure> getOverrideHierarchyStructure() {
return new Computable<HierarchyTreeStructure>() {
@Override
public HierarchyTreeStructure compute() {
return new KotlinOverrideTreeStructure(
getProject(),
(KtCallableDeclaration) getElementAtCaret(LanguageMethodHierarchy.INSTANCE)
);
}
};
}
private PsiElement getElementAtCaret(LanguageExtension<HierarchyProvider> extension) {
PsiFile file = PsiDocumentManager.getInstance(getProject()).getPsiFile(getEditor().getDocument());
HierarchyProvider provider = BrowseHierarchyActionBase.findProvider(extension, file, file, getDataContext());
PsiElement target = provider != null ? provider.getTarget(getDataContext()) : null;
if (target == null) throw new RefactoringErrorHintException("Cannot apply action for element at caret");
return target;
}
private DataContext getDataContext() {
Editor editor = getEditor();
MapDataContext context = new MapDataContext();
context.put(CommonDataKeys.PROJECT, getProject());
context.put(CommonDataKeys.EDITOR, editor);
PsiElement targetElement = (PsiElement) new TextEditorPsiDataProvider().getData(
CommonDataKeys.PSI_ELEMENT.getName(),
editor,
editor.getCaretModel().getCurrentCaret()
);
context.put(CommonDataKeys.PSI_ELEMENT, targetElement);
return context;
}
protected String[] getFilesToConfigure() {
final List<String> files = new ArrayList<String>(2);
FileUtil.processFilesRecursively(new File(folderName), new Processor<File>() {
@Override
public boolean process(File file) {
String fileName = file.getName();
if (fileName.endsWith(".kt") || fileName.endsWith(".java")) {
files.add(fileName);
}
return true;
}
});
Collections.sort(files);
return ArrayUtil.toStringArray(files);
}
@Override
protected void doHierarchyTest(Computable<HierarchyTreeStructure> treeStructureComputable, String... fileNames) throws Exception {
try {
super.doHierarchyTest(treeStructureComputable, fileNames);
}
catch (RefactoringErrorHintException e) {
File file = new File(folderName, "messages.txt");
if (file.exists()) {
String expectedMessage = FileUtil.loadFile(file, true);
assertEquals(expectedMessage, e.getLocalizedMessage());
}
else {
fail("Unexpected error: " + e.getLocalizedMessage());
}
}
catch (ComparisonFailure failure) {
String actual = ComparisonDetailsExtractor.getActual(failure);
String verificationFilePath =
getTestDataPath() + "/" + getBasePath() + "/" + getTestName(false) + "_verification.xml";
KotlinTestUtils.assertEqualsToFile(new File(verificationFilePath), actual);
}
}
@Override
protected String getBasePath() {
return folderName.substring("idea/testData/".length());
}
@Override
protected String getTestDataPath() {
return PluginTestCaseBase.getTestDataPathBase();
}
@Override
protected Sdk getTestProjectJdk() {
return PluginTestCaseBase.mockJdk();
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.inspections
import com.intellij.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.test.configureCompilerOptions
class CoroutineNonBlockingontextDetectionTest: KotlinLightCodeInsightFixtureTestCase() {
override fun getTestDataPath(): String
= PluginTestCaseBase.getTestDataPathBase() + "/inspections/blockingCallsDetection"
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
override fun setUp() {
super.setUp()
myFixture.addClass("""package org.jetbrains.annotations; public @interface BlockingContext {}""")
myFixture.enableInspections(BlockingMethodInNonBlockingContextInspection::class.java)
}
fun testSimpleCoroutineScope() {
myFixture.configureByFile("InsideCoroutine.kt")
myFixture.testHighlighting(true, false, false, "InsideCoroutine.kt")
}
fun testCoroutineContextCheck() {
myFixture.configureByFiles("ContextCheck.kt")
myFixture.testHighlighting(true, false, false, "ContextCheck.kt")
}
fun testLambdaReceiverType() {
myFixture.configureByFile("LambdaReceiverTypeCheck.kt")
myFixture.testHighlighting(true, false, false, "LambdaReceiverTypeCheck.kt")
}
fun testNestedFunctionsInsideSuspendLambda() {
myFixture.configureByFile("NestedFunctionsInsideSuspendLambda.kt")
myFixture.testHighlighting(true, false, false, "NestedFunctionsInsideSuspendLambda.kt")
}
}

View File

@@ -19,15 +19,14 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.lang.jvm.JvmClass
import com.intellij.lang.jvm.JvmElement
import com.intellij.lang.jvm.JvmMethod
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.PsiJvmSubstitutor
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.PsiType
import com.intellij.psi.*
import com.intellij.psi.codeStyle.SuggestedNameInfo
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
@@ -35,6 +34,9 @@ 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
@@ -401,15 +403,15 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
myFixture.atCaret(),
SimpleMethodRequest(
project,
methodName = "setBaz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(),
parameters = expectedParams(PsiType.getTypeByName("java.lang.String", project, project.allScope()))
)
).findWithText("Add 'var' property 'baz' to 'Foo'")
)
).findWithText("Add 'var' property 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
@@ -429,15 +431,15 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
myFixture.atCaret(),
SimpleMethodRequest(
project,
methodName = "setBaz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(),
parameters = expectedParams(PsiType.getTypeByName("java.lang.String", project, project.allScope()))
)
).findWithText("Add 'lateinit var' property 'baz' to 'Foo'")
)
).findWithText("Add 'lateinit var' property 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
@@ -515,15 +517,15 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
myFixture.atCaret(),
SimpleMethodRequest(
project,
methodName = "getBaz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(PsiType.getTypeByName("java.lang.String", project, project.allScope())),
parameters = expectedParams()
)
).findWithText("Add 'val' property 'baz' to 'Foo'")
)
).findWithText("Add 'val' property 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
@@ -534,6 +536,45 @@ 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) =

View File

@@ -0,0 +1,572 @@
/*
* 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.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.lang.jvm.JvmClass
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.openapi.project.Project
import com.intellij.openapi.util.Pair.pair
import com.intellij.psi.PsiJvmSubstitutor
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.PsiType
import com.intellij.psi.codeStyle.SuggestedNameInfo
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
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.toUElement
import org.junit.Assert
class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
private class SimpleMethodRequest(
project: Project,
private val methodName: String,
private val modifiers: Collection<JvmModifier> = emptyList(),
private val returnType: ExpectedTypes = emptyList(),
private val annotations: Collection<AnnotationRequest> = emptyList(),
parameters: List<ExpectedParameter> = emptyList(),
private val targetSubstitutor: JvmSubstitutor = PsiJvmSubstitutor(project, PsiSubstitutor.EMPTY)
) : CreateMethodRequest {
private val expectedParameters = parameters
override fun getTargetSubstitutor(): JvmSubstitutor = targetSubstitutor
override fun getModifiers() = modifiers
override fun getMethodName() = methodName
override fun getAnnotations() = annotations
override fun getExpectedParameters(): List<ExpectedParameter> = expectedParameters
override fun getReturnType() = returnType
override fun isValid(): Boolean = true
}
private class NameInfo(vararg names: String) : SuggestedNameInfo(names)
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
fun testMakeNotFinal() {
myFixture.configureByText("foo.kt", """
class Foo {
fun bar<caret>(){}
}
""")
myFixture.launchAction(
createModifierActions(
myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.FINAL, false)
).findWithText("Make 'bar' open")
)
myFixture.checkResult("""
class Foo {
open fun bar(){}
}
""")
}
fun testMakePrivate() {
myFixture.configureByText("foo.kt", """
class Foo<caret> {
fun bar(){}
}
""")
myFixture.launchAction(
createModifierActions(
myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PRIVATE, true)
).findWithText("Make 'Foo' private")
)
myFixture.checkResult("""
private class Foo {
fun bar(){}
}
""")
}
fun testMakeNotPrivate() {
myFixture.configureByText("foo.kt", """
private class Foo<caret> {
fun bar(){}
}
""".trim())
myFixture.launchAction(
createModifierActions(
myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PRIVATE, false)
).findWithText("Remove 'private' modifier")
)
myFixture.checkResult("""
class Foo {
fun bar(){}
}
""".trim(), true)
}
fun testMakePrivatePublic() {
myFixture.configureByText(
"foo.kt", """class Foo {
| private fun <caret>bar(){}
|}""".trim().trimMargin()
)
myFixture.launchAction(
createModifierActions(
myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true)
).findWithText("Remove 'private' modifier")
)
myFixture.checkResult(
"""class Foo {
| fun <caret>bar(){}
|}""".trim().trimMargin(), true
)
}
fun testMakeProtectedPublic() {
myFixture.configureByText(
"foo.kt", """open class Foo {
| protected fun <caret>bar(){}
|}""".trim().trimMargin()
)
myFixture.launchAction(
createModifierActions(
myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true)
).findWithText("Remove 'protected' modifier")
)
myFixture.checkResult(
"""open class Foo {
| fun <caret>bar(){}
|}""".trim().trimMargin(), true
)
}
fun testMakeInternalPublic() {
myFixture.configureByText(
"foo.kt", """class Foo {
| internal fun <caret>bar(){}
|}""".trim().trimMargin()
)
myFixture.launchAction(
createModifierActions(
myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true)
).findWithText("Remove 'internal' modifier")
)
myFixture.checkResult(
"""class Foo {
| fun <caret>bar(){}
|}""".trim().trimMargin(), true
)
}
fun testAddAnnotation() {
myFixture.configureByText(
"foo.kt", """class Foo {
| fun <caret>bar(){}
|}""".trim().trimMargin()
)
myFixture.launchAction(
createAddAnnotationActions(
myFixture.findElementByText("bar", KtModifierListOwner::class.java).toLightElements().single() as PsiMethod,
annotationRequest("kotlin.jvm.JvmName", stringAttribute("name", "foo"))
).single()
)
myFixture.checkResult(
"""class Foo {
| @JvmName(name = "foo")
| fun <caret>bar(){}
|}""".trim().trimMargin(), true
)
}
fun testAddJavaAnnotationValue() {
myFixture.addFileToProject(
"pkg/myannotation/JavaAnnotation.java", """
package pkg.myannotation
public @interface JavaAnnotation {
String value();
int param() default 0;
}
""".trimIndent()
)
myFixture.configureByText(
"foo.kt", """class Foo {
| fun bar(){}
| fun baz(){}
|}""".trim().trimMargin()
)
myFixture.launchAction(
createAddAnnotationActions(
myFixture.findElementByText("bar", KtModifierListOwner::class.java).toLightElements().single() as PsiMethod,
annotationRequest("pkg.myannotation.JavaAnnotation", stringAttribute("value", "foo"), intAttribute("param", 2))
).single()
)
myFixture.launchAction(
createAddAnnotationActions(
myFixture.findElementByText("baz", KtModifierListOwner::class.java).toLightElements().single() as PsiMethod,
annotationRequest("pkg.myannotation.JavaAnnotation", intAttribute("param", 2), stringAttribute("value", "foo"))
).single()
)
myFixture.checkResult(
"""import pkg.myannotation.JavaAnnotation
|
|class Foo {
| @JavaAnnotation("foo", param = 2)
| fun bar(){}
| @JavaAnnotation(param = 2, value = "foo")
| fun baz(){}
|}""".trim().trimMargin(), true
)
}
fun testDontMakePublicPublic() {
myFixture.configureByText(
"foo.kt", """class Foo {
| fun <caret>bar(){}
|}""".trim().trimMargin()
)
assertEmpty(createModifierActions(myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true)))
}
fun testDontMakeFunInObjectsOpen() {
myFixture.configureByText("foo.kt", """
object Foo {
fun bar<caret>(){}
}
""".trim())
assertEmpty(createModifierActions(myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.FINAL, false)))
}
fun testAddVoidVoidMethod() {
myFixture.configureByText("foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin())
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
methodRequest(project, "baz", JvmModifier.PRIVATE, PsiType.VOID)
).findWithText("Add method 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
| fun bar() {}
| private fun baz() {
|
| }
|}
""".trim().trimMargin(), true)
}
fun testAddIntIntMethod() {
myFixture.configureByText("foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin())
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
SimpleMethodRequest(project,
methodName = "baz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(PsiType.INT),
parameters = expectedParams(PsiType.INT))
).findWithText("Add method 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
| fun bar() {}
| fun baz(param0: Int): Int {
| TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
| }
|}
""".trim().trimMargin(), true)
}
fun testAddIntPrimaryConstructor() {
myFixture.configureByText("foo.kt", """
|class Foo<caret> {
|}
""".trim().trimMargin())
myFixture.launchAction(
createConstructorActions(
myFixture.atCaret(), constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType)))
).findWithText("Add primary constructor to 'Foo'")
)
myFixture.checkResult("""
|class Foo(param0: Int) {
|}
""".trim().trimMargin(), true)
}
fun testAddIntSecondaryConstructor() {
myFixture.configureByText("foo.kt", """
|class <caret>Foo() {
|}
""".trim().trimMargin())
myFixture.launchAction(
createConstructorActions(
myFixture.atCaret(),
constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType)))
).findWithText("Add secondary constructor to 'Foo'")
)
myFixture.checkResult("""
|class Foo() {
| constructor(param0: Int) {
|
| }
|}
""".trim().trimMargin(), true)
}
fun testChangePrimaryConstructorInt() {
myFixture.configureByText("foo.kt", """
|class <caret>Foo() {
|}
""".trim().trimMargin())
myFixture.launchAction(
createConstructorActions(
myFixture.atCaret(),
constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType)))
).findWithText("Add 'int' as 1st parameter to method 'Foo'")
)
myFixture.checkResult("""
|class Foo(param0: Int) {
|}
""".trim().trimMargin(), true)
}
fun testRemoveConstructorParameters() {
myFixture.configureByText("foo.kt", """
|class <caret>Foo(i: Int) {
|}
""".trim().trimMargin())
myFixture.launchAction(
createConstructorActions(
myFixture.atCaret(),
constructorRequest(project, emptyList())
).findWithText("Remove 1st parameter from method 'Foo'")
)
myFixture.checkResult("""
|class Foo() {
|}
""".trim().trimMargin(), true)
}
fun testAddStringVarProperty() {
myFixture.configureByText("foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin())
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
SimpleMethodRequest(
project,
methodName = "setBaz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(),
parameters = expectedParams(PsiType.getTypeByName("java.lang.String", project, project.allScope()))
)
).findWithText("Add 'var' property 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
| var baz: String = TODO("initialize me")
|
| fun bar() {}
|}
""".trim().trimMargin(), true)
}
fun testAddLateInitStringVarProperty() {
myFixture.configureByText("foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin())
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
SimpleMethodRequest(
project,
methodName = "setBaz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(),
parameters = expectedParams(PsiType.getTypeByName("java.lang.String", project, project.allScope()))
)
).findWithText("Add 'lateinit var' property 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
| lateinit var baz: String
|
| fun bar() {}
|}
""".trim().trimMargin(), true)
}
fun testAddStringVarField() {
myFixture.configureByText(
"foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin()
)
myFixture.launchAction(
createFieldActions(
myFixture.atCaret(),
FieldRequest(project, emptyList(), "java.util.Date", "baz")
).findWithText("Add 'var' property 'baz' to 'Foo'")
)
myFixture.checkResult(
"""
|import java.util.Date
|
|class Foo {
| @JvmField
| var baz: Date = TODO("initialize me")
|
| fun bar() {}
|}
""".trim().trimMargin(), true
)
}
fun testAddLateInitStringVarField() {
myFixture.configureByText(
"foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin()
)
myFixture.launchAction(
createFieldActions(
myFixture.atCaret(),
FieldRequest(project, listOf(JvmModifier.PRIVATE), "java.lang.String", "baz")
).findWithText("Add 'lateinit var' property 'baz' to 'Foo'")
)
myFixture.checkResult(
"""
|class Foo {
| private lateinit var baz: String
|
| fun bar() {}
|}
""".trim().trimMargin(), true
)
}
private fun createFieldActions(atCaret: JvmClass, fieldRequest: CreateFieldRequest): List<IntentionAction> =
com.intellij.lang.jvm.actions.EP_NAME.extensions.flatMap { it.createAddFieldActions(atCaret, fieldRequest) }
fun testAddStringValProperty() {
myFixture.configureByText("foo.kt", """
|class Foo<caret> {
| fun bar() {}
|}
""".trim().trimMargin())
myFixture.launchAction(
createMethodActions(
myFixture.atCaret(),
SimpleMethodRequest(
project,
methodName = "getBaz",
modifiers = listOf(JvmModifier.PUBLIC),
returnType = expectedTypes(PsiType.getTypeByName("java.lang.String", project, project.allScope())),
parameters = expectedParams()
)
).findWithText("Add 'val' property 'baz' to 'Foo'")
)
myFixture.checkResult("""
|class Foo {
| val baz: String = TODO("initialize me")
|
| fun bar() {}
|}
""".trim().trimMargin(), true)
}
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>,
val type: String,
val name: String
) : CreateFieldRequest {
override fun getTargetSubstitutor(): JvmSubstitutor = PsiJvmSubstitutor(project, PsiSubstitutor.EMPTY)
override fun getModifiers(): Collection<JvmModifier> = modifiers
override fun isConstant(): Boolean = false
override fun getFieldType(): List<ExpectedType> =
com.intellij.lang.jvm.actions.expectedTypes(PsiType.getTypeByName(type, project, project.allScope()))
override fun getFieldName(): String = name
override fun isValid(): Boolean = true
}
}

View File

@@ -72,6 +72,6 @@ public class KotlinVersion(val major: Int, val minor: Int, val patch: Int) : Com
* Returns the current version of the Kotlin standard library.
*/
@kotlin.jvm.JvmField
public val CURRENT: KotlinVersion = KotlinVersion(1, 3, 0) // value is written here automatically during build
public val CURRENT: KotlinVersion = KotlinVersion(1, 3, 111) // value is written here automatically during build
}
}

View File

@@ -22,12 +22,16 @@ import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.resolveCandidates
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
@@ -52,4 +56,11 @@ class IdeaKotlinUastResolveProviderService : KotlinUastResolveProviderService {
override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
return element.languageVersionSettings
}
override fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence<DeclarationDescriptor> {
val resolutionFacade = ktElement.getResolutionFacade()
val bindingContext = ktElement.analyze()
val call = ktElement.getCall(bindingContext) ?: return emptySequence()
return call.resolveCandidates(bindingContext, resolutionFacade).map { it.candidateDescriptor }.asSequence()
}
}

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.internal
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
class IdeaKotlinUastResolveProviderService : KotlinUastResolveProviderService {
override fun getBindingContext(element: KtElement) = element.analyze(BodyResolveMode.PARTIAL)
override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
return KotlinTypeMapper(
getBindingContext(element), ClassBuilderMode.LIGHT_CLASSES,
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, JvmTarget.DEFAULT,
element.languageVersionSettings,
false
)
}
override fun isJvmElement(psiElement: PsiElement): Boolean {
val module = psiElement.module
return module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform
}
override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
return element.languageVersionSettings
}
}

View File

@@ -30,6 +30,7 @@ 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
@@ -49,6 +50,7 @@ interface KotlinUastResolveProviderService {
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"))

View File

@@ -0,0 +1,555 @@
/*
* 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.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.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
}
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)
}
private 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
}
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)
}
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, this@KotlinUastLanguagePlugin) }
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement, this@KotlinUastLanguagePlugin) }
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 -> convertElement(original.kotlinOrigin, givenParent, requiredType)
else -> null
}
}
}
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
}
}
}
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
}
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 ->
KotlinUastLanguagePlugin().convertDeclaration(getter, givenParent, requiredType)
}
}
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)
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 }
}
}
}
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) }
}

View File

@@ -3,6 +3,7 @@ package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveResult
import org.jetbrains.kotlin.asJava.toLightAnnotation
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -22,11 +23,12 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
import org.jetbrains.uast.kotlin.internal.multiResolveResults
abstract class KotlinUAnnotationBase<T : KtCallElement>(
final override val sourcePsi: T,
givenParent: UElement?
) : KotlinAbstractUElement(givenParent), UAnnotationEx, UAnchorOwner {
) : KotlinAbstractUElement(givenParent), UAnnotationEx, UAnchorOwner, UMultiResolvable {
abstract override val javaPsi: PsiAnnotation?
@@ -100,6 +102,8 @@ abstract class KotlinUAnnotationBase<T : KtCallElement>(
}
return superParent
}
override fun multiResolve(): Iterable<ResolveResult> = sourcePsi.multiResolveResults().asIterable()
}
class KotlinUAnnotation(

View File

@@ -0,0 +1,161 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.asJava.toLightAnnotation
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
abstract class KotlinUAnnotationBase<T : KtCallElement>(
final override val sourcePsi: T,
givenParent: UElement?
) : KotlinAbstractUElement(givenParent), UAnnotationEx, UAnchorOwner {
abstract override val javaPsi: PsiAnnotation?
final override val psi: PsiElement = sourcePsi
protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
private val resolvedCall: ResolvedCall<*>? get () = sourcePsi.getResolvedCall(sourcePsi.analyze())
override val qualifiedName: String? by lz {
computeClassDescriptor().takeUnless(ErrorUtils::isError)
?.fqNameUnsafe
?.takeIf(FqNameUnsafe::isSafe)
?.toSafe()
?.toString()
}
override val attributeValues: List<UNamedExpression> by lz {
resolvedCall?.valueArguments?.entries?.mapNotNull {
val arguments = it.value.arguments
val name = it.key.name.asString()
when {
arguments.size == 1 ->
KotlinUNamedExpression.create(name, arguments.first(), this)
arguments.size > 1 ->
KotlinUNamedExpression.create(name, arguments, this)
else -> null
}
} ?: emptyList()
}
protected abstract fun computeClassDescriptor(): ClassDescriptor?
override fun resolve(): PsiClass? = computeClassDescriptor()?.toSource()?.getMaybeLightElement(this) as? PsiClass
override fun findAttributeValue(name: String?): UExpression? =
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
fun findAttributeValueExpression(arg: ValueArgument): UExpression? {
val mapping = resolvedCall?.getArgumentMapping(arg)
return (mapping as? ArgumentMatch)?.let { match ->
val namedExpression = attributeValues.find { it.name == match.valueParameter.name.asString() }
namedExpression?.expression as? KotlinUVarargExpression ?: namedExpression
}
}
override fun findDeclaredAttributeValue(name: String?): UExpression? {
return attributeValues.find {
it.name == name ||
(name == null && it.name == "value") ||
(name == "value" && it.name == null)
}?.expression
}
private fun findAttributeDefaultValue(name: String): UExpression? {
val parameter = computeClassDescriptor()
?.unsubstitutedPrimaryConstructor
?.valueParameters
?.find { it.name.asString() == name } ?: return null
val defaultValue = (parameter.source.getPsi() as? KtParameter)?.defaultValue ?: return null
return getLanguagePlugin().convertWithParent(defaultValue)
}
override fun convertParent(): UElement? {
val superParent = super.convertParent() ?: return null
if (annotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER) {
(superParent.uastParent as? KotlinUMethod)?.uastParameters?.firstIsInstance<KotlinReceiverUParameter>()?.let {
return it
}
}
return superParent
}
}
class KotlinUAnnotation(
annotationEntry: KtAnnotationEntry,
givenParent: UElement?
) : KotlinUAnnotationBase<KtAnnotationEntry>(annotationEntry, givenParent), UAnnotation {
override val javaPsi = annotationEntry.toLightAnnotation()
override fun computeClassDescriptor(): ClassDescriptor? =
sourcePsi.analyze()[BindingContext.ANNOTATION, sourcePsi]?.annotationClass
override fun annotationUseSiteTarget() = sourcePsi.useSiteTarget?.getAnnotationUseSiteTarget()
override val uastAnchor by lazy {
KotlinUIdentifier(
javaPsi?.nameReferenceElement,
annotationEntry.typeReference?.typeElement?.let {
(it as? KtUserType)?.referenceExpression?.getReferencedNameElement() ?: it.navigationElement
},
this
)
}
}
class KotlinUNestedAnnotation private constructor(
original: KtCallExpression,
givenParent: UElement?
) : KotlinUAnnotationBase<KtCallExpression>(original, givenParent) {
override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
override fun computeClassDescriptor(): ClassDescriptor? = classDescriptor(sourcePsi)
override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
override val uastAnchor by lazy {
KotlinUIdentifier(
javaPsi?.nameReferenceElement?.referenceNameElement,
(original.calleeExpression as? KtNameReferenceExpression)?.getReferencedNameElement(),
this
)
}
companion object {
fun tryCreate(original: KtCallExpression, givenParent: UElement?): KotlinUNestedAnnotation? {
if (classDescriptor(original)?.kind == ClassKind.ANNOTATION_CLASS)
return KotlinUNestedAnnotation(original, givenParent)
else
return null
}
private fun classDescriptor(original: KtCallExpression) =
(original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
}
}

View File

@@ -17,16 +17,19 @@
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, KotlinUElementWithType {
) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, UMultiResolvable, KotlinUElementWithType {
override val qualifierExpression: UExpression?
get() {
if (qualifierType != null) return null
@@ -46,4 +49,7 @@ class KotlinUCallableReferenceExpression(
get() = (resolve() as? PsiNamedElement)?.name
override fun resolve() = psi.callableReference.resolveCallToDeclaration(this)
override fun multiResolve(): Iterable<ResolveResult> = getResolveResultVariants(psi.callableReference)
}

View File

@@ -0,0 +1,49 @@
/*
* 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.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
class KotlinUCallableReferenceExpression(
override val psi: KtCallableReferenceExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, 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)
}

View File

@@ -16,10 +16,13 @@
package org.jetbrains.uast.kotlin
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiType
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -30,16 +33,20 @@ import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.uast.*
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.internal.TypedResolveResult
import org.jetbrains.uast.kotlin.internal.getReferenceVariants
import org.jetbrains.uast.kotlin.internal.multiResolveResults
import org.jetbrains.uast.visitor.UastVisitor
class KotlinUFunctionCallExpression(
override val psi: KtCallElement,
givenParent: UElement?,
private val _resolvedCall: ResolvedCall<*>?
) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, KotlinUElementWithType {
) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, KotlinUElementWithType, UMultiResolvable {
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
@@ -80,12 +87,37 @@ class KotlinUFunctionCallExpression(
override val valueArguments by lz { psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) } }
override fun getArgumentForParameter(i: Int): UExpression? {
val resolvedCall = resolvedCall ?: return null
val actualParamIndex = if (resolvedCall.extensionReceiver == null) i else i - 1
if (actualParamIndex == -1) return receiver
return getArgumentExpressionByIndex(actualParamIndex, resolvedCall, this)
val resolvedCall = resolvedCall
if (resolvedCall != null) {
val actualParamIndex = if (resolvedCall.extensionReceiver == null) i else i - 1
if (actualParamIndex == -1) return receiver
return getArgumentExpressionByIndex(actualParamIndex, resolvedCall, this)
}
val argument = valueArguments.getOrNull(i) ?: return null
val argumentType = argument.getExpressionType()
for (resolveResult in multiResolve()) {
val psiMethod = resolveResult.element as? PsiMethod ?: continue
val psiParameter = psiMethod.parameterList.parameters.getOrNull(i) ?: continue
if (argumentType == null || psiParameter.type.isAssignableFrom(argumentType))
return argument
}
return null
}
override fun getExpressionType(): PsiType? {
super<KotlinUElementWithType>.getExpressionType()?.let { return it }
for (resolveResult in multiResolve()) {
val psiMethod = resolveResult.element
when {
psiMethod.isConstructor ->
psiMethod.containingClass?.let { return PsiTypesUtil.getClassType(it) }
else ->
psiMethod.returnType?.let { return it }
}
}
return null
}
override val typeArgumentCount: Int
get() = psi.typeArguments.size
@@ -131,6 +163,30 @@ class KotlinUFunctionCallExpression(
}
private val multiResolved by lazy(fun(): Iterable<TypedResolveResult<PsiMethod>> {
val contextElement = psi
if (!Registry.`is`("kotlin.uast.multiresolve.enabled", true)) {
val calleeExpression = contextElement.calleeExpression ?: return emptyList()
return calleeExpression.multiResolveResults()
.mapNotNull { it.element.safeAs<PsiMethod>()?.let { TypedResolveResult(it) } }
.asIterable()
}
val calleeExpression = contextElement.calleeExpression as? KtReferenceExpression ?: return emptyList()
val methodName = methodName ?: calleeExpression.text ?: return emptyList()
val variants = getReferenceVariants(calleeExpression, methodName)
return variants.flatMap {
when (val source = it.toSource()) {
is KtClass -> source.toLightClass()?.constructors?.asSequence().orEmpty()
else -> resolveSource(psi, it, source)?.let { sequenceOf(it) }.orEmpty()
}
}.map { TypedResolveResult(it) }.asIterable()
})
override fun multiResolve(): Iterable<TypedResolveResult<PsiMethod>> = multiResolved
override fun resolve(): PsiMethod? {
val descriptor = resolvedCall?.resultingDescriptor ?: return null
val source = descriptor.toSource()

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.uast.*
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.visitor.UastVisitor
class KotlinUFunctionCallExpression(
override val psi: KtCallElement,
givenParent: UElement?,
private val _resolvedCall: ResolvedCall<*>?
) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, KotlinUElementWithType {
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
private val resolvedCall
get() = _resolvedCall ?: psi.getResolvedCall(psi.analyze())
override val receiverType by lz {
val resolvedCall = this.resolvedCall ?: return@lz null
val receiver = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver ?: return@lz null
receiver.type.toPsiType(this, psi, boxed = true)
}
override val methodName by lz { resolvedCall?.resultingDescriptor?.name?.asString() }
override val classReference by lz {
KotlinClassViaConstructorUSimpleReferenceExpression(psi, methodName.orAnonymous("class"), this)
}
override val methodIdentifier by lz {
val calleeExpression = psi.calleeExpression
when (calleeExpression) {
null -> null
is KtNameReferenceExpression ->
KotlinUIdentifier(calleeExpression.getReferencedNameElement(), this)
is KtConstructorDelegationReferenceExpression ->
KotlinUIdentifier(calleeExpression.firstChild ?: calleeExpression, this)
is KtConstructorCalleeExpression ->
KotlinUIdentifier(
calleeExpression.constructorReferenceExpression?.getReferencedNameElement() ?: calleeExpression, this
)
else -> KotlinUIdentifier(calleeExpression, this)
}
}
override val valueArgumentCount: Int
get() = psi.valueArguments.size
override val valueArguments by lz { psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) } }
override fun getArgumentForParameter(i: Int): UExpression? {
val resolvedCall = resolvedCall ?: return null
val actualParamIndex = if (resolvedCall.extensionReceiver == null) i else i - 1
if (actualParamIndex == -1) return receiver
return getArgumentExpressionByIndex(actualParamIndex, resolvedCall, this)
}
override val typeArgumentCount: Int
get() = psi.typeArguments.size
override val typeArguments by lz { psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) } }
override val returnType: PsiType?
get() = getExpressionType()
override val kind: UastCallKind by lz {
val resolvedCall = resolvedCall ?: return@lz UastCallKind.METHOD_CALL
when {
resolvedCall.resultingDescriptor is ConstructorDescriptor -> UastCallKind.CONSTRUCTOR_CALL
this.isAnnotationArgumentArrayInitializer() -> UastCallKind.NESTED_ARRAY_INITIALIZER
else -> UastCallKind.METHOD_CALL
}
}
override val receiver: UExpression?
get() {
(uastParent as? UQualifiedReferenceExpression)?.let {
if (it.selector == this) return it.receiver
}
val ktNameReferenceExpression = psi.calleeExpression as? KtNameReferenceExpression ?: return null
val variableCallDescriptor =
(resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
?: (resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.takeIf { it.visibility == Visibilities.LOCAL }
?: return null
// an implicit receiver for variables calls (KT-25524)
return object : KotlinAbstractUExpression(this), UReferenceExpression {
private val resolvedDeclaration = variableCallDescriptor.toSource()
override val psi: KtNameReferenceExpression get() = ktNameReferenceExpression
override val resolvedName: String? get() = (resolvedDeclaration as? PsiNamedElement)?.name
override fun resolve(): PsiElement? = resolvedDeclaration
}
}
override fun resolve(): PsiMethod? {
val descriptor = resolvedCall?.resultingDescriptor ?: return null
val source = descriptor.toSource()
return resolveSource(psi, descriptor, source)
}
override fun accept(visitor: UastVisitor) {
if (visitor.visitCallExpression(this)) return
methodIdentifier?.accept(visitor)
classReference.accept(visitor)
valueArguments.acceptList(visitor)
visitor.afterVisitCallExpression(this)
}
private fun isAnnotationArgumentArrayInitializer(): Boolean {
val resolvedCall = resolvedCall ?: return false
// KtAnnotationEntry -> KtValueArgumentList -> KtValueArgument -> arrayOf call
return psi.parents.elementAtOrNull(2) is KtAnnotationEntry && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
}
override fun convertParent(): UElement? = super.convertParent().let { result ->
when (result) {
is UMethod -> result.uastBody ?: result
is UClass ->
result.methods
.filterIsInstance<KotlinConstructorUMethod>()
.firstOrNull { it.isPrimary }
?.uastBody
?: result
else -> result
}
}
}
internal fun getArgumentExpressionByIndex(
actualParamIndex: Int,
resolvedCall: ResolvedCall<out CallableDescriptor>,
parent: UElement
): UExpression? {
val (parameter, resolvedArgument) = resolvedCall.valueArguments.entries.find { it.key.index == actualParamIndex } ?: return null
val arguments = resolvedArgument.arguments
if (arguments.isEmpty()) return null
if (arguments.size == 1) {
val argument = arguments.single()
val expression = argument.getArgumentExpression()
if (parameter.varargElementType != null && argument.getSpreadElement() == null) {
return createVarargsHolder(arguments, parent)
}
return KotlinConverter.convertOrEmpty(expression, parent)
}
return createVarargsHolder(arguments, parent)
}
private fun createVarargsHolder(arguments: List<ValueArgument>, parent: UElement?): KotlinUExpressionList =
KotlinUExpressionList(null, UastSpecialExpressionKind.VARARGS, parent).apply {
expressions = arguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), parent) }
}

View File

@@ -17,14 +17,17 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.ResolveResult
import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMultiResolvable
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
class KotlinUSafeQualifiedExpression(
override val psi: KtSafeQualifiedExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression,
) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression, UMultiResolvable,
KotlinUElementWithType, KotlinEvaluatableUElement {
override val receiver by lz { KotlinConverter.convertOrEmpty(psi.receiverExpression, this) }
override val selector by lz { KotlinConverter.convertOrEmpty(psi.selectorExpression, this) }
@@ -34,4 +37,5 @@ class KotlinUSafeQualifiedExpression(
get() = (resolve() as? PsiNamedElement)?.name
override fun resolve() = psi.selectorExpression?.resolveCallToDeclaration(this)
override fun multiResolve(): Iterable<ResolveResult> = getResolveResultVariants(psi.selectorExpression)
}

View File

@@ -0,0 +1,37 @@
/*
* 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.KtSafeQualifiedExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UQualifiedReferenceExpression
class KotlinUSafeQualifiedExpression(
override val psi: KtSafeQualifiedExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression,
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 = KotlinQualifiedExpressionAccessTypes.SAFE
override val resolvedName: String?
get() = (resolve() as? PsiNamedElement)?.name
override fun resolve() = psi.selectorExpression?.resolveCallToDeclaration(this)
}

View File

@@ -0,0 +1,38 @@
/*
* 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.KtThisExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UThisExpression
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUThisExpression(
override val psi: KtThisExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UThisExpression, DelegatedMultiResolve, KotlinUElementWithType, KotlinEvaluatableUElement {
override val label: String?
get() = psi.getLabelName()
override val labelIdentifier: UIdentifier?
get() = psi.getTargetLabel()?.let { KotlinUIdentifier(it, this) }
override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()]
}

View File

@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
@@ -40,6 +41,9 @@ class CliKotlinUastResolveProviderService : KotlinUastResolveProviderService {
override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
return element.project.analysisCompletedHandler?.getLanguageVersionSettings() ?: LanguageVersionSettingsImpl.DEFAULT
}
override fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence<DeclarationDescriptor> =
emptySequence() // Not supported
}
class UastAnalysisHandlerExtension : AnalysisHandlerExtension {

View File

@@ -0,0 +1,89 @@
package org.jetbrains.uast.kotlin.internal
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
class CliKotlinUastResolveProviderService : KotlinUastResolveProviderService {
val Project.analysisCompletedHandler: UastAnalysisHandlerExtension?
get() = getExtensions(AnalysisHandlerExtension.extensionPointName)
.filterIsInstance<UastAnalysisHandlerExtension>()
.firstOrNull()
override fun getBindingContext(element: KtElement): BindingContext {
return element.project.analysisCompletedHandler?.getBindingContext() ?: BindingContext.EMPTY
}
override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
return element.project.analysisCompletedHandler?.getTypeMapper()
}
override fun isJvmElement(psiElement: PsiElement) = true
override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
return element.project.analysisCompletedHandler?.getLanguageVersionSettings() ?: LanguageVersionSettingsImpl.DEFAULT
}
}
class UastAnalysisHandlerExtension : AnalysisHandlerExtension {
private var context: BindingContext? = null
private var typeMapper: KotlinTypeMapper? = null
private var languageVersionSettings: LanguageVersionSettings? = null
fun getBindingContext() = context
fun getLanguageVersionSettings() = languageVersionSettings
fun getTypeMapper(): KotlinTypeMapper? {
if (typeMapper != null) return typeMapper
val bindingContext = context ?: return null
val typeMapper = KotlinTypeMapper(
bindingContext, ClassBuilderMode.LIGHT_CLASSES,
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, JvmTarget.DEFAULT,
KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings
false
)
this.typeMapper = typeMapper
return typeMapper
}
override fun doAnalysis(
project: Project,
module: ModuleDescriptor,
projectContext: ProjectContext,
files: Collection<KtFile>,
bindingTrace: BindingTrace,
componentProvider: ComponentProvider
): AnalysisResult? {
languageVersionSettings = componentProvider.get<LanguageVersionSettings>()
return super.doAnalysis(project, module, projectContext, files, bindingTrace, componentProvider)
}
override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
bindingTrace: BindingTrace,
files: Collection<KtFile>
): AnalysisResult? {
context = bindingTrace.bindingContext
return null
}
}

View File

@@ -5,10 +5,55 @@
package org.jetbrains.uast.kotlin.internal
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPolyVariantReference
import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.ResolveResult
import com.intellij.psi.infos.CandidateInfo
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMultiResolvable
import org.jetbrains.uast.UResolvable
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.getMaybeLightElement
import org.jetbrains.uast.kotlin.toSource
//Dummy holder until idea 183
interface DelegatedMultiResolve : UResolvable
internal fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence<DeclarationDescriptor> =
ServiceManager.getService(ktElement.project, KotlinUastResolveProviderService::class.java).getReferenceVariants(ktElement, nameHint)
internal fun UElement.getResolveResultVariants(ktExpression: KtExpression?): Iterable<ResolveResult> {
ktExpression ?: return emptyList()
if (!Registry.`is`("kotlin.uast.multiresolve.enabled", true)) return ktExpression.multiResolveResults().asIterable()
val referenceVariants = getReferenceVariants(ktExpression, ktExpression.name ?: ktExpression.text)
fun asCandidateInfo(descriptor: DeclarationDescriptor): CandidateInfo? =
descriptor.toSource()?.getMaybeLightElement(this)?.let { CandidateInfo(it, PsiSubstitutor.EMPTY) }
return referenceVariants.mapNotNull(::asCandidateInfo).asIterable()
}
internal fun KtElement.multiResolveResults(): Sequence<ResolveResult> =
references.asSequence().flatMap { ref ->
when (ref) {
is PsiPolyVariantReference -> ref.multiResolve(false).asSequence()
else -> (ref.resolve()?.let { sequenceOf(CandidateInfo(it, PsiSubstitutor.EMPTY)) }).orEmpty()
}
}
interface DelegatedMultiResolve : UMultiResolvable, UResolvable {
override fun multiResolve(): Iterable<ResolveResult> = listOfNotNull(resolve()?.let { CandidateInfo(it, PsiSubstitutor.EMPTY) })
}
class TypedResolveResult<T : PsiElement>(element: T) : CandidateInfo(element, PsiSubstitutor.EMPTY) {
@Suppress("UNCHECKED_CAST")
override fun getElement(): T = super.getElement() as T
}

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