mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-28 15:51:42 +00:00
Compare commits
9 Commits
rr/pdn_byt
...
tmp/vbr/st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ce9e58e87 | ||
|
|
fad8a85886 | ||
|
|
9e5b69eb23 | ||
|
|
41f635dd48 | ||
|
|
efeb9e2fef | ||
|
|
2057c80252 | ||
|
|
1789895eb2 | ||
|
|
d2d8cd10b3 | ||
|
|
2d7682ff62 |
4
.idea/codeStyles/Project.xml
generated
4
.idea/codeStyles/Project.xml
generated
@@ -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
1
.idea/vcs.xml
generated
@@ -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
0
LOG_helloApp_.alive.txt
Normal 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)
|
||||
}
|
||||
@@ -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) {}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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>()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 */ }
|
||||
}
|
||||
}
|
||||
11
compiler/testData/asJava/lightClasses/AnnotatedParameterInInnerClassConstructor.java.182
vendored
Normal file
11
compiler/testData/asJava/lightClasses/AnnotatedParameterInInnerClassConstructor.java.182
vendored
Normal 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 */ }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
69
compiler/testData/codegen/bytecodeListing/inlineClasses/annotationsOnHiddenConstructor.txt.182
vendored
Normal file
69
compiler/testData/codegen/bytecodeListing/inlineClasses/annotationsOnHiddenConstructor.txt.182
vendored
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
133
compiler/testData/codegen/bytecodeListing/jvmOverloadsAndParametersAnnotations.txt.182
vendored
Normal file
133
compiler/testData/codegen/bytecodeListing/jvmOverloadsAndParametersAnnotations.txt.182
vendored
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
77
idea/src/META-INF/plugin.xml.182
Normal file
77
idea/src/META-INF/plugin.xml.182
Normal 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>
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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? =
|
||||
|
||||
@@ -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) }
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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?) {
|
||||
|
||||
@@ -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?) {
|
||||
|
||||
@@ -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?) {
|
||||
|
||||
32
idea/testData/inspections/blockingCallsDetection/ContextCheck.kt
vendored
Normal file
32
idea/testData/inspections/blockingCallsDetection/ContextCheck.kt
vendored
Normal 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()
|
||||
}
|
||||
0
idea/testData/inspections/blockingCallsDetection/ContextCheck.kt.182
vendored
Normal file
0
idea/testData/inspections/blockingCallsDetection/ContextCheck.kt.182
vendored
Normal file
10
idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt
vendored
Normal file
10
idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
0
idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt.182
vendored
Normal file
0
idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt.182
vendored
Normal file
20
idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt
vendored
Normal file
20
idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt
vendored
Normal 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
|
||||
0
idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt.182
vendored
Normal file
0
idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt.182
vendored
Normal file
11
idea/testData/inspections/blockingCallsDetection/NestedFunctionsInsideSuspendLambda.kt
vendored
Normal file
11
idea/testData/inspections/blockingCallsDetection/NestedFunctionsInsideSuspendLambda.kt
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
0
idea/testData/inspections/blockingCallsDetection/NestedFunctionsInsideSuspendLambda.kt.182
vendored
Normal file
0
idea/testData/inspections/blockingCallsDetection/NestedFunctionsInsideSuspendLambda.kt.182
vendored
Normal 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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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) =
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"))
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()]
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user